gapic-generator 0.3.1 → 0.5.1

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +35 -0
  3. data/lib/gapic/formatting_utils.rb +9 -7
  4. data/lib/gapic/generator/version.rb +1 -1
  5. data/lib/gapic/generators/default_generator.rb +13 -11
  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/method_presenter.rb +23 -17
  12. data/lib/gapic/presenters/package_presenter.rb +8 -1
  13. data/lib/gapic/presenters/resource_presenter.rb +55 -35
  14. data/lib/gapic/presenters/service_presenter.rb +56 -19
  15. data/lib/gapic/ruby_info.rb +93 -0
  16. data/lib/gapic/schema/api.rb +63 -1
  17. data/templates/default/gem/gemfile.erb +3 -0
  18. data/templates/default/gem/gemspec.erb +3 -1
  19. data/templates/default/gem/rakefile.erb +1 -0
  20. data/templates/default/gem/test_helper.erb +8 -0
  21. data/templates/default/layouts/_ruby.erb +5 -4
  22. data/templates/default/proto_docs/_message.erb +2 -2
  23. data/templates/default/service/client.erb +1 -1
  24. data/templates/default/service/client/_client.erb +15 -4
  25. data/templates/default/service/client/_config.erb +32 -28
  26. data/templates/default/service/client/_credentials.erb +1 -1
  27. data/templates/default/service/client/_operations.erb +3 -1
  28. data/templates/default/service/client/method/def/_options_defaults.erb +2 -2
  29. data/templates/default/service/client/method/def/_request_normal.erb +2 -2
  30. data/templates/default/service/client/method/def/_request_streaming.erb +3 -3
  31. data/templates/default/service/client/method/def/_response_normal.erb +1 -1
  32. data/templates/default/service/client/method/def/_response_paged.erb +2 -2
  33. data/templates/default/service/client/method/docs/_error.erb +1 -1
  34. data/templates/default/service/client/method/docs/_request_normal.erb +2 -2
  35. data/templates/default/service/client/method/docs/_request_streaming.erb +2 -2
  36. data/templates/default/service/client/method/docs/_response.erb +1 -1
  37. data/templates/default/service/client/resource/_def.erb +1 -1
  38. data/templates/default/service/client/resource/_multi.erb +4 -7
  39. data/templates/default/service/client/resource/_single.erb +2 -3
  40. data/templates/default/service/credentials.erb +1 -1
  41. data/templates/default/service/operations.erb +1 -1
  42. data/templates/default/service/paths.erb +1 -1
  43. data/templates/default/service/test/_resource.erb +16 -0
  44. data/templates/default/service/test/client.erb +17 -4
  45. data/templates/default/service/test/client_operations.erb +3 -4
  46. data/templates/default/service/test/client_paths.erb +17 -0
  47. data/templates/default/service/test/method/_configure.erb +19 -0
  48. metadata +8 -3
@@ -55,8 +55,26 @@ module Gapic
55
55
  @service.address
56
56
  end
57
57
 
58
+ # Returns a presenter for this service's delegate (if it is a common service)
59
+ # otherwise returns `nil`.
60
+ def common_service_delegate
61
+ unless defined? @common_service_delegate
62
+ delegate = @api.delegate_service_for @service
63
+ @common_service_delegate = delegate ? ServicePresenter.new(@api, delegate) : nil
64
+ end
65
+ @common_service_delegate
66
+ end
67
+
68
+ # The namespace of the client. Normally this is the version module. This
69
+ # may be different from the proto namespace for a common service.
58
70
  def namespace
59
- return @service.ruby_package if @service.ruby_package.present?
71
+ # If this service is a common service, its client should go into its
72
+ # delegate's namespace rather than its own. For example, KMS includes
73
+ # the common IAMPolicy service, but that service's client should go
74
+ # into the KMS namespace.
75
+ return common_service_delegate.namespace if common_service_delegate
76
+
77
+ return ensure_absolute_namespace @service.ruby_package if @service.ruby_package.present?
60
78
 
61
79
  namespace = ruby_namespace_for_address @service.address[0...-1]
62
80
  fix_namespace @api, namespace
@@ -71,15 +89,25 @@ module Gapic
71
89
  end
72
90
 
73
91
  def name
74
- @service.name
92
+ @api.fix_service_name @service.name
93
+ end
94
+
95
+ # The namespace of the protos. This may be different from the client
96
+ # namespace for a common service.
97
+ def proto_namespace
98
+ return ensure_absolute_namespace @service.ruby_package if @service.ruby_package.present?
99
+
100
+ namespace = ruby_namespace_for_address @service.address[0...-1]
101
+ @api.override_proto_namespaces? ? fix_namespace(@api, namespace) : namespace
75
102
  end
76
103
 
77
104
  def proto_service_name_full
78
- fix_namespace @api, "#{namespace}::#{name}"
105
+ name_full = "#{proto_namespace}::#{@service.name}"
106
+ @api.override_proto_namespaces? ? fix_namespace(@api, name_full) : name_full
79
107
  end
