gapic-generator 0.1.4 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -0
  3. data/lib/gapic/formatting_utils.rb +65 -14
  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 +172 -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 +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 +25 -2
  24. data/templates/default/gem/gemspec.erb +1 -1
  25. data/templates/default/gem/readme.erb +2 -2
  26. data/templates/default/gem/rubocop.erb +2 -0
  27. data/templates/default/helpers/filepath_helper.rb +2 -21
  28. data/templates/default/helpers/namespace_helper.rb +2 -27
  29. data/templates/default/layouts/_ruby.erb +1 -3
  30. data/templates/default/service/client/_client.erb +7 -1
  31. data/templates/default/service/client/_paths.erb +1 -0
  32. data/templates/default/service/client/method/def/_options_defaults.erb +1 -1
  33. data/templates/default/service/client/method/def/_response_normal.erb +1 -1
  34. metadata +16 -14
  35. data/templates/default/helpers/presenter_helper.rb +0 -24
  36. data/templates/default/helpers/presenters/field_presenter.rb +0 -146
  37. data/templates/default/helpers/presenters/file_presenter.rb +0 -53
  38. data/templates/default/helpers/presenters/gem_presenter.rb +0 -140
  39. data/templates/default/helpers/presenters/message_presenter.rb +0 -66
  40. data/templates/default/helpers/presenters/method_presenter.rb +0 -293
  41. data/templates/default/helpers/presenters/package_presenter.rb +0 -65
  42. data/templates/default/helpers/presenters/resource_presenter.rb +0 -92
  43. data/templates/default/helpers/presenters/sample_presenter.rb +0 -74
  44. data/templates/default/helpers/presenters/service_presenter.rb +0 -276
@@ -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,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