gapic-generator 0.1.7 → 0.3.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -0
  3. data/lib/gapic/formatting_utils.rb +9 -4
  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 +13 -14
  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 +176 -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 +80 -0
  18. data/lib/gapic/presenters/resource_presenter.rb +93 -0
  19. data/lib/gapic/presenters/sample_presenter.rb +84 -0
  20. data/lib/gapic/presenters/service_presenter.rb +306 -0
  21. data/lib/gapic/resource_lookup.rb +23 -38
  22. data/lib/gapic/schema/api.rb +62 -0
  23. data/lib/gapic/schema/loader.rb +9 -2
  24. data/lib/gapic/schema/wrappers.rb +118 -24
  25. data/templates/default/gem/entrypoint.erb +8 -0
  26. data/templates/default/gem/gemspec.erb +1 -1
  27. data/templates/default/gem/readme.erb +17 -3
  28. data/templates/default/gem/rubocop.erb +13 -41
  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/lib/_package.erb +17 -0
  33. data/templates/default/lib/_service.erb +32 -0
  34. data/templates/default/package.erb +5 -5
  35. data/templates/default/service.erb +5 -7
  36. data/templates/default/service/_helpers.erb +3 -0
  37. data/templates/default/service/client/_client.erb +7 -17
  38. data/templates/default/service/client/_operations.erb +0 -4
  39. data/templates/default/service/client/_resource.erb +1 -1
  40. data/templates/default/service/client/method/docs/_request_normal.erb +10 -5
  41. data/templates/default/service/client/method/docs/_request_streaming.erb +1 -1
  42. metadata +20 -15
  43. data/templates/default/helpers/presenter_helper.rb +0 -24
  44. data/templates/default/helpers/presenters/field_presenter.rb +0 -146
  45. data/templates/default/helpers/presenters/file_presenter.rb +0 -53
  46. data/templates/default/helpers/presenters/gem_presenter.rb +0 -140
  47. data/templates/default/helpers/presenters/message_presenter.rb +0 -66
  48. data/templates/default/helpers/presenters/method_presenter.rb +0 -293
  49. data/templates/default/helpers/presenters/package_presenter.rb +0 -65
  50. data/templates/default/helpers/presenters/resource_presenter.rb +0 -92
  51. data/templates/default/helpers/presenters/sample_presenter.rb +0 -74
  52. data/templates/default/helpers/presenters/service_presenter.rb +0 -276
  53. data/templates/default/service/client/_helpers.erb +0 -9
