gapic-generator 0.1.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +55 -0
  3. data/lib/gapic/formatting_utils.rb +63 -12
  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 +13 -14
  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 +176 -0
  15. data/lib/gapic/presenters/message_presenter.rb +73 -0
  16. data/lib/gapic/presenters/method_presenter.rb +307 -0
  17. data/lib/gapic/presenters/package_presenter.rb +80 -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 +306 -0
  21. data/lib/gapic/resource_lookup.rb +23 -38
  22. data/lib/gapic/schema/api.rb +70 -0
  23. data/lib/gapic/schema/loader.rb +9 -2
  24. data/lib/gapic/schema/wrappers.rb +134 -24
  25. data/templates/default/gem/entrypoint.erb +8 -0
  26. data/templates/default/gem/gemspec.erb +2 -2
  27. data/templates/default/gem/readme.erb +17 -3
  28. data/templates/default/gem/rubocop.erb +13 -41
  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/lib/_package.erb +17 -0
  33. data/templates/default/lib/_service.erb +32 -0
  34. data/templates/default/package.erb +5 -5
  35. data/templates/default/service.erb +5 -7
  36. data/templates/default/service/_helpers.erb +3 -0
  37. data/templates/default/service/client/_client.erb +7 -17
  38. data/templates/default/service/client/_operations.erb +0 -4
  39. data/templates/default/service/client/_paths.erb +1 -0
  40. data/templates/default/service/client/method/def/_options_defaults.erb +1 -1
  41. data/templates/default/service/client/method/def/_response_normal.erb +1 -1
  42. data/templates/default/service/client/method/docs/_request_normal.erb +10 -5
  43. data/templates/default/service/client/method/docs/_request_streaming.erb +1 -1
  44. metadata +20 -15
  45. data/templates/default/helpers/presenter_helper.rb +0 -24
  46. data/templates/default/helpers/presenters/field_presenter.rb +0 -146
  47. data/templates/default/helpers/presenters/file_presenter.rb +0 -53
  48. data/templates/default/helpers/presenters/gem_presenter.rb +0 -140
  49. data/templates/default/helpers/presenters/message_presenter.rb +0 -66
  50. data/templates/default/helpers/presenters/method_presenter.rb +0 -293
  51. data/templates/default/helpers/presenters/package_presenter.rb +0 -65
  52. data/templates/default/helpers/presenters/resource_presenter.rb +0 -92
  53. data/templates/default/helpers/presenters/sample_presenter.rb +0 -74
  54. data/templates/default/helpers/presenters/service_presenter.rb +0 -276
  55. data/templates/default/service/client/_helpers.erb +0 -9
