gapic-generator 0.1.7 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -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 +2 -4
  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 +170 -0
  15. data/lib/gapic/presenters/message_presenter.rb +73 -0
  16. data/lib/gapic/presenters/method_presenter.rb +298 -0
  17. data/lib/gapic/presenters/package_presenter.rb +72 -0
  18. data/lib/gapic/presenters/resource_presenter.rb +99 -0
  19. data/lib/gapic/presenters/sample_presenter.rb +84 -0
  20. data/lib/gapic/presenters/service_presenter.rb +297 -0
  21. data/lib/gapic/resource_lookup.rb +8 -1
  22. data/lib/gapic/schema/api.rb +16 -0
  23. data/lib/gapic/schema/wrappers.rb +9 -2
  24. data/templates/default/gem/readme.erb +2 -2
  25. data/templates/default/helpers/filepath_helper.rb +2 -21
  26. data/templates/default/helpers/namespace_helper.rb +2 -27
  27. data/templates/default/layouts/_ruby.erb +1 -3
  28. data/templates/default/service/client/_client.erb +7 -1
  29. metadata +16 -14
  30. data/templates/default/helpers/presenter_helper.rb +0 -24
  31. data/templates/default/helpers/presenters/field_presenter.rb +0 -146
  32. data/templates/default/helpers/presenters/file_presenter.rb +0 -53
  33. data/templates/default/helpers/presenters/gem_presenter.rb +0 -140
  34. data/templates/default/helpers/presenters/message_presenter.rb +0 -66
  35. data/templates/default/helpers/presenters/method_presenter.rb +0 -293
  36. data/templates/default/helpers/presenters/package_presenter.rb +0 -65
  37. data/templates/default/helpers/presenters/resource_presenter.rb +0 -92
  38. data/templates/default/helpers/presenters/sample_presenter.rb +0 -74
  39. data/templates/default/helpers/presenters/service_presenter.rb +0 -276