@@ -0,0 +1,59 @@
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 "gapic/helpers/namespace_helper"
18
+
19
+ module Gapic
20
+ module Presenters
21
+ ##
22
+ # A presenter for proto files.
23
+ #
24
+ class FilePresenter
25
+ include Gapic::Helpers::NamespaceHelper
26
+
27
+ # @param file [Gapic::Schema::File] the file to present
28
+ def initialize api, file
29
+ @api = api
30
+ @file = file
31
+ end
32
+
33
+ def name
34
+ @file.name
35
+ end
36
+
37
+ def address
38
+ @file.address
39
+ end
40
+
41
+ def namespace
42
+ return @file.ruby_package if @file.ruby_package.present?
43
+ ruby_namespace_for_address address
44
+ end
45
+
46
+ def messages
47
+ @messages ||= @file.messages.map { |m| MessagePresenter.new @api, m }
48
+ end
49
+
50
+ def enums
51
+ @enums ||= @file.enums.map { |e| EnumPresenter.new e }
52
+ end
53
+
54
+ def docs_file_path
55
+ @file.name.gsub ".proto", ".rb"
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,176 @@
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/helpers/filepath_helper"
18
+ require "gapic/helpers/namespace_helper"
19
+
20
+ module Gapic
21
+ module Presenters
22
+ ##
23
+ # A presenter for gems.
24
+ #
25
+ class GemPresenter
26
+ include Gapic::Helpers::FilepathHelper
27
+ include Gapic::Helpers::NamespaceHelper
28
+
29
+ def initialize api
30
+ @api = api
31
+ end
32
+
33
+ def packages
34
+ @packages ||= begin
35
+ packages = @api.generate_files.map(&:package).uniq.sort
36
+ packages.map { |p| PackagePresenter.new @api, p }.delete_if(&:empty?)
37
+ end
38
+ end
39
+
40
+ def packages?
41
+ !packages.empty?
42
+ end
43
+
44
+ def services
45
+ @services ||= begin
46
+ files = @api.generate_files
47
+ files.map(&:services).flatten.map { |s| ServicePresenter.new @api, s }
48
+ end
49
+ end
50
+
51
+ def proto_files
52
+ @proto_files ||= begin
53
+ files = @api.files
54
+ files = files.reject { |f| blacklist_protos.include? f.name }
55
+ files = files.reject { |f| f.messages.empty? && f.enums.empty? }
56
+ files.map { |f| FilePresenter.new @api, f }
57
+ end
58
+ end
59
+
60
+ def address
61
+ name.split("-").map(&:camelize)
62
+ end
63
+
64
+ def name
65
+ gem_config :name
66
+ end
67
+
68
+ def namespace
69
+ gem_config(:namespace) ||
70
+ fix_namespace(@api, name.split("-").map(&:camelize).join("::"))
71
+ end
72
+
73
+ def title
74
+ gem_config(:title) ||
75
+ namespace.split("::").join(" ")
76
+ end
77
+
78
+ def version
79
+ gem_config(:version) ||
80
+ "0.0.1"
81
+ end
82
+
83
+ def version_require
84
+ ruby_file_path @api, version_name_full
85
+ end
86
+
87
+ def version_file_path
88
+ "#{version_require}.rb"
89
+ end
90
+
91
+ def version_name_full
92
+ "#{namespace}::VERSION"
93
+ end
94
+
95
+ def authors
96
+ gem_config(:authors) ||
97
+ ["Google LLC"]
98
+ end
99
+
100
+ def email
101
+ gem_config(:email) ||
102
+ "googleapis-packages@google.com"
103
+ end
104
+
105
+ def description
106
+ gem_config(:description) ||
107
+ "#{name} is the official client library for the #{title} API."
108
+ end
109
+
110
+ def summary
111
+ gem_config(:summary) ||
112
+ "API Client library for the #{title} API"
113
+ end
114
+
115
+ def homepage
116
+ gem_config(:homepage) ||
117
+ "https://github.com/googleapis/googleapis"
118
+ end
119
+
120
+ def env_prefix
121
+ (gem_config(:env_prefix) || name.split("-").last).upcase
122
+ end
123
+
124
+ def iam_dependency?
125
+ @api.files.map(&:name).any? { |f| f.start_with? "google/iam/v1/" }
126
+ end
127
+
128
+ def library_documentation_url
129
+ gem_config(:library_documentation_url) || "https://googleapis.dev/ruby/#{name}/latest"
130
+ end
131
+
132
+ def product_documentation_url
133
+ gem_config :product_documentation_url
134
+ end
135
+
136
+ def api_id
137
+ gem_config :api_id
138
+ end
139
+
140
+ def free_tier?
141
+ # Default to false unless the config is explicitly set to "true"
142
+ gem_config(:free_tier) == "true"
143
+ end
144
+
145
+ def yard_strict?
146
+ # Default to true unless the config is explicitly set to "false"
147
+ gem_config(:yard_strict) != "false"
148
+ end
149
+
150
+ def entrypoint_require
151
+ packages.first.package_require
152
+ end
153
+
154
+ private
155
+
156
+ def gem_config key
157
+ return unless @api.configuration[:gem]
158
+
159
+ @api.configuration[:gem][key]
160
+ end
161
+
162
+ def blacklist_protos
163
+ blacklist = gem_config :blacklist
164
+
165
+ return default_blacklist_protos if blacklist.nil?
166
+ return default_blacklist_protos if blacklist[:protos].nil?
167
+
168
+ default_blacklist_protos[:protos]
169
+ end
170
+
171
+ def default_blacklist_protos
172
+ ["google/api/http.proto", "google/protobuf/descriptor.proto"]
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,73 @@
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
+
19
+ require "gapic/helpers/namespace_helper"
20
+
21
+ module Gapic
22
+ module Presenters
23
+ ##
24
+ # A presenter for proto messages.
25
+ #
26
+ class MessagePresenter
27
+ include Gapic::Helpers::NamespaceHelper
28
+
29
+ def initialize api, message
30
+ @api = api
31
+ @message = message
32
+ end
33
+
34
+ def name
35
+ @message.name
36
+ end
37
+
38
+ def doc_types
39
+ type_name_full
40
+ end
41
+
42
+ def doc_description
43
+ @message.docs_leading_comments
44
+ end
45
+
46
+ def default_value
47
+ "{}"
48
+ end
49
+
50
+ def type_name_full
51
+ message_ruby_type @message
52
+ end
53
+
54
+ def fields
55
+ @fields = @message.fields.map { |f| FieldPresenter.new @api, @message, f }
56
+ end
57
+
58
+ def nested_enums
59
+ @nested_enums ||= @message.nested_enums.map { |e| EnumPresenter.new e }
60
+ end
61
+
62
+ def nested_messages
63
+ @nested_messages ||= @message.nested_messages.map { |m| MessagePresenter.new @api, m }
64
+ end
65
+
66
+ protected
67
+
68
+ def message_ruby_type message
69
+ ruby_namespace @api, message.address.join(".")
70
+ end
71
+ end
72
+ end
73
+ end
@@ -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