@@ -0,0 +1,307 @@
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
+
164
+ # HACK(dazuma, 2020-04-06): Two specific RPCs should not be paged.
165
+ # This is an intentionally hard-coded exception (and a temporary one,
166
+ # to be removed when these methods no longer conform to AIP-4233.) For
167
+ # detailed information, see internal link go/actools-talent-pagination.
168
+ address = @method.address.join "."
169
+ return false if address == "google.cloud.talent.v4beta1.SearchProfiles"
170
+ return false if address == "google.cloud.talent.v4beta1.SearchJobs"
171
+
172
+ paged_request?(@method.input) && paged_response?(@method.output)
173
+ end
174
+
175
+ def paged_response_type
176
+ return nil unless paged_response? @method.output
177
+
178
+ repeated_field = @method.output.fields.find do |f|
179
+ f.label == Google::Protobuf::FieldDescriptorProto::Label::LABEL_REPEATED &&
180
+ f.type == Google::Protobuf::FieldDescriptorProto::Type::TYPE_MESSAGE
181
+ end
182
+ message_ruby_type repeated_field.message
183
+ end
184
+
185
+ ##
186
+ #
187
+ # @return [Array<String>] The segment key names.
188
+ #
189
+ def routing_params
190
+ segments = Gapic::PathTemplate.parse method_path
191
+ segments.select { |s| s.is_a? Gapic::PathTemplate::Segment }.map(&:name)
192
+ end
193
+
194
+ def routing_params?
195
+ routing_params.any?
196
+ end
197
+
198
+ def grpc_service_config
199
+ if @api.grpc_service_config&.service_method_level_configs&.key?(service.grpc_full_name) &&
200
+ @api.grpc_service_config.service_method_level_configs[service.grpc_full_name]&.key?(grpc_method_name)
201
+ @api.grpc_service_config.service_method_level_configs[service.grpc_full_name][grpc_method_name]
202
+ end
203
+ end
204
+
205
+ def grpc_method_name
206
+ @method.name
207
+ end
208
+
209
+ protected
210
+
211
+ def message_ruby_type message
212
+ ruby_namespace @api, message.address.join(".")
213
+ end
214
+
215
+ def doc_types_for arg
216
+ if arg.message?
217
+ "#{message_ruby_type arg.message}, Hash"
218
+ elsif arg.enum?
219
+ # TODO: handle when arg message is nil and enum is the type
220
+ message_ruby_type arg.enum
221
+ else
222
+ case arg.type
223
+ when 1, 2 then "Float"
224
+ when 3, 4, 5, 6, 7, 13, 15, 16, 17, 18 then "Integer"
225
+ when 9, 12 then "String"
226
+ when 8 then "Boolean"
227
+ else
228
+ "Object"
229
+ end
230
+ end
231
+ end
232
+
233
+ def doc_desc_for arg
234
+ return nil if arg.docs.leading_comments.empty?
235
+
236
+ arg.docs.leading_comments
237
+ end
238
+
239
+ def default_value_for arg
240
+ if arg.message?
241
+ "{}"
242
+ elsif arg.enum?
243
+ # TODO: select the first non-0 enum value
244
+ # ":ENUM"
245
+ arg.enum.values.first
246
+ else
247
+ case arg.type
248
+ when 1, 2 then "3.14"
249
+ when 3, 4, 5, 6, 7, 13, 15, 16, 17, 18 then "42"
250
+ when 9, 12 then "\"hello world\""
251
+ when 8 then "true"
252
+ else
253
+ "Object"
254
+ end
255
+ end
256
+ end
257
+
258
+ def method_path
259
+ return "" if @method.http.nil?
260
+
261
+ method = [
262
+ @method.http.get, @method.http.post, @method.http.put,
263
+ @method.http.patch, @method.http.delete
264
+ ].find { |x| !x.empty? }
265
+ return method unless method.nil?
266
+
267
+ return @method.http.custom.path unless @method.http.custom.nil?
268
+ end
269
+
270
+ def paged_request? request
271
+ page_token = request.fields.find do |f|
272
+ f.name == "page_token" && f.type == Google::Protobuf::FieldDescriptorProto::Type::TYPE_STRING
273
+ end
274
+ return false if page_token.nil?
275
+
276
+ page_size_types = [
277
+ Google::Protobuf::FieldDescriptorProto::Type::TYPE_INT32,
278
+ Google::Protobuf::FieldDescriptorProto::Type::TYPE_INT64
279
+ ]
280
+ page_size = request.fields.find do |f|
281
+ f.name == "page_size" && page_size_types.include?(f.type)
282
+ end
283
+ return false if page_size.nil?
284
+
285
+ true
286
+ end
287
+
288
+ def paged_response? response
289
+ next_page_token = response.fields.find do |f|
290
+ f.name == "next_page_token" && f.type == Google::Protobuf::FieldDescriptorProto::Type::TYPE_STRING
291
+ end
292
+ return false if next_page_token.nil?
293
+
294
+ repeated_field = response.fields.find do |f|
295
+ f.label == Google::Protobuf::FieldDescriptorProto::Label::LABEL_REPEATED &&
296
+ f.type == Google::Protobuf::FieldDescriptorProto::Type::TYPE_MESSAGE
297
+ end
298
+ return false if repeated_field.nil?
299
+
300
+ # We want to make sure the first repeated field is also has the lowest field number,
301
+ # but the google-protobuf gem sorts fields by number, so we lose the original order.
302
+
303
+ true
304
+ end
305
+ end
306
+ end
307
+ end
@@ -0,0 +1,80 @@
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 parent_namespace
49
+ namespace.split("::")[0...-1].join("::")
50
+ end
51
+
52
+ def module_name
53
+ namespace.split("::").last
54
+ end
55
+
56
+ def services
57
+ @services ||= begin
58
+ files = @api.generate_files.select { |f| f.package == @package }
59
+ files.map(&:services).flatten.map { |s| ServicePresenter.new @api, s }
60
+ end
61
+ end
62
+
63
+ def address
64
+ @package.split "."
65
+ end
66
+
67
+ def package_require
68
+ ruby_file_path @api, namespace
69
+ end
70
+
71
+ def package_file_path
72
+ package_require + ".rb"
73
+ end
74
+
75
+ def empty?
76
+ services.empty?
77
+ end
78
+ end
79
+ end
80
+ 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