80
108
 
81
109
  def module_name
82
- proto_service_name_full.split("::").last
110
+ service_name_full.split("::").last
83
111
  end
84
112
 
85
113
  def proto_service_file_path
@@ -110,6 +138,10 @@ module Gapic
110
138
  "#{proto_service_name_full}::Stub"
111
139
  end
112
140
 
141
+ def service_name_full
142
+ fix_namespace @api, "#{namespace}::#{name}"
143
+ end
144
+
113
145
  def service_file_path
114
146
  service_require + ".rb"
115
147
  end
@@ -123,7 +155,7 @@ module Gapic
123
155
  end
124
156
 
125
157
  def service_require
126
- ruby_file_path @api, proto_service_name_full
158
+ ruby_file_path @api, service_name_full
127
159
  end
128
160
 
129
161
  def client_name
@@ -131,7 +163,7 @@ module Gapic
131
163
  end
132
164
 
133
165
  def client_name_full
134
- fix_namespace @api, "#{proto_service_name_full}::#{client_name}"
166
+ fix_namespace @api, "#{service_name_full}::#{client_name}"
135
167
  end
136
168
 
137
169
  def create_client_call
@@ -155,16 +187,17 @@ module Gapic
155
187
  end
156
188
 
157
189
  def client_endpoint
158
- return @parent_service.client_endpoint if @parent_service
159
- @service.host || default_config(:default_host) || "localhost"
190
+ @parent_service&.client_endpoint ||
191
+ common_service_delegate&.client_endpoint ||
192
+ @service.host ||
193
+ default_config(:default_host) ||
194
+ "localhost"
160
195
  end
161
196
 
162
197
  def client_scopes
163
- @service.scopes || default_config(:oauth_scopes)
164
- end
165
-
166
- def client_proto_name
167
- @service.address.join "."
198
+ common_service_delegate&.client_scopes ||
199
+ @service.scopes ||
200
+ default_config(:oauth_scopes)
168
201
  end
169
202
 
170
203
  def credentials_name
@@ -172,7 +205,7 @@ module Gapic
172
205
  end
173
206
 
174
207
  def credentials_name_full
175
- fix_namespace @api, "#{proto_service_name_full}::#{credentials_name}"
208
+ fix_namespace @api, "#{service_name_full}::#{credentials_name}"
176
209
  end
177
210
 
178
211
  def credentials_class_xref
@@ -200,7 +233,7 @@ module Gapic
200
233
  end
201
234
 
202
235
  def helpers_require
203
- ruby_file_path @api, "#{proto_service_name_full}::Helpers"
236
+ ruby_file_path @api, "#{service_name_full}::Helpers"
204
237
  end
205
238
 
206
239
  def references
@@ -216,7 +249,7 @@ module Gapic
216
249
  end
217
250
 
218
251
  def paths_name_full
219
- fix_namespace @api, "#{proto_service_name_full}::#{paths_name}"
252
+ fix_namespace @api, "#{service_name_full}::#{paths_name}"
220
253
  end
221
254
 
222
255
  def paths_file_path
@@ -228,13 +261,17 @@ module Gapic
228
261
  end
229
262
 
230
263
  def paths_require
231
- ruby_file_path @api, "#{proto_service_name_full}::#{paths_name}"
264
+ ruby_file_path @api, "#{service_name_full}::#{paths_name}"
232
265
  end
233
266
 
234
267
  def test_client_file_path
235
268
  service_file_path.sub ".rb", "_test.rb"
236
269
  end
237
270
 
271
+ def test_paths_file_path
272
+ service_file_path.sub ".rb", "_paths_test.rb"
273
+ end
274
+
238
275
  def test_client_operations_file_path
239
276
  service_file_path.sub ".rb", "_operations_test.rb"
240
277
  end
@@ -260,7 +297,7 @@ module Gapic
260
297
  end
261
298
 
262
299
  def operations_name_full
263
- fix_namespace @api, "#{proto_service_name_full}::#{operations_name}"
300
+ fix_namespace @api, "#{service_name_full}::#{operations_name}"
264
301
  end
265
302
 
266
303
  def operations_file_path
@@ -272,7 +309,7 @@ module Gapic
272
309
  end
273
310
 
274
311
  def operations_require
275
- ruby_file_path @api, "#{proto_service_name_full}::#{operations_name}"
312
+ ruby_file_path @api, "#{service_name_full}::#{operations_name}"
276
313
  end
277
314
 
278
315
  def lro_service
@@ -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")
@@ -29,7 +29,9 @@ Gem::Specification.new do |gem|
29
29
  <%- end -%>
30
30
 
31
31
  gem.add_development_dependency "google-style", "~> 1.24.0"