@@ -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,170 @@
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 services
41
+ @services ||= begin
42
+ files = @api.generate_files
43
+ files.map(&:services).flatten.map { |s| ServicePresenter.new @api, s }
44
+ end
45
+ end
46
+
47
+ def proto_files
48
+ @proto_files ||= begin
49
+ files = @api.files
50
+ files = files.reject { |f| blacklist_protos.include? f.name }
51
+ files = files.reject { |f| f.messages.empty? && f.enums.empty? }
52
+ files.map { |f| FilePresenter.new @api, f }
53
+ end
54
+ end
55
+
56
+ def address
57
+ name.split("-").map(&:camelize)
58
+ end
59
+
60
+ def name
61
+ gem_config :name
62
+ end
63
+
64
+ def namespace
65
+ gem_config(:namespace) ||
66
+ fix_namespace(@api, name.split("-").map(&:camelize).join("::"))
67
+ end
68
+
69
+ def title
70
+ gem_config(:title) ||
71
+ namespace.split("::").join(" ")
72
+ end
73
+
74
+ def version
75
+ gem_config(:version) ||
76
+ "0.0.1"
77
+ end
78
+
79
+ def version_require
80
+ ruby_file_path @api, version_name_full
81
+ end
82
+
83
+ def version_file_path
84
+ "#{version_require}.rb"
85
+ end
86
+
87
+ def version_name_full
88
+ "#{namespace}::VERSION"
89
+ end
90
+
91
+ def authors
92
+ gem_config(:authors) ||
93
+ ["Google LLC"]
94
+ end
95
+
96
+ def email
97
+ gem_config(:email) ||
98
+ "googleapis-packages@google.com"
99
+ end
100
+
101
+ def description
102
+ gem_config(:description) ||
103
+ "#{name} is the official client library for the #{title} API."
104
+ end
105
+
106
+ def summary
107
+ gem_config(:summary) ||
108
+ "API Client library for the #{title} API"
109
+ end
110
+
111
+ def homepage
112
+ gem_config(:homepage) ||
113
+ "https://github.com/googleapis/googleapis"
114
+ end
115
+
116
+ def env_prefix
117
+ (gem_config(:env_prefix) || name.split("-").last).upcase
118
+ end
119
+
120
+ def iam_dependency?
121
+ @api.files.map(&:name).any? { |f| f.start_with? "google/iam/v1/" }
122
+ end
123
+
124
+ def library_documentation_url
125
+ gem_config(:library_documentation_url) || "https://googleapis.dev/ruby/#{name}/latest"
126
+ end
127
+
128
+ def product_documentation_url
129
+ gem_config :product_documentation_url
130
+ end
131
+
132
+ def api_id
133
+ gem_config :api_id
134
+ end
135
+
136
+ def free_tier?
137
+ gem_config(:free_tier) ? true : false
138
+ end
139
+
140
+ def yard_strict?
141
+ gem_config(:yard_strict) ? true : false
142
+ end
143
+
144
+ def entrypoint_require
145
+ packages.first.package_require
146
+ end
147
+
148
+ private
149
+
150
+ def gem_config key
151
+ return unless @api.configuration[:gem]
152
+
153
+ @api.configuration[:gem][key]
154
+ end
155
+
156
+ def blacklist_protos
157
+ blacklist = gem_config :blacklist
158
+
159
+ return default_blacklist_protos if blacklist.nil?
160
+ return default_blacklist_protos if blacklist[:protos].nil?
161
+
162
+ default_blacklist_protos[:protos]
163
+ end
164
+
165
+ def default_blacklist_protos
166
+ ["google/api/http.proto", "google/protobuf/descriptor.proto"]
167
+ end
168
+ end
169
+ end
170
+ 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,298 @@
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
+ paged_request?(@method.input) && paged_response?(@method.output)
164
+ end
165
+
166
+ def paged_response_type
167
+ return nil unless paged_response? @method.output
168
+
169
+ repeated_field = @method.output.fields.find do |f|
170
+ f.label == Google::Protobuf::FieldDescriptorProto::Label::LABEL_REPEATED &&
171
+ f.type == Google::Protobuf::FieldDescriptorProto::Type::TYPE_MESSAGE
172
+ end
173
+ message_ruby_type repeated_field.message
174
+ end
175
+
176
+ ##
177
+ #
178
+ # @return [Array<String>] The segment key names.
179
+ #
180
+ def routing_params
181
+ segments = Gapic::PathTemplate.parse method_path
182
+ segments.select { |s| s.is_a? Gapic::PathTemplate::Segment }.map(&:name)
183
+ end
184
+
185
+ def routing_params?
186
+ routing_params.any?
187
+ end
188
+
189
+ def grpc_service_config
190
+ if @api.grpc_service_config&.service_method_level_configs&.key?(service.grpc_full_name) &&
191
+ @api.grpc_service_config.service_method_level_configs[service.grpc_full_name]&.key?(grpc_method_name)
192
+ @api.grpc_service_config.service_method_level_configs[service.grpc_full_name][grpc_method_name]
193
+ end
194
+ end
195
+
196
+ def grpc_method_name
197
+ @method.name
198
+ end
199
+
200
+ protected
201
+
202
+ def message_ruby_type message
203
+ ruby_namespace @api, message.address.join(".")
204
+ end
205
+
206
+ def doc_types_for arg
207
+ if arg.message?
208
+ "#{message_ruby_type arg.message} | Hash"
209
+ elsif arg.enum?
210
+ # TODO: handle when arg message is nil and enum is the type
211
+ message_ruby_type arg.enum
212
+ else
213
+ case arg.type
214
+ when 1, 2 then "Float"
215
+ when 3, 4, 5, 6, 7, 13, 15, 16, 17, 18 then "Integer"
216
+ when 9, 12 then "String"
217
+ when 8 then "Boolean"
218
+ else
219
+ "Object"
220
+ end
221
+ end
222
+ end
223
+
224
+ def doc_desc_for arg
225
+ return nil if arg.docs.leading_comments.empty?
226
+
227
+ arg.docs.leading_comments
228
+ end
229
+
230
+ def default_value_for arg
231
+ if arg.message?
232
+ "{}"
233
+ elsif arg.enum?
234
+ # TODO: select the first non-0 enum value
235
+ # ":ENUM"
236
+ arg.enum.values.first
237
+ else
238
+ case arg.type
239
+ when 1, 2 then "3.14"
240
+ when 3, 4, 5, 6, 7, 13, 15, 16, 17, 18 then "42"
241
+ when 9, 12 then "\"hello world\""
242
+ when 8 then "true"
243
+ else
244
+ "Object"
245
+ end
246
+ end
247
+ end
248
+
249
+ def method_path
250
+ return "" if @method.http.nil?
251
+
252
+ method = [
253
+ @method.http.get, @method.http.post, @method.http.put,
254
+ @method.http.patch, @method.http.delete
255
+ ].find { |x| !x.empty? }
256
+ return method unless method.nil?
257
+
258
+ return @method.http.custom.path unless @method.http.custom.nil?
259
+ end
260
+
261
+ def paged_request? request
262
+ page_token = request.fields.find do |f|
263
+ f.name == "page_token" && f.type == Google::Protobuf::FieldDescriptorProto::Type::TYPE_STRING
264
+ end
265
+ return false if page_token.nil?
266
+
267
+ page_size_types = [
268
+ Google::Protobuf::FieldDescriptorProto::Type::TYPE_INT32,
269
+ Google::Protobuf::FieldDescriptorProto::Type::TYPE_INT64
270
+ ]
271
+ page_size = request.fields.find do |f|
272
+ f.name == "page_size" && page_size_types.include?(f.type)
273
+ end
274
+ return false if page_size.nil?
275
+
276
+ true
277
+ end
278
+
279
+ def paged_response? response
280
+ next_page_token = response.fields.find do |f|
281
+ f.name == "next_page_token" && f.type == Google::Protobuf::FieldDescriptorProto::Type::TYPE_STRING
282
+ end
283
+ return false if next_page_token.nil?
284
+
285
+ repeated_field = response.fields.find do |f|
286
+ f.label == Google::Protobuf::FieldDescriptorProto::Label::LABEL_REPEATED &&
287
+ f.type == Google::Protobuf::FieldDescriptorProto::Type::TYPE_MESSAGE
288
+ end
289
+ return false if repeated_field.nil?
290
+
291
+ # We want to make sure the first repeated field is also has the lowest field number,
292
+ # but the google-protobuf gem sorts fields by number, so we lose the original order.
293
+
294
+ true
295
+ end
296
+ end
297
+ end
298
+ end