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
@@ -26,57 +26,42 @@ module Gapic
26
26
 
27
27
  # @private
28
28
  def lookup!
29
- resources = @api.files.flat_map { |file| lookup_file_resource_descriptors file }
30
- resources.compact.uniq
31
- end
32
-
33
- # @private
34
- def lookup_file_resource_descriptors file
35
29
  resources = []
36
- resources += file.resources.select { |resource| service_resource_types.include? resource.type }
37
- resources += file.messages.flat_map { |message| lookup_message_resources_descriptors message }
38
- resources
39
- end
40
-
41
- # @private
42
- def service_resource_types
43
- @service_resource_types ||= begin
44
- @service.methods.flat_map do |method|
45
- message_resource_types method.input
46
- end.uniq
30
+ @service.methods.each do |method|
31
+ resources.concat resources_for_message(method.input)
32
+ resources.concat resources_for_message(method.output) if @api.generate_path_helpers_output?
47
33
  end
34
+ resources.uniq
48
35
  end
49
36
 
50
37
  # @private
51
- def message_resource_types message, seen_messages = []
52
- return [] if seen_messages.include? message
38
+ def resources_for_message message, seen_messages = []
39
+ resources = []
40
+ return resources if seen_messages.include? message
53
41
  seen_messages << message
54
- resource_types = []
55
- resource_types << message.resource.type if message.resource
56
- resource_types += message.nested_messages.map do |nested_message|
57
- message_resource_types nested_message, seen_messages
42
+ resources << message.resource if message.resource
43
+ message.nested_messages.each do |nested_message|
44
+ resources.concat resources_for_message(nested_message, seen_messages)
58
45
  end
59
46
  message.fields.each do |field|
60
- resource_types << field.resource_reference.type if field.resource_reference
61
- resource_types += message_resource_types field.message, seen_messages if field.message?
47
+ resources.concat resources_for_reference(field.resource_reference) if field.resource_reference
48
+ resources.concat resources_for_message(field.message, seen_messages) if field.message?
62
49
  end
63
- resource_types.flatten
50
+ resources
64
51
  end
65
52
 
66
53
  # @private
67
- def lookup_message_resources_descriptors message
68
- resources = []
69
-
70
- # We don't expect service_resource_types to iclude nil, so we can use message.resource&.type
71
- resources << message.resource if service_resource_types.include? message.resource&.type
72
-
73
- if message.nested_messages
74
- resources += message.nested_messages.flat_map do |nested_message|
75
- lookup_message_resources_descriptors nested_message
76
- end
54
+ # Given a reference (either a type or child type), return the corresponding
55
+ # resources.
56
+ def resources_for_reference reference
57
+ if (type = reference.type) && !type.empty?
58
+ Array(@api.lookup_resource_type(type))
59
+ elsif (child_type = reference.child_type) && !child_type.empty?
60
+ child_resource = @api.lookup_resource_type child_type
61
+ child_resource ? child_resource.parent_resources : []
62
+ else
63
+ []
77
64
  end
78
-
79
- resources
80
65
  end
81
66
 
82
67
  # Lookup all resources for a given service.
@@ -51,6 +51,7 @@ module Gapic
51
51
  loader.load_file fd, request.file_to_generate.include?(fd.name)
52
52
  end
53
53
  @files.each { |f| f.parent = self }
54
+ @resource_types = analyze_resources
54
55
  end
55
56
 
56
57
  def containing_api
@@ -208,6 +209,22 @@ module Gapic
208
209
  end
209
210
  end
210
211
 
212
+ # Whether the generate_path_helpers_output parameter was given in the configuration
213
+ def generate_path_helpers_output_defined?
214
+ configuration.key? :generate_path_helpers_output
215
+ end
216
+
217
+ # Sets the generate_path_helpers_output parameter in the configuration
218
+ def generate_path_helpers_output= value
219
+ configuration[:generate_path_helpers_output] = value
220
+ end
221
+
222
+ # Whether to generate path helpers for output as well as input messages
223
+ def generate_path_helpers_output?
224
+ # if not set in configuration, false by default
225
+ configuration[:generate_path_helpers_output] ||= false
226
+ end
227
+
211
228
  # Raw parsed json of the combined grpc service config files if provided
