gapic-generator 0.3.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/lib/gapic/formatting_utils.rb +7 -7
  4. data/lib/gapic/generator/version.rb +1 -1
  5. data/lib/gapic/generators/default_generator.rb +16 -14
  6. data/lib/gapic/helpers/filepath_helper.rb +1 -0
  7. data/lib/gapic/helpers/namespace_helper.rb +8 -1
  8. data/lib/gapic/path_template/segment.rb +7 -0
  9. data/lib/gapic/presenters/field_presenter.rb +9 -9
  10. data/lib/gapic/presenters/file_presenter.rb +1 -1
  11. data/lib/gapic/presenters/gem_presenter.rb +28 -2
  12. data/lib/gapic/presenters/method_presenter.rb +23 -17
  13. data/lib/gapic/presenters/package_presenter.rb +11 -3
  14. data/lib/gapic/presenters/resource_presenter.rb +55 -35
  15. data/lib/gapic/presenters/service_presenter.rb +66 -23
  16. data/lib/gapic/ruby_info.rb +93 -0
  17. data/lib/gapic/schema/api.rb +63 -1
  18. data/templates/default/gem/gemfile.erb +3 -0
  19. data/templates/default/gem/gemspec.erb +7 -6
  20. data/templates/default/gem/rakefile.erb +1 -0
  21. data/templates/default/gem/test_helper.erb +8 -0
  22. data/templates/default/layouts/_ruby.erb +5 -4
  23. data/templates/default/lib/_service.erb +2 -0
  24. data/templates/default/proto_docs/_message.erb +2 -2
  25. data/templates/default/service/client.erb +1 -1
  26. data/templates/default/service/client/_client.erb +17 -4
  27. data/templates/default/service/client/_config.erb +33 -29
  28. data/templates/default/service/client/_credentials.erb +1 -1
  29. data/templates/default/service/client/_operations.erb +3 -1
  30. data/templates/default/service/client/method/def/_options_defaults.erb +2 -2
  31. data/templates/default/service/client/method/def/_request_normal.erb +2 -2
  32. data/templates/default/service/client/method/def/_request_streaming.erb +3 -3
  33. data/templates/default/service/client/method/def/_response_normal.erb +1 -1
  34. data/templates/default/service/client/method/def/_response_paged.erb +2 -2
  35. data/templates/default/service/client/method/docs/_error.erb +1 -1
  36. data/templates/default/service/client/method/docs/_request_normal.erb +2 -2
  37. data/templates/default/service/client/method/docs/_request_streaming.erb +2 -2
  38. data/templates/default/service/client/method/docs/_response.erb +1 -1
  39. data/templates/default/service/client/resource/_def.erb +1 -1
  40. data/templates/default/service/client/resource/_multi.erb +4 -7
  41. data/templates/default/service/client/resource/_single.erb +2 -3
  42. data/templates/default/service/credentials.erb +1 -1
  43. data/templates/default/service/operations.erb +1 -1
  44. data/templates/default/service/paths.erb +1 -1
  45. data/templates/default/service/test/_resource.erb +16 -0
  46. data/templates/default/service/test/client.erb +17 -4
  47. data/templates/default/service/test/client_operations.erb +3 -4
  48. data/templates/default/service/test/client_paths.erb +17 -0
  49. data/templates/default/service/test/method/_configure.erb +19 -0
  50. metadata +8 -3
@@ -27,14 +27,15 @@ module Gapic
27
27
  include Gapic::Helpers::FilepathHelper
28
28
  include Gapic::Helpers::NamespaceHelper
29
29
 
30
- def initialize api, service, parent_service: nil
30
+ def initialize gem_presenter, api, service, parent_service: nil
31
+ @gem_presenter = gem_presenter
31
32
  @api = api
32
33
  @service = service
33
34
  @parent_service = parent_service
34
35
  end
35
36
 
36
37
  def gem
37
- GemPresenter.new @api
38
+ @gem_presenter
38
39
  end
39
40
 
40
41
  def file
@@ -42,12 +43,12 @@ module Gapic
42
43
  end
43
44
 
44
45
  def package
