Skip to content

Commit 43957a8

Browse files
committed
[API] Update the API Generator
1 parent 902a27f commit 43957a8

File tree

3 files changed

+108
-60
lines changed

3 files changed

+108
-60
lines changed

elasticsearch-api/utils/thor/generate_source.rb

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,15 @@ class SourceGenerator < Thor
3232

3333
include Thor::Actions
3434

35+
SRC_PATH = '../../../../tmp/elasticsearch/rest-api-spec/src/main/resources/rest-api-spec/api/'.freeze
3536
__root = Pathname( File.expand_path('../../..', __FILE__) )
3637

3738
desc "generate", "Generate source code and tests from the REST API JSON specification"
38-
method_option :language, default: 'ruby', desc: 'Programming language'
39-
method_option :force, type: :boolean, default: false, desc: 'Overwrite the output'
40-
method_option :verbose, type: :boolean, default: false, desc: 'Output more information'
41-
method_option :input, default: File.expand_path('../../../../tmp/elasticsearch/rest-api-spec/api/**/*.json', __FILE__), desc: 'Path to directory with JSON API specs'
42-
method_option :output, default: File.expand_path('../../../tmp/out', __FILE__), desc: 'Path to output directory'
39+
method_option :language, default: 'ruby', desc: 'Programming language'
40+
method_option :force, type: :boolean, default: false, desc: 'Overwrite the output'
41+
method_option :verbose, type: :boolean, default: false, desc: 'Output more information'
42+
method_option :input, default: File.expand_path(SRC_PATH, __FILE__), desc: 'Path to directory with JSON API specs'
43+
method_option :output, default: File.expand_path('../../../tmp/out', __FILE__), desc: 'Path to output directory'
4344

4445
def generate(*files)
4546
self.class.source_root File.expand_path('../', __FILE__)
@@ -50,39 +51,48 @@ def generate(*files)
5051
# -- Test helper
5152
copy_file "templates/ruby/test_helper.rb", @output.join('test').join('test_helper.rb') if options[:language] == 'ruby'
5253

53-
files = Dir.entries(@input.to_s).reject { |f| f.start_with?('.') || f.start_with?('_') }
54+
# Remove unwanted files
55+
files = Dir.entries(@input.to_s).reject do |f|
56+
f.start_with?('.') ||
57+
f.start_with?('_') ||
58+
File.extname(f) != '.json'
59+
end
5460

5561
files.each do |filepath|
5662
file = @input.join(filepath)
5763

5864
@path = Pathname(file)
5965
@json = MultiJson.load( File.read(@path) )
66+
6067
@spec = @json.values.first
6168
say_status 'json', @path, :yellow
6269

6370
@spec['url'] ||= {}
64-
@spec['url']['parts'] ||= []
65-
@spec['url']['params'] ||= {}
6671

6772
# say_status 'JSON', @spec.inspect, options[:verbose]
6873

