gapic-generator 0.7.1 → 0.9.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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -0
  3. data/lib/gapic/generator/version.rb +1 -1
  4. data/lib/gapic/generators/default_generator.rb +18 -5
  5. data/lib/gapic/generators/default_generator_parameters.rb +8 -4
  6. data/lib/gapic/presenters.rb +4 -0
  7. data/lib/gapic/presenters/field_presenter.rb +44 -0
  8. data/lib/gapic/presenters/gem_presenter.rb +55 -10
  9. data/lib/gapic/presenters/method_presenter.rb +40 -16
  10. data/lib/gapic/presenters/method_rest_presenter.rb +194 -0
  11. data/lib/gapic/presenters/package_presenter.rb +18 -0
  12. data/lib/gapic/presenters/service_config_presenter.rb +48 -0
  13. data/lib/gapic/presenters/service_presenter.rb +60 -4
  14. data/lib/gapic/presenters/service_rest_presenter.rb +139 -0
  15. data/lib/gapic/presenters/snippet_presenter.rb +103 -0
  16. data/lib/gapic/runner.rb +2 -1
  17. data/lib/gapic/schema/api.rb +58 -16
  18. data/lib/gapic/schema/request_param_parser.rb +46 -12
  19. data/lib/google/protobuf/any.pb.rb +1 -1
  20. data/lib/google/protobuf/compiler/plugin.pb.rb +9 -6
  21. data/lib/google/protobuf/descriptor.pb.rb +2 -2
  22. data/lib/google/protobuf/empty.pb.rb +1 -1
  23. data/templates/default/gem/readme.erb +3 -3
  24. data/templates/default/lib/_package.erb +11 -1
  25. data/templates/default/lib/_service.erb +31 -1
  26. data/templates/default/lib/rest/_rest.erb +11 -0
  27. data/templates/default/service/client/_client.erb +1 -1
  28. data/templates/default/service/client/_credentials.erb +2 -0
  29. data/templates/default/service/client/_operations.erb +1 -1
  30. data/templates/default/service/client/_self_configure_defaults.erb +2 -2
  31. data/templates/default/service/rest.erb +6 -0
  32. data/templates/default/service/rest/client.erb +6 -0
  33. data/templates/default/service/rest/client/_client.erb +115 -0
  34. data/templates/default/service/rest/client/_config.erb +74 -0
  35. data/templates/default/service/rest/client/_requires.erb +1 -0
  36. data/templates/default/service/rest/client/method/_def.erb +18 -0
  37. data/templates/default/service/rest/client/method/def/_options_defaults.erb +15 -0
  38. data/templates/default/service/rest/client/method/def/_rescue.erb +3 -0
  39. data/templates/default/service/rest/client/method/def/_response_normal.erb +17 -0
  40. data/templates/default/service/rest/client/method/docs/_error.erb +2 -0
  41. data/templates/default/service/rest/client/method/docs/_request.erb +27 -0
  42. data/templates/default/service/rest/client/method/docs/_result.erb +6 -0
  43. data/templates/default/service/rest/grpc_transcoding.erb +6 -0
  44. data/templates/default/service/rest/grpc_transcoding/_grpc_transcoding.erb +9 -0
  45. data/templates/default/service/rest/grpc_transcoding/method/_def.erb +21 -0
  46. data/templates/default/service/rest/grpc_transcoding/method/def/_query_string_param.erb +8 -0
  47. data/templates/default/service/rest/test/client.erb +18 -0
  48. data/templates/default/service/rest/test/method/_assert_response.erb +2 -0
  49. data/templates/default/service/rest/test/method/_configure.erb +19 -0
  50. data/templates/default/service/rest/test/method/_normal.erb +71 -0
  51. data/templates/default/service/rest/test/method/_setup.erb +38 -0
  52. data/templates/default/snippets/gemfile.erb +17 -0
  53. data/templates/default/snippets/snippet/_structure.erb +71 -0
  54. data/templates/default/snippets/standalone.erb +6 -0
  55. metadata +32 -4
  56. data/templates/default/service/client/_self_configure_retry_policy.erb +0 -15