45
- PackagePresenter.new @api, @service.parent.package
46
+ PackagePresenter.new @gem_presenter, @api, @service.parent.package
46
47
  end
47
48
 
48
49
  def methods
49
50
  @methods ||= begin
50
- @service.methods.map { |m| MethodPresenter.new @api, m }
51
+ @service.methods.map { |m| MethodPresenter.new self, @api, m }
51
52
  end
52
53
  end
53
54
 
@@ -55,8 +56,26 @@ module Gapic
55
56
  @service.address
56
57
  end
57
58
 
59
+ # Returns a presenter for this service's delegate (if it is a common service)
60
+ # otherwise returns `nil`.
61
+ def common_service_delegate
62
+ unless defined? @common_service_delegate
63
+ delegate = @api.delegate_service_for @service
64
+ @common_service_delegate = delegate ? ServicePresenter.new(@gem_presenter, @api, delegate) : nil
65
+ end
66
+ @common_service_delegate
67
+ end
68
+
69
+ # The namespace of the client. Normally this is the version module. This
70
+ # may be different from the proto namespace for a common service.
58
71
  def namespace
59
- return @service.ruby_package if @service.ruby_package.present?
72
+ # If this service is a common service, its client should go into its
73
+ # delegate's namespace rather than its own. For example, KMS includes
74
+ # the common IAMPolicy service, but that service's client should go
75
+ # into the KMS namespace.
76
+ return common_service_delegate.namespace if common_service_delegate
77
+
78
+ return ensure_absolute_namespace @service.ruby_package if @service.ruby_package.present?
60
79
 
61
80
  namespace = ruby_namespace_for_address @service.address[0...-1]
62
81
  fix_namespace @api, namespace
@@ -71,15 +90,25 @@ module Gapic
71
90
  end
72
91
 
73
92
  def name
74
- @service.name
93
+ @api.fix_service_name @service.name
94
+ end
95
+
96
+ # The namespace of the protos. This may be different from the client
97
+ # namespace for a common service.
98
+ def proto_namespace
99
+ return ensure_absolute_namespace @service.ruby_package if @service.ruby_package.present?
100
+
101
+ namespace = ruby_namespace_for_address @service.address[0...-1]
102
+ @api.override_proto_namespaces? ? fix_namespace(@api, namespace) : namespace
75
103
  end
76
104
 
77
105
  def proto_service_name_full
78
- fix_namespace @api, "#{namespace}::#{name}"
106
+ name_full = "#{proto_namespace}::#{@service.name}"
107
+ @api.override_proto_namespaces? ? fix_namespace(@api, name_full) : name_full
79
108
  end
80
109
 
81
110
  def module_name
82
- proto_service_name_full.split("::").last
111
+ service_name_full.split("::").last
83
112
  end
84
113
 
85
114
  def proto_service_file_path
@@ -110,6 +139,10 @@ module Gapic
110
139
  "#{proto_service_name_full}::Stub"
111
140
  end
112
141
 
142
+ def service_name_full
143
+ fix_namespace @api, "#{namespace}::#{name}"
144
+ end
145
+
113
146
  def service_file_path
114
147
  service_require + ".rb"
115
148
  end
@@ -123,7 +156,7 @@ module Gapic
123
156
  end
124
157
 
125
158
  def service_require
126
- ruby_file_path @api, proto_service_name_full
159
+ ruby_file_path @api, service_name_full
127
160
  end
128
161
 
129
162
  def client_name
@@ -131,7 +164,7 @@ module Gapic
131
164
  end
132
165
 
133
166
  def client_name_full
134
- fix_namespace @api, "#{proto_service_name_full}::#{client_name}"
167
+ fix_namespace @api, "#{service_name_full}::#{client_name}"
135
168
  end
136
169
 
137
170
  def create_client_call
@@ -155,16 +188,22 @@ module Gapic
155
188
  end
156
189
 
157
190
  def client_endpoint
158
- return @parent_service.client_endpoint if @parent_service
159
- @service.host || default_config(:default_host) || "localhost"
191
+ return nil if generic_endpoint?
192
+ @parent_service&.client_endpoint ||
193
+ common_service_delegate&.client_endpoint ||
194
+ @service.host ||
195
+ default_config(:default_host) ||
196
+ "localhost"
160
197
  end
