gapic-generator 0.1.3 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +49 -0
  3. data/lib/gapic/formatting_utils.rb +160 -0
  4. data/lib/gapic/generator/version.rb +1 -1
  5. data/lib/gapic/generators/base_generator.rb +0 -8
  6. data/lib/gapic/generators/default_generator.rb +2 -4
  7. data/lib/gapic/helpers/filepath_helper.rb +45 -0
  8. data/lib/gapic/helpers/namespace_helper.rb +51 -0
  9. data/lib/gapic/presenters.rb +44 -0
  10. data/{templates/default/helpers → lib/gapic}/presenters/enum_presenter.rb +19 -14
  11. data/{templates/default/helpers → lib/gapic}/presenters/enum_value_presenter.rb +19 -12
  12. data/lib/gapic/presenters/field_presenter.rb +154 -0
  13. data/lib/gapic/presenters/file_presenter.rb +59 -0
  14. data/lib/gapic/presenters/gem_presenter.rb +170 -0
  15. data/lib/gapic/presenters/message_presenter.rb +73 -0
  16. data/lib/gapic/presenters/method_presenter.rb +298 -0
  17. data/lib/gapic/presenters/package_presenter.rb +72 -0
  18. data/lib/gapic/presenters/resource_presenter.rb +99 -0
  19. data/lib/gapic/presenters/sample_presenter.rb +84 -0
  20. data/lib/gapic/presenters/service_presenter.rb +298 -0
  21. data/lib/gapic/resource_lookup.rb +8 -1
  22. data/lib/gapic/schema/api.rb +24 -0
  23. data/lib/gapic/schema/wrappers.rb +30 -8
  24. data/templates/default/gem/gemspec.erb +1 -1
  25. data/templates/default/gem/gitignore.erb +2 -0
  26. data/templates/default/gem/readme.erb +2 -2
  27. data/templates/default/gem/rubocop.erb +2 -0
  28. data/templates/default/helpers/default_helper.rb +2 -8
  29. data/templates/default/helpers/filepath_helper.rb +2 -21
  30. data/templates/default/helpers/namespace_helper.rb +2 -27
  31. data/templates/default/layouts/_ruby.erb +1 -3
  32. data/templates/default/service/client/_client.erb +7 -1
  33. data/templates/default/service/client/_paths.erb +1 -0
  34. data/templates/default/service/client/method/def/_options_defaults.erb +1 -1
  35. data/templates/default/service/client/method/def/_response_normal.erb +1 -1
  36. metadata +17 -14
  37. data/templates/default/helpers/presenter_helper.rb +0 -24
  38. data/templates/default/helpers/presenters/field_presenter.rb +0 -146
  39. data/templates/default/helpers/presenters/file_presenter.rb +0 -53
  40. data/templates/default/helpers/presenters/gem_presenter.rb +0 -140
  41. data/templates/default/helpers/presenters/message_presenter.rb +0 -66
  42. data/templates/default/helpers/presenters/method_presenter.rb +0 -293
  43. data/templates/default/helpers/presenters/package_presenter.rb +0 -65
  44. data/templates/default/helpers/presenters/resource_presenter.rb +0 -92
  45. data/templates/default/helpers/presenters/sample_presenter.rb +0 -74
  46. data/templates/default/helpers/presenters/service_presenter.rb +0 -276
