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
@@ -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+.