161
198
 
162
- def client_scopes
163
- @service.scopes || default_config(:oauth_scopes)
199
+ def generic_endpoint?
200
+ gem.generic_endpoint?
164
201
  end
165
202
 
166
- def client_proto_name
167
- @service.address.join "."
203
+ def client_scopes
204
+ common_service_delegate&.client_scopes ||
205
+ @service.scopes ||
206
+ default_config(:oauth_scopes)
168
207
  end
169
208
 
170
209
  def credentials_name
@@ -172,7 +211,7 @@ module Gapic
172
211
  end
173
212
 
174
213
  def credentials_name_full
175
- fix_namespace @api, "#{proto_service_name_full}::#{credentials_name}"
214
+ fix_namespace @api, "#{service_name_full}::#{credentials_name}"
176
215
  end
177
216
 
178
217
  def credentials_class_xref
@@ -200,7 +239,7 @@ module Gapic
200
239
  end
201
240
 
202
241
  def helpers_require
203
- ruby_file_path @api, "#{proto_service_name_full}::Helpers"
242
+ ruby_file_path @api, "#{service_name_full}::Helpers"
204
243
  end
205
244
 
206
245
  def references
@@ -216,7 +255,7 @@ module Gapic
216
255
  end
217
256
 
218
257
  def paths_name_full
219
- fix_namespace @api, "#{proto_service_name_full}::#{paths_name}"
258
+ fix_namespace @api, "#{service_name_full}::#{paths_name}"
220
259
  end
221
260
 
222
261
  def paths_file_path
@@ -228,13 +267,17 @@ module Gapic
228
267
  end
229
268
 
230
269
  def paths_require
231
- ruby_file_path @api, "#{proto_service_name_full}::#{paths_name}"
270
+ ruby_file_path @api, "#{service_name_full}::#{paths_name}"
232
271
  end
233
272
 
234
273
  def test_client_file_path
235
274
  service_file_path.sub ".rb", "_test.rb"
236
275
  end
237
276
 
277
+ def test_paths_file_path
278
+ service_file_path.sub ".rb", "_paths_test.rb"
279
+ end
280
+
238
281
  def test_client_operations_file_path
239
282
  service_file_path.sub ".rb", "_operations_test.rb"
240
283
  end
@@ -260,7 +303,7 @@ module Gapic
260
303
  end
261
304
 
262
305
  def operations_name_full
263
- fix_namespace @api, "#{proto_service_name_full}::#{operations_name}"
306
+ fix_namespace @api, "#{service_name_full}::#{operations_name}"
264
307
  end
265
308
 
266
309
  def operations_file_path
@@ -272,12 +315,12 @@ module Gapic
272
315
  end
273
316
 
274
317
  def operations_require
275
- ruby_file_path @api, "#{proto_service_name_full}::#{operations_name}"
318
+ ruby_file_path @api, "#{service_name_full}::#{operations_name}"
276
319
  end
277
320
 
278
321
  def lro_service
279
322
  lro = @service.parent.parent.files.find { |file| file.name == "google/longrunning/operations.proto" }
280
- return ServicePresenter.new @api, lro.services.first, parent_service: self unless lro.nil?
323
+ return ServicePresenter.new @gem_presenter, @api, lro.services.first, parent_service: self unless lro.nil?
281
324
  end
282
325
 