32
- gem.add_development_dependency "minitest", "~> 5.10"
32
+ gem.add_development_dependency "minitest", "~> 5.14"
33
+ gem.add_development_dependency "minitest-focus", "~> 1.1"
34
+ gem.add_development_dependency "minitest-rg", "~> 5.2"
33
35
  gem.add_development_dependency "rake", ">= 12.0"
34
36
  gem.add_development_dependency "redcarpet", "~> 3.0"
35
37
  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
@@ -0,0 +1,8 @@
1
+ <%- assert_locals gem -%>
2
+ <%= render partial: "shared/header" -%>
3
+
4
+ require "simplecov"
5
+
6
+ require "minitest/autorun"
7
+ require "minitest/focus"
8
+ require "minitest/rg"
@@ -5,12 +5,13 @@
5
5
  <%= @requires -%>
6
6
  <%- end -%>
7
7
 
8
- <%- namespace.split("::").each_with_index do |ns, i| -%>
8
+ <%- namespace_components = namespace.split("::").reject(&:empty?) -%>
9
+ <%- namespace_components.each_with_index do |ns, i| -%>
9
10
  <%= indent "module #{ns}", i*2 %>
10
11
  <%- end -%>
11
- <%= indent yield, namespace.split("::").count*2 %>
12
- <%- namespace.split("::").count.times do |i| -%>
13
- <%= indent "end", (namespace.split("::").count-1-i)*2 %>
12
+ <%= indent yield, namespace_components.count*2 %>
13
+ <%- namespace_components.count.times do |i| -%>
14
+ <%= indent "end", (namespace_components.count-1-i)*2 %>
14
15
  <%- end -%>
15
16
  <%- if instance_variable_defined? :@footer -%>
16
17
 
@@ -10,8 +10,8 @@
10
10
  <%- end -%>
11
11
  <%- end -%>
12
12
  class <%= message.name %>
13
- include Google::Protobuf::MessageExts
14
- extend Google::Protobuf::MessageExts::ClassMethods
13
+ include ::Google::Protobuf::MessageExts
14
+ extend ::Google::Protobuf::MessageExts::ClassMethods
15
15
  <%- message.nested_messages.each do |submsg| -%>
16
16
 
17
17
  <%= indent_tail render(partial: "proto_docs/message", locals: { message: submsg }), 2 %>
@@ -2,5 +2,5 @@
2
2
  <%= render partial: "service/client/client",
3
3
  layout: "layouts/ruby",
4
4
  locals: { service: service,
5
- namespace: service.proto_service_name_full }
5
+ namespace: service.service_name_full }
6
6
  %>
@@ -29,7 +29,7 @@ class <%= service.client_name %>
29
29
  # To modify the configuration for all <%= service.name %> clients:
30
30
  #
31
31
  # <%= service.client_name_full %>.configure do |config|
32
- # config.timeout = 10_000
32
+ # config.timeout = 10.0
33
33
  # end
34
34
  #
35
35
  # @yield [config] Configure the <%= service.client_name %> client.
@@ -75,7 +75,7 @@ class <%= service.client_name %>
75
75
  # configuration:
76
76
  #
77
77
  # client = <%= service.client_name_full %>.new do |config|
78
- # config.timeout = 10_000
78
+ # config.timeout = 10.0
79
79
  # end
80
80
  #
81
81
  # @yield [config] Configure the <%= service.name %> client.
@@ -100,15 +100,17 @@ class <%= service.client_name %>
100
100
  if credentials.is_a?(String) || credentials.is_a?(Hash)
101
101
  credentials = Credentials.new credentials, scope: @config.scope
102
102
  end
103
- @quota_project_id = credentials.respond_to?(:quota_project_id) ? credentials.quota_project_id : nil
103
+ @quota_project_id = @config.quota_project
104
+ @quota_project_id ||= credentials.quota_project_id if credentials.respond_to? :quota_project_id
104
105
 
105
106
  <%- if service.lro? -%>
106
107
  <%= service.lro_client_ivar %> = <%= service.operations_name %>.new do |config|
107
108
  config.credentials = credentials
109
+ config.endpoint = @config.endpoint
108
110
  end
109
111
 
110
112
  <%- end -%>
111
- @<%= service.stub_name %> = Gapic::ServiceStub.new(
113
+ @<%= service.stub_name %> = ::Gapic::ServiceStub.new(
112
114
  <%= service.proto_service_stub_name_full %>,
113
115
  credentials: credentials,
114
116
  endpoint: @config.endpoint,
@@ -117,6 +119,15 @@ class <%= service.client_name %>
117
119
  )
118
120
  end
119
121
 
122
+ <%- if service.lro? -%>
123
+ ##
124
+ # Get the associated client for long-running operations.
125
+ #
126
+ # @return [<%= service.operations_name_full %>]
127
+ #
128
+ attr_reader :<%= service.lro_client_var %>
129
+
130
+ <%- end -%>
120
131
  # Service calls
121
132
  <%- service.methods.each do |method| -%>
122
133