212
229
  # or an empty hash if no config was provided
213
230
  def grpc_service_config_raw
@@ -227,8 +244,53 @@ module Gapic
227
244
  end
228
245
  end
229
246
 
247
+ # Get a resource given its type string
248
+ def lookup_resource_type resource_type
249
+ @resource_types[resource_type]
250
+ end
251
+
230
252
  private
231
253
 
254
+ # Does a pre-analysis of all resources defined in the job. This has
255
+ # two effects:
256
+ # * Side effect: each resource has its parent_resources field set.
257
+ # * A mapping from resource type to resource wrapper is returned.
258
+ def analyze_resources
259
+ # In order to set parent_resources, we first populate a mapping from
260
+ # parsed pattern to resource mapping (in the patterns variable). This
261
+ # is done in one pass along with populating the resource type mapping.
262
+ # Then, we go through all resources again, get its expected parent
263
+ # patterns, and anything that shows up in the patterns mapping is taken
264
+ # to be a parent.
265
+ types = {}
266
+ patterns = {}
267
+ @files.each do |file|
268
+ file.resources.each { |resource| populate_resource_lookups resource, types, patterns }
269
+ file.messages.each { |message| populate_message_resource_lookups message, types, patterns }
270
+ end
271
+ types.each do |_type, resource|
272
+ parents = resource.parsed_parent_patterns
273
+ .map { |pat| patterns[pat] }
274
+ .compact.uniq
275
+ resource.parent_resources.replace parents
276
+ end
277
+ types
278
+ end
279
+
280
+ def populate_resource_lookups resource, types, patterns
281
+ types[resource.type] = resource
282
+ resource.parsed_patterns.each do |pat|
283
+ patterns[pat] = resource
284
+ end
285
+ end
286
+
287
+ def populate_message_resource_lookups message, types, patterns
288
+ populate_resource_lookups message.resource, types, patterns if message.resource
289
+ message.nested_messages.each do |nested|
290
+ populate_message_resource_lookups nested, types, patterns
291
+ end
292
+ end
293
+
232
294
  def parse_parameter str
233
295
  str.scan(/\\.|,|=|[^\\,=]+/)
234
296
  .each_with_object([[String.new]]) do |tok, arr|
@@ -64,9 +64,13 @@ module Gapic
64
64
  load_service registry, s, address, docs, [6, i]
65
65
  end
66
66
 
67
+ # Load top-level resources
68
+ resource_descriptors = file_descriptor.options[:".google.api.resource_definition"] if file_descriptor.options
69
+ resources = Array(resource_descriptors).map { |descriptor| Resource.new descriptor }
70
+
67
71
  # Construct and return the file.
68
72
  File.new file_descriptor, address, docs[path], messages, enums,
69
- services, file_to_generate, registry
73
+ services, resources, file_to_generate, registry
70
74
  end
71
75
 
72
76
  # Updates the fields of a message and it's nested messages.
@@ -158,9 +162,12 @@ module Gapic
158
162
  load_field registry, e, address, docs, path + [6, i]
159
163
  end
160
164
 
165
+ resource_descriptor = descriptor.options[:".google.api.resource"] if descriptor.options
166
+ resource = resource_descriptor ? Resource.new(resource_descriptor) : nil
167
+
161
168
  # Construct, cache, and return.
162
169
  msg = Message.new(descriptor, address, docs[path], fields, extensions,
163
- nested_messages, nested_enums)
170
+ resource, nested_messages, nested_enums)
164
171
  @prior_messages << msg
165
172
  add_to_registry registry, address, msg
166
173
  end
@@ -107,14 +107,21 @@ module Gapic
107
107
  parent&.containing_file
108
108
  end
109
109
 
110
+ ##
110
111
  # Gets the cleaned up leading comments documentation
111
- def docs_leading_comments
112
+ #
113
+ # @param disable_xrefs [Boolean] (default is `false`) Disable linking to
114
+ # cross-references, and render them simply as text. This can be used if
115
+ # it is known that the targets are not present in the current library.
116
+ # @return [String]
117
+ #
118
+ def docs_leading_comments disable_xrefs: false
112
119
  return nil if @docs.nil?