283
326
  def config_channel_args
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2020 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
+ ##
19
+ # Various Ruby language information useful for generators.
20
+ #
21
+ module RubyInfo
22
+ class << self
23
+ ##
24
+ # A sorted list of Ruby's keywords.
25
+ #
26
+ # @see https://docs.ruby-lang.org/en/2.7.0/keywords_rdoc.html
27
+ #
28
+ # @return [Array<String>]
29
+ #
30
+ def keywords
31
+ @keywords ||= [
32
+ "__ENCODING__",
33
+ "__LINE__",
34
+ "__FILE__",
35
+ "BEGIN",
36
+ "END",
37
+ "alias",
38
+ "and",
39
+ "begin",
40
+ "break",
41
+ "case",
42
+ "class",
43
+ "def",
44
+ "defined?",
45
+ "do",
46
+ "else",
47
+ "elsif",
48
+ "end",
49
+ "ensure",
50
+ "false",
51
+ "for",
52
+ "if",
53
+ "in",
54
+ "module",
55
+ "next",
56
+ "nil",
57
+ "not",
58
+ "or",
59
+ "redo",
60
+ "rescue",
61
+ "retry",
62
+ "return",
63
+ "self",
64
+ "super",
65
+ "then",
66
+ "true",
67
+ "undef",
68
+ "unless",
69
+ "until",
70
+ "when",
71
+ "while",
72
+ "yield"
73
+ ].freeze
74
+ end
75
+
76
+ ##
77
+ # A sorted list of method names that generated code should avoid.
78
+ # This includes methods of the Object class (including BasicObject and
79
+ # Kernel), Ruby keywords, and a few special names including "initialize"
80
+ # and "configure".
81
+ #
82
+ # @return [Array<String>]
83
+ #
84
+ def excluded_method_names
85
+ @excluded_method_names ||= begin
86
+ object_methods = (Object.instance_methods + Object.private_instance_methods).map(&:to_s)
87
+ other_methods = ["configure", "initialize"]
88
+ (object_methods + other_methods + keywords).sort.freeze
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -91,6 +91,13 @@ module Gapic
91
91
  configuration[:overrides][:namespace].fetch str, str
92
92
  end
93
93
 
94
+ def fix_service_name str
95
+ str = String str
96
+ return str if configuration[:overrides].nil?
97
+ return str if configuration[:overrides][:service].nil?
98
+ configuration[:overrides][:service].fetch str, str
99
+ end
100
+
94
101
  def generate_files
95
102
  @files.select(&:generate?)
96
103
  end
@@ -202,7 +209,7 @@ module Gapic
202
209
  config = config_file ? YAML.load_file(config_file) : {}
203
210
  protoc_options.each do |k, v|
204
211
  next if k == "configuration"
205
- branch = key_to_str(k).split(".").reverse.inject(v) { |m, s| { str_to_key(s) => m } }
212
+ branch = parse_key(key_to_str(k)).reverse.inject(v) { |m, s| { str_to_key(s) => m } }
206
213
  config = deep_merge config, branch
207
214
  end
208
215
  config
@@ -225,6 +232,21 @@ module Gapic
225
232
  configuration[:generate_path_helpers_output] ||= false
226
233
  end
227
234
 
235
+ # Whether the override_proto_namespaces parameter was given in the configuration
236
+ def override_proto_namespaces_defined?
237
+ configuration.key? :override_proto_namespaces
238
+ end
239
+
240
+ # Sets the override_proto_namespaces parameter in the configuration
241
+ def override_proto_namespaces= value
242
+ configuration[:override_proto_namespaces] = value
243
+ end
244
+
245
+ # Whether namespace overrides apply to proto/grpc class references
246
+ def override_proto_namespaces?
247
+ configuration[:override_proto_namespaces] ||= false
248
+ end
249
+
228
250
  # Raw parsed json of the combined grpc service config files if provided
229
251
  # or an empty hash if no config was provided
230
252
  def grpc_service_config_raw
@@ -249,6 +271,28 @@ module Gapic
249
271
  @resource_types[resource_type]
250
272
  end
251
273
 
274
+ # Given a service, find all common services that use it as a delegate.
275
+ def common_services_for delegate
276
+ @delegate_to_common ||= begin
277
+ (configuration[:common_services] || {}).each_with_object({}) do |(c, d), mapping|
278
+ (mapping[d] ||= []) << c
279
+ end
280
+ end
281
+ all_services = services
282
+ @delegate_to_common.fetch(delegate.address.join("."), []).map do |addr|
283
+ addr = addr.split "."
284
+ all_services.find { |s| s.address == addr }
285
+ end.compact.uniq
286
+ end
287
+
288
+ # Given a common service, return its delegate.
289
+ def delegate_service_for common
290
+ addr = (configuration[:common_services] || {})[common.address.join "."]
291
+ return nil unless addr
292
+ addr = addr.split "."
293
+ services.find { |s| s.address == addr }
294
+ end
295
+
252
296
  private