@@ -0,0 +1,194 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2021 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/uri_template"
18
+
19
+ module Gapic
20
+ module Presenters
21
+ ##
22
+ # A presenter for rpc methods (REST submethods)
23
+ #
24
+ class MethodRestPresenter
25
+ def initialize main_method
26
+ @main_method = main_method
27
+ @proto_method = main_method.method
28
+ end
29
+
30
+ ##
31
+ # @return [Boolean] Whether a http verb is present for this method
32
+ #
33
+ def verb?
34
+ !verb.nil?
35
+ end
36
+
37
+ ##
38
+ # @return [Symbol] a http verb for this method
39
+ #
40
+ def verb
41
+ return nil if @proto_method.http.nil?
42
+
43
+ method = {
44
+ get: @proto_method.http.get,
45
+ post: @proto_method.http.post,
46
+ put: @proto_method.http.put,
47
+ patch: @proto_method.http.patch,
48
+ delete: @proto_method.http.delete
49
+ }.find { |_, value| !value.empty? }
50
+
51
+ method[0] unless method.nil?
52
+ end
53
+
54
+ ##
55
+ # @return [Boolean] Whether a method path is present and non-empty
56
+ #
57
+ def path?
58
+ !path.empty?
59
+ end
60
+
61
+ ##
62
+ # @return [String] A method path or an empty string if not present
63
+ #
64
+ def path
65
+ return "" if @proto_method.http.nil?
66
+
67
+ verb_path = [
68
+ @proto_method.http.get, @proto_method.http.post, @proto_method.http.put,
69
+ @proto_method.http.patch, @proto_method.http.delete
70
+ ].find { |x| !x.empty? }
71
+
72
+ verb_path || @proto_method.http.custom&.path || ""
73
+ end
74
+
75
+ ##
76
+ # @return [Boolean] Whether any routing params are present
77
+ #
78
+ def routing_params?
79
+ routing_params.any?
80
+ end
81
+
82
+ ##
83
+ # @return [Array<String>] The segment key names.
84
+ #
85
+ def routing_params
86
+ Gapic::UriTemplate.parse_arguments path
87
+ end
88
+
89
+ ##
90
+ # Performs a limited version of grpc transcoding to create a string that will interpolate
91
+ # the values from the request object to create a request URI at runtime.
92
+ # Currently only supports "value" into "request_object.value"
93
+ # @param [String] request_obj_name the name of the request object for the interpolation
94
+ # defaults to "request_pb"
95
+ # @return [String] A string to interpolate values from the request object into URI
96
+ #
97
+ def uri_interpolated request_obj_name = "request_pb"
98
+ return path unless routing_params?
99
+
100
+ routing_params.reduce path do |uri, param|
101
+ param_esc = Regexp.escape param
102
+ uri.gsub(/{#{param_esc}[^}]*}/, "\#{#{request_obj_name}.#{param}}")
103
+ end
104
+ end
105
+
106
+ ##
107
+ # @return [Boolean] Whether method has body specified in proto
108
+ #
109
+ def body?
110
+ return false if @proto_method.http.nil?
111
+
112
+ !@proto_method.http.body.empty?
113
+ end
114
+
115
+ ##
116
+ # Name of the variable to use for storing the body result of the transcoding call
117
+ # Normally "body" but use "_body" for discarding the result for
118
+ # the calls that do not send body
119
+ # @return [String]
120
+ def body_var_name
121
+ body? ? "body" : "_body"
122
+ end
123
+
124
+ ##
125
+ # @return [String] A body specified for the given method in proto or an empty string if not specified
126
+ #
127
+ def body
128
+ @proto_method.http&.body || ""
129
+ end
130
+
131
+ ##
132
+ # @return [Boolean] True if body contains full request object (`*` in the annotation), false otherwise
133
+ #
134
+ def body_is_request_object?
135
+ body == "*"
136
+ end
137
+
138
+ ##
139
+ # Performs a limited version of grpc transcoding to create a string that will interpolate
140
+ # the values from the request object to create a request body at runtime.
141
+ # Currently only supports either "*" for "the whole request object" or
142
+ # "value" for "request_object.value"
143
+ #
144
+ # @param [String] request_obj_name the name of the request object for the interpolation
145
+ # defaults to "request_pb"
146
+ #
147
+ # @return [String] A string to interpolate values from the request object into body
148
+ #
149
+ def body_interpolated request_obj_name = "request_pb"
150
+ return "\"\"" unless body?
151
+
152
+ return "#{request_obj_name}.to_json" if body_is_request_object?
153
+
154
+ "#{request_obj_name}.#{body}.to_json"
155
+ end
156
+
157
+ ##
158
+ # @return [Boolean] whether any query string parameters are present
159
+ #
160
+ def query_string_params?
161
+ query_string_params.any?
162
+ end
163
+
164
+ # @return [Array<String>]
165
+ def query_string_params
166
+ return [] if body_is_request_object?
167
+
168
+ routing_params_set = routing_params.to_set
169
+ @main_method.arguments
170
+ .reject { |arg| routing_params_set.include? arg.name }
171
+ .reject { |arg| body == arg.name }
172
+ .reject(&:message?)
173
+ .reject { |arg| arg.default_value_for_type.nil? }
174
+ end
175
+
176
+ ##
177
+ # Name of the variable to use for storing the query_string_params result of the transcoding call
178
+ # Normally "query_string_params" but use "_query_string_params" for discarding the result for
179
+ # the calls that do not sent query_string_params
180
+ # @return [String]
181
+ def query_string_params_var_name
182
+ query_string_params? ? "query_string_params" : "_query_string_params"
183
+ end
184
+
185
+ ##
186
+ # Name for the GRPC transcoding helper method
187
+ #
188
+ # @return [String]
189
+ def transcoding_helper_name
190
+ "transcode_#{@main_method.name}"
191
+ end
192
+ end
193
+ end
194
+ end
@@ -54,7 +54,10 @@ module Gapic
54
54
  namespace.split("::").last
55
55
  end
56
56
 
57
+ ##
57
58
  # Services whose clients should be generated in this package namespace.
59
+ # @return [Enumerable<Gapic::Presenters::ServicePresenter>]
60
+ #
58
61
  def services
59
62
  @services ||= begin
60
63
  files = @api.generate_files.select { |f| f.package == @package }
@@ -117,6 +120,21 @@ module Gapic
117
120
  services: services.map { |s| [s.grpc_service_name, s.drift_manifest] }.to_h
118
121
  }
119
122
  end
123
+
124
+ ##
125
+ # How comments in the generated libraries refer to the GRPC client
126
+ # if no REST code is generated, this should just be "client",
127
+ # if REST code is generated, this should be disambiguated into the "GRPC client"
128
+ #
129
+ # Since we are using first service for an indication of whether package generates
130
+ # REST code, it's OK to defer this to the first service as well.
131
+ # For packages with no services the value of this does not really matter as
132
+ # no client generation docs will be generated.
133
+ #
134
+ # @return [String]
135
+ def grpc_client_designation
136
+ services.first&.grpc_client_designation || ""
137
+ end
120
138
  end
121
139
  end
122
140
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2021 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
+ module Gapic
18
+ module Presenters
19
+ ##
20
+ # A presenter for grpc service config.
21
+ #
22
+ class ServiceConfigPresenter
23
+ def initialize grpc_service_config
24
+ @grpc_service_config = grpc_service_config
25
+ end
26
+
27
+ attr_reader :grpc_service_config
28
+
29
+ def retry_policy_fields
30
+ elems = []
31
+ retry_policy = grpc_service_config&.retry_policy
32
+ if retry_policy&.initial_delay_seconds
33
+ elems << "initial_delay: #{Gapic::FormattingUtils.format_number retry_policy.initial_delay_seconds}"
34
+ end
35
+ if retry_policy&.max_delay_seconds
36
+ elems << "max_delay: #{Gapic::FormattingUtils.format_number retry_policy.max_delay_seconds}"
37
+ end
38
+ if retry_policy&.multiplier
39
+ elems << "multiplier: #{Gapic::FormattingUtils.format_number retry_policy.multiplier}"
40
+ end
41
+ if retry_policy&.status_codes
42
+ elems << "retry_codes: #{retry_policy.status_codes}"
43
+ end
44
+ elems.empty? ? "{}" : "{\n #{elems.join ', '}\n}"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -27,11 +27,15 @@ module Gapic
27
27
  include Gapic::Helpers::FilepathHelper
28
28
  include Gapic::Helpers::NamespaceHelper
29
29
 
30
+ # @return [Gapic::Presenters::ServiceRestPresenter]
31
+ attr_reader :rest
32
+
30
33
  def initialize gem_presenter, api, service, parent_service: nil
31
34
  @gem_presenter = gem_presenter
32
35
  @api = api
33
36
  @service = service
34
37
  @parent_service = parent_service
38
+ @rest = ServiceRestPresenter.new self, api
35
39
  end
36
40
 
37
41
  def gem
@@ -46,10 +50,11 @@ module Gapic
46
50
  PackagePresenter.new @gem_presenter, @api, @service.parent.package
47
51
  end
48
52
 
53
+ ##
54
+ # @return [Enumerable<Gapic::Presenters::MethodPresenter>]
55
+ #
49
56
  def methods
50
- @methods ||= begin
51
- @service.methods.map { |m| MethodPresenter.new self, @api, m }
52
- end
57
+ @methods ||= @service.methods.map { |m| MethodPresenter.new self, @api, m }
53
58
  end
54
59
 
55
60
  def address
@@ -271,6 +276,29 @@ module Gapic
271
276
  ruby_file_path @api, "#{service_name_full}::#{paths_name}"
272
277
  end
273
278
 
279
+ def generate_rest_clients?
280
+ @api.generate_rest_clients?
281
+ end
282
+
283
+ def generate_grpc_clients?
284
+ @api.generate_grpc_clients?
285
+ end
286
+
287
+ ##
288
+ # @return [Boolean] whether this service contains any methods with REST bindings
289
+ #
290
+ def methods_rest_bindings?
291
+ methods_rest_bindings.any?
292
+ end
293
+
294
+ ##
295
+ # @return [Enumerable<Gapic::Presenters::MethodPresenter>]
296
+ # List of mods for which REST bindings are present and REST methods can be generated
297
+ #
298
+ def methods_rest_bindings
299
+ methods.select { |method| method.rest.path? && method.rest.verb? }
300
+ end
301
+
274
302
  def test_client_file_path
275
303
  service_file_path.sub ".rb", "_test.rb"
276
304
  end
@@ -333,6 +361,10 @@ module Gapic
333
361
  @api.grpc_service_config.service_level_configs[grpc_full_name]
334
362
  end
335
363
 
364
+ def service_config_presenter
365
+ ServiceConfigPresenter.new grpc_service_config
366
+ end
367
+
336
368
  ##
337
369
  # The short proto name for this service
338
370
  #
@@ -361,12 +393,36 @@ module Gapic
361
393
  # their names are returned together in an array.
362
394
  # For Ruby currently we have 1:1 proto to code
363
395
  # correspondence for methods, so our generation is easier
364
- methods: methods.map { |m| [m.grpc_method_name, [m.name]] }.to_h
396
+ rpcs: methods.map { |m| [m.grpc_method_name, m.drift_manifest] }.to_h
365
397
  }