113
120
  return nil if @docs.leading_comments.empty?
114
121
 
115
122
  lines = @docs.leading_comments.each_line.to_a
116
123
  lines.map! { |line| line.start_with?(" ") ? line[1..-1] : line }
117
- lines = FormattingUtils.format_doc_lines containing_api, lines
124
+ lines = FormattingUtils.format_doc_lines containing_api, lines, disable_xrefs: disable_xrefs
118
125
  lines.join
119
126
  end
120
127
 
@@ -350,16 +357,19 @@ module Gapic
350
357
  # Wrapper for a protobuf file.
351
358
  #
352
359
  # @!attribute [r] messages
353
- # @ return [Enumerable<Message>] The top level messages contained in
360
+ # @return [Enumerable<Message>] The top level messages contained in
354
361
  # this file.
355
362
  # @!attribute [r] enums
356
- # @ return [Enumerable<Enum>] The top level enums contained in this
363
+ # @return [Enumerable<Enum>] The top level enums contained in this
357
364
  # file.
358
365
  # @!attribute [r] services
359
- # @ return [Enumerable<Service>] The services contained in this file.
366
+ # @return [Enumerable<Service>] The services contained in this file.
367
+ # @!attribute [r] resources
368
+ # @return [Enumerable<Resource>] The top level resources contained in
369
+ # this file.
360
370
  class File < Proto
361
371
  extend Forwardable
362
- attr_reader :messages, :enums, :services, :registry
372
+ attr_reader :messages, :enums, :services, :resources, :registry
363
373
 
364
374
  # Initializes a message object.
365
375
  # @param descriptor [Google::Protobuf::DescriptorProto] the protobuf
@@ -372,20 +382,23 @@ module Gapic
372
382
  # file.
373
383
  # @param enums [Enumerable<Enum>] The top level enums of this file.
374
384
  # @param services [Enumerable<Service>] The services of this file.
385
+ # @param resources [Enumerable<Resource>] The resources from this file.
375
386
  # @param generate [Boolean] Whether this file should be generated.
376
387
  def initialize descriptor, address, docs, messages, enums, services,
377
- generate, registry
388
+ resources, generate, registry
378
389
  super descriptor, address, docs
379
390
  @messages = messages || []
380
391
  @enums = enums || []
381
392
  @services = services || []
393
+ @resources = resources || []
382
394
  @generate = generate
383
395
  @registry = registry
384
396
 
385
397
  # Apply parent
386
398
  @messages.each { |m| m.parent = self }
387
- @enums.each { |m| m.parent = self }
399
+ @enums.each { |m| m.parent = self }
388
400
  @services.each { |m| m.parent = self }
401
+ @resources.each { |m| m.parent = self }
389
402
  end
390
403
 
391
404
  def containing_file
@@ -406,13 +419,6 @@ module Gapic
406
419
  options[:ruby_package] if options
407
420
  end
408
421
 
409
- # @return [Array<Google::Api::ResourceDescriptor>] A representation of the resource.
410
- # This is generally intended to be attached to the "name" field.
411
- # See `google/api/resource.proto`.
412
- def resources
413
- options[:".google.api.resource_definition"] if options
414
- end
415
-
416
422
  # @!method name
417
423
  # @return [String] file name, relative to root of source tree.
418
424
  # @!method package
@@ -504,6 +510,8 @@ module Gapic
504
510
  # @ return [Enumerable<Field>] The fields of a message.
505
511
  # @!attribute [r] extensions
506
512
  # @ return [Enumerable<Field>] The extensions of a message.
513
+ # @!attribute [r] resource
514
+ # @ return [Resource,nil] A representation of the resource.
507
515
  # @!attribute [r] nested_messages
508
516
  # @ return [Enumerable<Message>] The nested message declarations of a
509
517
  # message.
@@ -511,7 +519,7 @@ module Gapic
511
519
  # @ return [Enumerable<Enum>] The nested enum declarations of a message.
512
520
  class Message < Proto
