gapic-generator 0.1.3 → 0.2.2

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 (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