6974
@full_namespace = @json.keys.first.split('.')
7075
@namespace_depth = @full_namespace.size > 0 ? @full_namespace.size-1 : 0
7176
@module_namespace = @full_namespace[0, @namespace_depth]
7277
@method_name = @full_namespace.last
73-
@http_method = "Elasticsearch::API::HTTP_#{@spec['methods'].first}"
74-
@http_path = unless @spec['url']['parts'].empty?
75-
@spec['url']['path']
78+
79+
@parts = __endpoint_parts
80+
@params = @spec['params'] || {}
81+
82+
method = @spec['url']['paths'].map { |a| a['methods'] }.flatten.first
83+
@http_method = "HTTP_#{method}"
84+
@http_path_params = __path_params
85+
@http_path = unless false
86+
@spec['url']['paths'].first['path']
7687
.split('/')
7788
.compact
7889
.reject { |p| p =~ /^\s*$/ }
7990
.map { |p| p =~ /\{/ ? "\#\{arguments[:#{p.tr('{}', '')}]\}" : p }
8091
.join('/')
8192
.gsub(/^\//, '')
8293
else
83-
@spec['url']['path'].gsub(/^\//, '')
94+
@spec['url']['paths'].first.gsub(/^\//, '')
8495
end
85-
8696
# -- Ruby files
8797

8898
@path_to_file = @output.join('api').join( @module_namespace.join('/') ).join("#{@method_name}.rb")
@@ -137,6 +147,24 @@ def __create_directories(key, value)
137147
end
138148
end
139149

150+
def __endpoint_parts
151+
parts = @spec['url']['paths'].select do |a|
152+
a.keys.include?('parts')
153+
end.map do |part|
154+
part&.[]('parts')
155+
end
156+
(parts.first || [])
157+
end
158+
159+
def __path_params
160+
return nil if @parts.empty? || @parts.nil?
161+
params = []
162+
@parts.each do |name, _|
163+
params << "Utils.__listify(_#{name})"
164+
end
165+
', ' + params.join(', ')
166+
end
167+
140168
end
141169
end
142170
end

elasticsearch-api/utils/thor/templates/ruby/method.erb

Lines changed: 65 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,78 @@
33
# See the LICENSE file in the project root for more information
44

55
module Elasticsearch
6-
module API
7-
<%- @module_namespace.each_with_index do |name, i| -%>
8-
<%= ' '*i %>module <%= name == 'xpack' ? 'XPack' : name.capitalize %>
9-
<%- end -%>
10-
<%= ' '*@namespace_depth %>module Actions
11-
12-
<%= ' '*@namespace_depth %># <%= @spec['description'] || 'TODO: Description' %>
13-
<%= ' '*@namespace_depth %>#
14-
<%# URL parts -%>
15-
<%- @spec['url']['parts'].each do |name,info| -%>
16-
<%- info['type'] = 'String' if info['type'] == 'enum' # Rename 'enums' to 'strings' -%>
17-
<%= ' '*@namespace_depth + "# @option arguments [#{info['type'] ? info['type'].capitalize : 'String'}] :#{name} #{info['description'] ? info['description'].strip : '[TODO]'}" + ( info['required'] ? ' (*Required*)' : '' ) -%><%= " (options: #{info['options'].join(', '.strip)})" if info['options'] -%>
18-
<%= "\n" -%>
19-
<%- end -%>
20-
<%# Body -%>
6+
<%= ' '*(@namespace_depth+1) %>module API
7+
<%- @module_namespace.each_with_index do |name, i| -%>
8+
<%= ' '*i %>module <%= name == 'xpack' ? 'XPack' : name.capitalize %>
9+
<%- end -%>
10+
<%= ' '*(@namespace_depth+2) %>module Actions
11+
<%- if @spec['documentation']['description'] %>
12+
<%= ' '*(@namespace_depth+3) %># <%= @spec['documentation']['description'].gsub("\n", "\n#{' '*(@namespace_depth+3)}# ") %>
13+
<%- else %>
14+
<%= ' '*(@namespace_depth+3) %># TODO: Description %>
15+
<%- end %>
16+
<%= ' '*(@namespace_depth+3) %>#
17+
<%- unless @parts.nil? || @parts.empty? %><%# URL parts -%>
18+
<%- @parts.each do |name, info| -%>
19+
<%- info['type'] = 'String' if info['type'] == 'enum' # Rename 'enums' to 'strings' -%>
20+
<%= ' '*(@namespace_depth+3) + "# @option arguments [#{info['type'] ? info['type'].capitalize : 'String'}] :#{name} #{info['description'] ? info['description'].strip : '[TODO]'}" + ( info['required'] ? ' (*Required*)' : '' ) -%>
21+
<%= " (options: #{info['options'].join(', '.strip)})" if info['options'] -%>
22+
<%= "\n" -%>
23+
<%- end -%>
24+
<%- end -%><%# Body -%>
2125
<%= ' '*(@namespace_depth+3) + '# @option arguments [Hash] :body ' + (@spec['body']['description'] ? @spec['body']['description'].strip : 'TODO: Description') + (@spec['body']['required'] ? ' (*Required*)' : '') + "\n" if @spec['body'] -%>
26+
2227
<%# URL parameters -%>
23-
<%- @spec['url']['params'].each do |name,info| -%>
24-
<%- info['type'] = 'String' if info['type'] == 'enum' # Rename 'enums' to 'strings' -%>
25-
<%= ' '*@namespace_depth + "# @option arguments [#{info['type'] ? info['type'].capitalize : 'String'}] :#{name} #{info['description'] ? info['description'].strip : '[TODO]'}" -%><%= " (options: #{info['options'].join(', ')})" if info['options'] -%>
26-
<%= "\n" -%>
27-
<%- end if @spec['url']['parts'] -%>
28-
<%= ' '*@namespace_depth -%>#
28+
<%- @params.each do |name,info| -%>
29+
<%- info['type'] = 'String' if info['type'] == 'enum' # Rename 'enums' to 'strings' -%>
30+
<%= ' '*(@namespace_depth+5) + "# @option arguments [#{info['type'] ? info['type'].capitalize : 'String'}] :#{name} #{info['description'] ? info['description'].strip : '[TODO]'}" -%>
31+
<%= ' '*(@namespace_depth+5) +" (options: #{info['options'].join(', ')})" if info['options'] -%>
32+
<%= "\n" -%>
33+
<%- end if @spec['url']['parts'] -%>
34+
<%= ' '*(@namespace_depth+3) -%>#
2935
<%# Documentation link -%>
30-
<%= ' '*@namespace_depth %># @see <%= @spec['documentation'] ? @spec['documentation'] : "[TODO]" %>
31-
<%= ' '*@namespace_depth %>#
36+
<%= ' '*(@namespace_depth+3) %># @see <%= @spec['documentation']['url'] ? @spec['documentation']['url'] : "[TODO]" %>
37+
<%= ' '*(@namespace_depth+3) %>#
3238
<%# Method definition -%>
33-
<%= ' '*@namespace_depth -%>def <%= @method_name %>(arguments={})
34-
<%# Required arguments -%>
35-
<%- @spec['url']['parts'].select { |name, info| info['required'] }.each do |name, info| -%>
36-
<%= ' '*(@namespace_depth+1) + "raise ArgumentError, \"Required argument '#{name}' missing\" unless arguments[:#{name}]" + "\n" -%>
37-
<%- end -%>
39+
<%= ' '*(@namespace_depth+3) -%>def <%= @method_name %>(arguments={})
40+
<%# Arguments -%>
41+
<%= ' '*(@namespace_depth+4) %>arguments = arguments.clone
42+
<%- @parts.each do |name, info| %>
43+
<%- if info['required'] %>
44+
<%= ' '*(@namespace_depth+3) + "raise ArgumentError, \"Required argument '#{name}' missing\" unless arguments[:#{name}]" + "\n" -%>
45+
<%- end -%>
46+
<%= ' '*(@namespace_depth+4) + "_#{name}" %> = arguments.delete(:<%=name %>)
47+
<%- end -%>
3848
<%- if @spec['body'] && @spec['body']['required'] -%>
39-
<%= ' '*(@namespace_depth+1) + "raise ArgumentError, \"Required argument 'body' missing\" unless arguments[:body]" + "\n" -%>
49+
<%= ' '*(@namespace_depth+3) + "raise ArgumentError, \"Required argument 'body' missing\" unless arguments[:body]" + "\n" -%>
4050
<%- end -%>
41-
<%# Method, path, params, body -%>
42-
<%- unless @spec['url']['params'].empty? -%>
43-
<%= ' '*@namespace_depth %> valid_params = [
44-
<%= ' '*(@namespace_depth+2) %><%= @spec['url']['params'].keys.map { |k| ":#{k}" }.join(",\n#{' '*(@namespace_depth+5)}") %> ]
45-
<%- end -%>
46-
<%= ' '*@namespace_depth %> method = <%= @http_method %>
47-
<%= ' '*@namespace_depth %> path = "<%= @http_path %>"
48-
<%- unless @spec['url']['params'].empty? -%>
49-
<%= ' '*@namespace_depth %> params = Elasticsearch::API::Utils.__validate_and_extract_params arguments, valid_params
50-
<%- else -%>
51-
<%= ' '*@namespace_depth %> params = {}
52-
<%- end -%>
53-
<%= ' '*@namespace_depth %> body = <%= @spec['body'].nil? ? 'nil' : 'arguments[:body]' %>
51+
52+
<%= ' '*(@namespace_depth+4) %>method = <%= @http_method %>
53+
<%= ' '*(@namespace_depth+4) %>path = Utils.__pathify "<%= @http_path %>"<%= @http_path_params %>
54+
<%- unless @params.empty? -%>
55+
<%= ' '*(@namespace_depth+4) %>params = Utils.__validate_and_extract_params arguments, ParamsRegistry.get(__method__)
56+
<%- else -%>
57+
<%= ' '*(@namespace_depth+4) %>params = {}
58+
<%- end -%>
59+
<%= ' '*(@namespace_depth+4) %>body = <%= @spec['body'].nil? ? 'nil' : 'arguments[:body]' %>
5460
<%# Perform request %>
55-
<%= ' '*@namespace_depth %> perform_request(method, path, params, body).body
56-
<%= ' '*@namespace_depth %>end
57-
<%- @namespace_depth.downto(1) do |i| -%>
58-
<%= ' '*(i-1) %>end
59-
<%- end if @namespace_depth > 0 -%>
61+
<%= ' '*(@namespace_depth+4) %>perform_request(method, path, params, body).body
62+
<%= ' '*(@namespace_depth+3) %>end
63+
64+
<%# Method, path, params, body -%>
65+
66+
<%= ' '*(@namespace_depth+3) %># Register this action with its valid params when the module is loaded.
67+
<%= ' '*(@namespace_depth+3) %>#
68+
<%= ' '*(@namespace_depth+3) %># @since 6.2.0
69+
<%- unless @params.empty? -%>
70+
<%= ' '*(@namespace_depth+3) %>ParamsRegistry.register(:<%= @method_name %>, [
71+
<%= ' '*(@namespace_depth+4) %><%= @params.keys.map { |k| ":#{k}" }.join(",\n#{' '*(@namespace_depth+5)}") %>
72+
<%= ' '*(@namespace_depth+3) %>].freeze)
73+
<%- end -%>
74+
75+
<%- @namespace_depth.downto(1) do |i| -%>
76+
<%= ' '*(i-1) %>end
77+
<%- end if @namespace_depth > 0 -%>
6078
end
6179
end
6280
end
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/sh
2+
cp ../tmp/out/api/* ../lib/elasticsearch/api/actions/ -R

0 commit comments

Comments
 (0)