513
521
  extend Forwardable
514
- attr_reader :fields, :extensions, :nested_messages, :nested_enums
522
+ attr_reader :fields, :extensions, :resource, :nested_messages, :nested_enums
515
523
 
516
524
  # Initializes a message object.
517
525
  # @param descriptor [Google::Protobuf::DescriptorProto] the protobuf
@@ -522,15 +530,17 @@ module Gapic
522
530
  # of the proto. See #docs for more info.
523
531
  # @param fields [Enumerable<Field>] The fields of this message.
524
532
  # @param extensions [Enumerable<Field>] The extensions of this message.
533
+ # @param resource [Resource,nil] The resource of this message, or nil if none.
525
534
  # @param nested_messages [Enumerable<Message>] The nested message
526
535
  # declarations of this message.
527
536
  # @param nested_enums [Enumerable<Enum>] The nested enum declarations
528
537
  # of this message.
529
- def initialize descriptor, address, docs, fields, extensions,
538
+ def initialize descriptor, address, docs, fields, extensions, resource,
530
539
  nested_messages, nested_enums
531
540
  super descriptor, address, docs
532
541
  @fields = fields || []
533
542
  @extensions = extensions || []
543
+ @resource = resource
534
544
  @nested_messages = nested_messages || []
535
545
  @nested_enums = nested_enums || []
536
546
 
@@ -538,13 +548,7 @@ module Gapic
538
548
  @extensions.each { |x| x.parent = self }
539
549
  @nested_messages.each { |m| m.parent = self }
540
550
  @nested_enums.each { |e| e.parent = self }
541
- end
542
-
543
- # @return [Google::Api::ResourceDescriptor] A representation of the resource.
544
- # This is generally intended to be attached to the "name" field.
545
- # See `google/api/resource.proto`.
546
- def resource
547
- options[:".google.api.resource"] if options
551
+ @resource.parent = self if @resource
548
552
  end
549
553
 
550
554
  # @return [Boolean] whether this type is a map entry
@@ -729,5 +733,95 @@ module Gapic
729
733
  :options
730
734
  )
731
735
  end