@@ -0,0 +1,298 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2018 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "active_support/inflector"
18
+ require "gapic/path_template"
19
+ require "gapic/helpers/namespace_helper"
20
+
21
+ module Gapic
22
+ module Presenters
23
+ ##
24
+ # A presenter for rpc methods.
25
+ #
26
+ class MethodPresenter
27
+ include Gapic::Helpers::NamespaceHelper
28
+
29
+ def initialize api, method
30
+ @api = api
31
+ @method = method
32
+ end
33
+
34
+ def service
35
+ ServicePresenter.new @api, @method.parent
36
+ end
37
+
38
+ def name
39
+ ActiveSupport::Inflector.underscore @method.name
40
+ end
41
+
42
+ def kind
43
+ if client_streaming?
44
+ if server_streaming?
45
+ :bidi
46
+ else
47
+ :client
48
+ end
49
+ elsif server_streaming?
50
+ :server
51
+ else
52
+ :normal
53
+ end
54
+ end
55
+
56
+ def doc_description
57
+ @method.docs_leading_comments
58
+ end
59
+
60
+ def doc_response_type
61
+ ret = return_type
62
+ ret = "Gapic::Operation" if lro?
63
+ if server_streaming?
64
+ ret = "Enumerable<#{ret}>"
65
+ elsif paged?
66
+ paged_type = paged_response_type
67
+ paged_type = "Gapic::Operation" if paged_type == "Google::Longrunning::Operation"
68
+ ret = "Gapic::PagedEnumerable<#{paged_type}>"
69
+ end
70
+ ret
71
+ end
72
+
73
+ def arguments
74
+ arguments = @method.input.fields.reject(&:output_only?)
75
+ arguments.map { |arg| FieldPresenter.new @api, @method.input, arg }
76
+ end
77
+
78
+ def fields
79
+ @method.input.fields.map { |field| FieldPresenter.new @api, @method.input, field }
80
+ end
81
+
82
+ def fields_with_first_oneof
83
+ return fields if @method.input.oneof_decl.empty?
84
+
85
+ selected_fields = []
86
+ have_oneof = []
87
+
88
+ @method.input.fields.each do |field|
89
+ idx = field.oneof_index
90
+ selected_fields << field unless have_oneof.include? idx
91
+ have_oneof << idx
92
+ end
93
+
94
+ selected_fields.map { |field| FieldPresenter.new @api, @method.input, field }
95
+ end
96
+
97
+ def request_type
98
+ message_ruby_type @method.input
99
+ end
100
+
101
+ def return_type
102
+ message_ruby_type @method.output
103
+ end
104
+
105
+ def yields?
106
+ # Server streaming RCP calls are the only one that does not yield
107
+ !server_streaming?
108
+ end
109
+
110
+ def yield_doc_description
111
+ return "Register a callback to be run when an operation is done." if lro?
112
+
113
+ "Access the result along with the RPC operation"
114
+ end
115
+
116
+ def yield_params
117
+ if lro?
118
+ return [
119
+ OpenStruct.new(
120
+ name: "operation",
121
+ doc_types: "Gapic::Operation"
122
+ )
123
+ ]
124
+ end
125
+ [
126
+ OpenStruct.new(
127
+ name: "result",
128
+ doc_types: return_type
129
+ ),
130
+ OpenStruct.new(
131
+ name: "operation",
132
+ doc_types: "GRPC::ActiveCall::Operation"
133
+ )
134
+ ]
135
+ end
136
+
137
+ # @api.incode samples and sample_configs are yaml configuration files such as
138
+ # speech_transcribe_sync_gcs.yaml
139
+ def samples
140
+ sample_configs = @api.incode_samples.select do |sample_config|
141
+ sample_config["service"] == @method.address[0...-1].join(".") &&
142
+ sample_config["rpc"] == @method.name
143
+ end
144
+ sample_configs.map { |sample_config| SamplePresenter.new @api, sample_config }
145
+ end
146
+
147
+ def lro?
148
+ return paged_response_type == "Google::Longrunning::Operation" if paged?
149
+
150
+ message_ruby_type(@method.output) == "Google::Longrunning::Operation"
151
+ end
152
+
153
+ def client_streaming?
154
+ @method.client_streaming
155
+ end
156
+
157
+ def server_streaming?
158
+ @method.server_streaming
159
+ end
160
+
161
+ def paged?
162
+ return false if server_streaming? # Cannot page a streaming response
163
+ paged_request?(@method.input) && paged_response?(@method.output)
164
+ end
165
+
166
+ def paged_response_type
167
+ return nil unless paged_response? @method.output
168
+
169
+ repeated_field = @method.output.fields.find do |f|
170
+ f.label == Google::Protobuf::FieldDescriptorProto::Label::LABEL_REPEATED &&
171
+ f.type == Google::Protobuf::FieldDescriptorProto::Type::TYPE_MESSAGE
172
+ end
173
+ message_ruby_type repeated_field.message
174
+ end
175
+
176
+ ##
177
+ #
178
+ # @return [Array<String>] The segment key names.
179
+ #
180
+ def routing_params
181
+ segments = Gapic::PathTemplate.parse method_path
182
+ segments.select { |s| s.is_a? Gapic::PathTemplate::Segment }.map(&:name)
183
+ end
184
+
185
+ def routing_params?
186
+ routing_params.any?
187
+ end
188
+
189
+ def grpc_service_config
190
+ if @api.grpc_service_config&.service_method_level_configs&.key?(service.grpc_full_name) &&
191
+ @api.grpc_service_config.service_method_level_configs[service.grpc_full_name]&.key?(grpc_method_name)
192
+ @api.grpc_service_config.service_method_level_configs[service.grpc_full_name][grpc_method_name]
193
+ end
194
+ end
195
+
196
+ def grpc_method_name
197
+ @method.name
198
+ end
199
+
200
+ protected
201
+
202
+ def message_ruby_type message
203
+ ruby_namespace @api, message.address.join(".")
204
+ end
205
+
206
+ def doc_types_for arg
207
+ if arg.message?
208
+ "#{message_ruby_type arg.message} | Hash"
209
+ elsif arg.enum?
210
+ # TODO: handle when arg message is nil and enum is the type
211
+ message_ruby_type arg.enum
212
+ else
213
+ case arg.type
214
+ when 1, 2 then "Float"
215
+ when 3, 4, 5, 6, 7, 13, 15, 16, 17, 18 then "Integer"
216
+ when 9, 12 then "String"
217
+ when 8 then "Boolean"
218
+ else
219
+ "Object"
220
+ end
221
+ end
222
+ end
223
+
224
+ def doc_desc_for arg
225
+ return nil if arg.docs.leading_comments.empty?
226
+
227
+ arg.docs.leading_comments
228
+ end
229
+
230
+ def default_value_for arg
231
+ if arg.message?
232
+ "{}"
233
+ elsif arg.enum?
234
+ # TODO: select the first non-0 enum value
235
+ # ":ENUM"
236
+ arg.enum.values.first
237
+ else
238
+ case arg.type
239
+ when 1, 2 then "3.14"
240
+ when 3, 4, 5, 6, 7, 13, 15, 16, 17, 18 then "42"
241
+ when 9, 12 then "\"hello world\""
242
+ when 8 then "true"
243
+ else
244
+ "Object"
245
+ end
246
+ end
247
+ end
248
+
249
+ def method_path
250
+ return "" if @method.http.nil?
251
+
252
+ method = [
253
+ @method.http.get, @method.http.post, @method.http.put,
254
+ @method.http.patch, @method.http.delete
255
+ ].find { |x| !x.empty? }
256
+ return method unless method.nil?
257
+
258
+ return @method.http.custom.path unless @method.http.custom.nil?
259
+ end
260
+
261
+ def paged_request? request
262
+ page_token = request.fields.find do |f|
263
+ f.name == "page_token" && f.type == Google::Protobuf::FieldDescriptorProto::Type::TYPE_STRING
264
+ end
265
+ return false if page_token.nil?
266
+
267
+ page_size_types = [
268
+ Google::Protobuf::FieldDescriptorProto::Type::TYPE_INT32,
269
+ Google::Protobuf::FieldDescriptorProto::Type::TYPE_INT64
270
+ ]
271
+ page_size = request.fields.find do |f|
272
+ f.name == "page_size" && page_size_types.include?(f.type)
273
+ end
274
+ return false if page_size.nil?
275
+
276
+ true
277
+ end
278
+
279
+ def paged_response? response
280
+ next_page_token = response.fields.find do |f|
281
+ f.name == "next_page_token" && f.type == Google::Protobuf::FieldDescriptorProto::Type::TYPE_STRING
282
+ end
283
+ return false if next_page_token.nil?
284
+
285
+ repeated_field = response.fields.find do |f|
286
+ f.label == Google::Protobuf::FieldDescriptorProto::Label::LABEL_REPEATED &&
287
+ f.type == Google::Protobuf::FieldDescriptorProto::Type::TYPE_MESSAGE
288
+ end
289
+ return false if repeated_field.nil?
290
+
291
+ # We want to make sure the first repeated field is also has the lowest field number,
292
+ # but the google-protobuf gem sorts fields by number, so we lose the original order.
293
+
294
+ true
295
+ end
296
+ end
297
+ end
298
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2019 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "active_support/inflector"
18
+ require "gapic/helpers/filepath_helper"
19
+ require "gapic/helpers/namespace_helper"
20
+
21
+ module Gapic
22
+ module Presenters
23
+ ##
24
+ # A presenter for proto packages.
25
+ #
26
+ class PackagePresenter
27
+ include Gapic::Helpers::FilepathHelper
28
+ include Gapic::Helpers::NamespaceHelper
29
+
30
+ def initialize api, package
31
+ @api = api
32
+ @package = package
33
+ end
34
+
35
+ def gem
36
+ GemPresenter.new @api
37
+ end
38
+
39
+ def name
40
+ @package
41
+ end
42
+
43
+ def namespace
44
+ return services.first&.namespace if services.first&.namespace
45
+ ruby_namespace_for_address address
46
+ end
47
+
48
+ def services
49
+ @services ||= begin
50
+ files = @api.generate_files.select { |f| f.package == @package }
51
+ files.map(&:services).flatten.map { |s| ServicePresenter.new @api, s }
52
+ end
53
+ end
54
+
55
+ def address
56
+ @package.split "."
57
+ end
58
+
59
+ def package_require
60
+ ruby_file_path @api, namespace
61
+ end
62
+
63
+ def package_file_path
64
+ package_require + ".rb"
65
+ end
66
+
67
+ def empty?
68
+ services.empty?
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2019 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "gapic/path_template"
18
+ require "ostruct"
19
+ require "active_support/inflector"
20
+
21
+ module Gapic
22
+ module Presenters
23
+ ##
24
+ # A presenter for proto resources.
25
+ #
26
+ class ResourcePresenter
27
+ # @param resource [Google::Api::ResourceDescriptor]
28
+ def initialize resource
29
+ @resource = resource
30
+
31
+ @patterns = resource.pattern.map do |template|
32
+ segments = Gapic::PathTemplate.parse template
33
+ OpenStruct.new(
34
+ template: template,
35
+ segments: segments,
36
+ arguments: arguments_for(segments),
37
+ path_string: path_string_for(segments)
38
+ )
39
+ end
40
+
41
+ @patterns.each do |pattern|
42
+ # URI path template verification for expected proto resource usage
43
+ if named_arg_patterns? pattern.segments
44
+ raise ArgumentError, "only resources without named patterns are supported, " \
45
+ " not #{pattern.template}"
46
+ elsif positional_args? pattern.segments
47
+ raise ArgumentError, "only resources with named segments are supported, " \
48
+ " not #{pattern.template}"
49
+ end
50
+ end
51
+ end
52
+
53
+ def name
54
+ @resource.type.split("/").delete_if(&:empty?).last
55
+ end
56
+
57
+ def type
58
+ @resource.type
59
+ end
60
+
61
+ def patterns
62
+ @patterns
63
+ end
64
+
65
+ def path_helper
66
+ "#{ActiveSupport::Inflector.underscore name}_path"
67
+ end
68
+
69
+ private
70
+
71
+ def arguments_for segments
72
+ arg_segments(segments).map(&:name)
73
+ end
74
+
75
+ def arg_segments segments
76
+ segments.select { |segment| segment.is_a? Gapic::PathTemplate::Segment }
77
+ end
78
+
79
+ def path_string_for segments
80
+ segments.map do |segment|
81
+ if segment.is_a? Gapic::PathTemplate::Segment
82
+ "\#{#{segment.name}}"
83
+ else
84
+ # Should be a String
85
+ segment
86
+ end
87
+ end.join
88
+ end
89
+
90
+ def positional_args? segments
91
+ arg_segments(segments).any?(&:positional?)
92
+ end
93
+
94
+ def named_arg_patterns? segments
95
+ arg_segments(segments).any?(&:pattern)
96
+ end
97
+ end
98
+ end
99
+ end