366
398
  }
367
399
  }
368
400
  end
369
401
 
402
+ ##
403
+ # How comments in the generated libraries refer to the GRPC client
404
+ # if no REST code is generated, this should just be "client",
405
+ # if REST code is generated, this should be disambiguated into the "GRPC client"
406
+ #
407
+ # @return [String]
408
+ def grpc_client_designation
409
+ generate_rest_clients? ? "GRPC client" : "client"
410
+ end
411
+
412
+ ##
413
+ # The method to use for quick start samples. Normally this is simply the
414
+ # first non-client-streaming method defined, but it can be overridden via
415
+ # a gem config.
416
+ #
417
+ # @return [Gapic::Presenters::MethodPresenter]
418
+ #
419
+ def quick_start_method
420
+ gem_config = @api.configuration[:gem]
421
+ preferred_method = gem_config[:quick_start_method] if gem_config
422
+ result = methods.find { |meth| meth.name == preferred_method } if preferred_method
423
+ result || methods.find { |meth| !meth.client_streaming? }
424
+ end
425
+
370
426
  private
371
427
 
372
428
  def default_config key
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2021 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 service (REST submethods)
25
+ #
26
+ class ServiceRestPresenter
27
+ include Gapic::Helpers::FilepathHelper
28
+ include Gapic::Helpers::NamespaceHelper
29
+
30
+ ##
31
+ # @param main_service [Gapic::Presenters::ServicePresenter]
32
+ # @param api [Gapic::Schema::Api]
33
+ #
34
+ def initialize main_service, api
35
+ @main_service = main_service
36
+ @api = api
37
+ end
38
+
39
+ ##
40
+ # @return [String]
41
+ #
42
+ def service_name_full
43
+ fix_namespace api, "#{main_service.service_name_full}::Rest"
44
+ end
45
+
46
+ ##
47
+ # @return [String]
48
+ #
49
+ def client_name
50
+ main_service.client_name
51
+ end
52
+
53
+ ##
54
+ # @return [String]
55
+ #
56
+ def client_name_full
57
+ fix_namespace api, "#{service_name_full}::#{client_name}"
58
+ end
59
+
60
+ ##
61
+ # @return [String]
62
+ #
63
+ def client_require
64
+ ruby_file_path api, client_name_full
65
+ end
66
+
67
+ ##
68
+ # @return [String]
69
+ #
70
+ def client_file_path
71
+ "#{client_require}.rb"
72
+ end
73
+
74
+ ##
75
+ # @return [String]
76
+ #
77
+ def create_client_call
78
+ "#{client_name_full}.new"
79
+ end
80
+
81
+ ##
82
+ # @return [String]
83
+ #
84
+ def service_rest_require
85
+ ruby_file_path api, service_name_full
86
+ end
87
+
88
+ ##
89
+ # @return [String]
90
+ #
91
+ def service_rest_file_path
92
+ "#{service_rest_require}.rb"
93
+ end
94
+
95
+ ##
96
+ # @return [String]
97
+ #
98
+ def transcoding_helper_name
99
+ "GrpcTranscoding"
100
+ end
101
+
102
+ ##
103
+ # @return [String]
104
+ #
105
+ def transcoding_helper_name_full
106
+ fix_namespace api, "#{service_name_full}::#{transcoding_helper_name}"
107
+ end
108
+
109
+ ##
110
+ # @return [String]
111
+ #
112
+ def transcoding_helper_require
113
+ ruby_file_path api, transcoding_helper_name_full
114
+ end
115
+
116
+ ##
117
+ # @return [String]
118
+ #
119
+ def transcoding_helper_file_path
120
+ "#{transcoding_helper_require}.rb"
121
+ end
122
+
123
+ ##
124
+ # @return [String]
125
+ #
126
+ def test_client_file_path
127
+ main_service.service_file_path.sub ".rb", "_test.rb"
128
+ end
129
+
130
+
131
+ private
132
+
133
+ # @return [Gapic::Presenters::ServicePresenter]
134
+ attr_reader :main_service
135
+ # @return [Gapic::Schema::Api]
136
+ attr_reader :api
137
+ end
138
+ end
139
+ end