736
+
737
+ # Wrapper for a protobuf Resource.
738
+ #
739
+ # Unlike most wrappers, this does not subclass the {Proto} wrapper because
740
+ # it does not use the fields exposed by that wrapper (`address`, `docs`,
741
+ # etc.) This is here principally to augment the resource definition with
742
+ # information about resource parent-child relationships.
743
+ #
744
+ # Resource parentage is defined implicitly by path patterns. The algorithm
745
+ # is as follows:
746
+ # * If the final segment of a pattern is an ID segment (i.e. `*` or some
747
+ # `{name}`) then remove it and the previous segment (which we assume to
748
+ # be the corresponding collection identifier, as described in AIP-122.)
749
+ # The resulting pattern is what we expect a parent to have.
750
+ # * If the final segment is static, then assume the pattern represents a
751
+ # singleton resource (AIP-156) and remove only that one segment. The
752
+ # resulting pattern is what we expect a parent to have.
753
+ #
754
+ # The {Resource#parsed_parent_patterns} method returns the set of patterns
755
+ # we expect of parents. It is then possible to search for resources with
756
+ # those patterns to determine what the parents are.
757
+ #
758
+ # @!attribute [rw] parent
759
+ # @return [Gapic::Schema::File,Gapic::Schema::Message] The parent object.
760
+ # @!attribute [r] descriptor
761
+ # @return [Array<Gapic::Schema::ResourceDescriptor>] The resource
762
+ # descriptor.
763
+ # @!attribute [r] parsed_patterns
764
+ # @return [Array<Array<String>>] The normalized, segmented forms of the
765
+ # patterns. Normalized means all ID segments are replaced by asterisks
766
+ # to remove non-structural differences due to different names being
767
+ # used. Segmented means simply split on slashes.
768
+ # For example, if a pattern is `"projects/{project}""`, the
769
+ # corresponding parsed pattern would be `["projects", "*"]`.
770
+ # @!attribute [r] parent_resources
771
+ # @return [Array<Gapic::Schema::Resource>] Parent resources
772
+ class Resource
773
+ extend Forwardable
774
+ attr_reader :descriptor, :parsed_patterns, :parent_resources
775
+ attr_accessor :parent
776
+
777
+ # Initializes a resource object.
778
+ # @param descriptor [Google::Protobuf::ResourceDescriptor] the protobuf
779
+ # representation of this resource.
780
+ def initialize descriptor
781
+ @parent = nil
782
+ @descriptor = descriptor
783
+ @parsed_patterns = descriptor.pattern.map do |pattern|
784
+ pattern.split("/").map do |segment|
785
+ segment =~ %r{\{[^/\}]+(=[^\}]+)?\}} ? "*" : segment
786
+ end.freeze
787
+ end.freeze
788
+ @parent_resources = []
789
+ end
790
+
791
+ # Returns the "root" of this schema.
792
+ # @return [Gapic::Schema::Api]
793
+ def containing_api
794
+ parent&.containing_api
795
+ end
796
+
797
+ # Returns the file containing this proto entity
798
+ # @return [Gapic::Schema::File]
799
+ def containing_file
800
+ parent&.containing_file
801
+ end
802
+
803
+ # Returns parsed patterns for the expected parents.
804
+ # @return [Array<Array<String>>]
805
+ def parsed_parent_patterns
806
+ @parsed_patterns.map do |pat|
807
+ parent = pat.last =~ /^\*\*?$/ ? pat[0...-2] : pat[0...-1]
808
+ parent.empty? ? nil : parent
809
+ end.compact.uniq
810
+ end
811
+
812
+ # @!method type
813
+ # @return [String] the resource type string.
814
+ # @!method pattern
815
+ # @return [Array<String>] the set of patterns.
816
+ # @!method name_field
817
+ # @return [String] the field on the resource that designates the
818
+ # resource name field. If omitted, this is assumed to be "name".
819
+ def_delegators(
820
+ :descriptor,
821
+ :type,
822
+ :pattern,
823
+ :name_field
824
+ )
825
+ end
732
826
  end
733
827
  end
@@ -0,0 +1,8 @@
1
+ <%- assert_locals gem -%>
2
+ <%= render partial: "shared/header" -%>
3
+
4
+ # This gem does not autoload during Bundler.require. To load this gem,
5
+ # issue explicit require statements for the packages desired, e.g.:
6
+ <%- gem.packages.each do |package| -%>
7
+ # require "<%= package.package_require %>"
8
+ <%- end -%>
@@ -25,7 +25,7 @@ Gem::Specification.new do |gem|
25
25
 
26
26
  gem.add_dependency "gapic-common", "~> 0.2"
27
27
  <%- if gem.iam_dependency? -%>
28
- gem.add_dependency "grpc-google-iam-v1", "~> 0.6.9"
28
+ gem.add_dependency "grpc-google-iam-v1", ">= 0.6.10", "< 2.0"
29
29
  <%- end -%>
30
30
 
31
31
  gem.add_development_dependency "google-style", "~> 1.24.0"
@@ -1,9 +1,9 @@
1
- # <%= gem.title %>
2
-
3
- <%= gem.description %>
1
+ # Ruby Client for the <%= gem.title %> API
4
2
 
5
3
  <%= gem.summary %>
6
4
 
5
+ <%= gem.description %>
6
+
7
7
  <%= gem.homepage %>
8
8
 
9
9
  ## Installation
@@ -12,6 +12,20 @@
12
12
  $ gem install <%= gem.name %>
13
13
  ```
14
14
 
15
+ ## Quick Start
16
+
17
+ ```ruby
18
+ require "<%= gem.entrypoint_require %>"
19
+ <%- service = gem.packages.first&.services.first -%>
20
+ <%- method = service&.methods.first -%>
21
+ <%- if service && method -%>
22
+
23
+ client = <%= service.create_client_call %>
24
+ request = my_create_request
25
+ response = client.<%= method.name %> request
26
+ <%- end -%>
27
+ ```
28
+
15
29
  ## Supported Ruby Versions
16
30
 
17
31
  This library is supported on Ruby 2.4+.