253
297
 
254
298
  # Does a pre-analysis of all resources defined in the job. This has
@@ -291,6 +335,8 @@ module Gapic
291
335
  end
292
336
  end
293
337
 
338
+ # Parse a comma-delimited list of equals-delimited lists of strings, while
339
+ # mapping backslash-escaped commas and equal signs to literal characters.
294
340
  def parse_parameter str
295
341
  str.scan(/\\.|,|=|[^\\,=]+/)
296
342
  .each_with_object([[String.new]]) do |tok, arr|
@@ -307,6 +353,22 @@ module Gapic
307
353
  end
308
354
  end
309
355
 
356
+ # split the string on periods, but map backslash-escaped periods to
357
+ # literal periods.
358
+ def parse_key str
359
+ str.scan(/\.|\\.|[^\.\\]+/)
360
+ .each_with_object([String.new]) do |tok, arr|
361
+ if tok == "."
362
+ arr.append String.new
363
+ elsif tok.start_with? "\\"
364
+ arr.last << tok[1]
365
+ else
366
+ arr.last << tok
367
+ end
368
+ arr
369
+ end
370
+ end
371
+
310
372
  def str_to_key str
311
373
  str = str.to_s
312
374
  str.start_with?(":") ? str[1..-1].to_sym : str
@@ -2,3 +2,6 @@
2
2
  source "https://rubygems.org"
3
3
 
4
4
  gemspec
5
+
6
+ # google-protobuf 3.12.0 requires Ruby 2.5 or later, so pin to 3.11 on older Rubies
7
+ gem "google-protobuf", (RUBY_VERSION < "2.5" ? "~> 3.11.4" : "~> 3.12")
@@ -12,24 +12,25 @@ Gem::Specification.new do |gem|
12
12
  gem.description = <%= gem.description.inspect %>
13
13
  gem.summary = <%= gem.summary.inspect %>
14
14
  gem.homepage = <%= gem.homepage.inspect %>
15
- gem.license = "MIT"
15
+ gem.license = <%= gem.license_name.inspect %>
16
16
 
17
17
  gem.platform = Gem::Platform::RUBY
18
18
 
19
19
  gem.files = `git ls-files -- lib/*`.split("\n") +
20
20
  `git ls-files -- proto_docs/*`.split("\n") +
21
- ["README.md", "LICENSE.md", ".yardopts"]
21
+ <%= gem.extra_files.inspect %>
22
22
  gem.require_paths = ["lib"]
23
23
 
24
24
  gem.required_ruby_version = ">= 2.4"
25
25
 
26
- gem.add_dependency "gapic-common", "~> 0.2"
27
- <%- if gem.iam_dependency? -%>
28
- gem.add_dependency "grpc-google-iam-v1", ">= 0.6.10", "< 2.0"
26
+ <%- gem.dependency_list.each do |name, requirements| -%>
27
+ gem.add_dependency <%= name.inspect %>, <%= requirements.map { |v| v.inspect }.join ", " %>
29
28
  <%- end -%>
30
29
 
31
30
  gem.add_development_dependency "google-style", "~> 1.24.0"
32
- gem.add_development_dependency "minitest", "~> 5.10"
31
+ gem.add_development_dependency "minitest", "~> 5.14"
32
+ gem.add_development_dependency "minitest-focus", "~> 1.1"
33
+ gem.add_development_dependency "minitest-rg", "~> 5.2"
33
34
  gem.add_development_dependency "rake", ">= 12.0"
34
35
  gem.add_development_dependency "redcarpet", "~> 3.0"
35
36
  gem.add_development_dependency "simplecov", "~> 0.18"
@@ -10,6 +10,7 @@ RuboCop::RakeTask.new
10
10
  require "rake/testtask"
11
11
  desc "Run tests."
12
12
  Rake::TestTask.new do |t|
13
+ t.libs << "test"
13
14
  t.test_files = FileList["test/**/*_test.rb"]
14
15
  t.warning = false
15
16
  end