gapic-generator 0.1.7 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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