protobuf_transpiler 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 55572283d38aaaf17ae92233d0a4e276f1f4fa969ecea798d85c838b46070605
4
- data.tar.gz: a1b7299db9e0ac59d5c818b729e5515400a9f0127f18bf99cb074685d8f7fb60
3
+ metadata.gz: c4d91bcc62be9eb73107bf462765f913081d60f8795d3b2aa3833aa46c5e7c6d
4
+ data.tar.gz: 4ab88cacd593ded7f0a9280ab300531a2ca3b3f6e2a6e9d19eeff34bbdff7f50
5
5
  SHA512:
6
- metadata.gz: c157a107eada279ba863e049248cfb38a8d573cb11c97fe7a92b8cf9af245f04338433845021381b9e5d2c51d880621bc82bf32a8e371a59ca0f2d4b71b19ae8
7
- data.tar.gz: e9240d2f92d78141d79e993ca8fda889540a7fa14d7c72fd8556d25e35e6aebba092ac80cac9768a53989579b0d83f2f8241e9de0d7fb1a11b2b19801434b5e1
6
+ metadata.gz: 01a17468881fbe21a0632ef79846a01a7350f37c1ef2464909f9ff3fbe462c28067d4bfe29ff18eec18aa45b932288a694a02815141e2199b1f77c3087b00bd9
7
+ data.tar.gz: b429fc9270fe9a2682b514298a73d9cf2c1541ff406c18cf839c703bec91ecd04821e3c5fc016ee3f54213d6fe2c9ec17debce6c5894b7a4082aa038a94a8380
data/CHANGELOG.md CHANGED
@@ -8,6 +8,16 @@
8
8
  ### Bug fixes
9
9
  )-->
10
10
 
11
+ ## 1.1.0 2023-08-21
12
+ ### New features
13
+ - Add annotation support for:
14
+ - streams
15
+ - oneofs
16
+ - maps
17
+ - nested messages
18
+ ### Bug fixes
19
+ - Annotate task now correctly replaces existing annotations
20
+
11
21
  ## 1.0.0 2023-07-24
12
22
 
13
23
  First release. Refer to [README.md](README.md) for the full documentation.
data/README.md CHANGED
@@ -37,12 +37,12 @@ Finally, following the stubs generation, the task also creates a ruby file for a
37
37
  For example if you have a gem defining proto files with this structure:
38
38
  ```
39
39
  public
40
- ├── mod1
41
- │ └── sample1.proto
42
- ├── mod2
43
- │ └── sample2.proto
40
+ ├── mod1
41
+ │ └── sample1.proto
42
+ ├── mod2
43
+ │ └── sample2.proto
44
44
  ```
45
- you will get the follwing structure nested in `app/stubs`
45
+ you will get the following structure nested in `app/stubs`:
46
46
  ```
47
47
  app/stubs
48
48
  ├── mod1
@@ -63,15 +63,26 @@ rake grpc_stubs:annotate
63
63
  ```
64
64
  As stated in [generate](#generate) this task is executed automatically unless you opt out after the generation step. Leveraging reflection, Messages and Services are inspected and a comment summary is prepended in the corresponding stub file.
65
65
 
66
+ The annotations of messages follow these conventions:
67
+ - each message is reported with its fully qualified name
68
+ - fields are indented in the lines following the message name and are reported as `name: type`
69
+ - `repeated` fields are annotated with their type enclosed in brackets (`[type]`)
70
+ - `map` fields are annotated with angular brackets: `Map<key_type, value_type>`
71
+ - `oneof` fields are annotated with their wrapper name, then each possible variant placed on a new line, further indented and prepended with `| `.
72
+
66
73
  Here's an example of annotations of some messages:
67
74
  ```
68
75
  # ===== Protobuf Annotation =====
69
76
  # Test::GetJobReq
70
77
  # id: uint64
78
+ # some_oneof_wrapper:
79
+ # | alternative: string
80
+ # | another: uint64
71
81
  # Test::GetJobResp
72
82
  # id: uint64
73
83
  # name: string
74
84
  # surname: string
85
+ # notes: [string]
75
86
  # ===== Protobuf Annotation =====
76
87
  ```
77
88
  and some rpcs:
@@ -84,6 +95,7 @@ and some rpcs:
84
95
  # ===== Protobuf Annotation =====
85
96
  ```
86
97
 
98
+
87
99
  ## Future extensions
88
100
  - Support nested messages definition
89
101
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ProtobufTranspiler
4
- VERSION = '1.0.0'
4
+ VERSION = '1.1.0'
5
5
  end
@@ -12,7 +12,7 @@ module ProtobufTranspiler
12
12
  proto_paths = proto_files
13
13
  .split.map { |p| p.sub %r{(?<=public).*}, '' }
14
14
  .uniq.join ' '
15
- out_path = "#{Rails.root}/app/stubs/"
15
+ out_path = "#{Rails.root}/app/stubs/"
16
16
  FileUtils.mkdir_p out_path
17
17
  `grpc_tools_ruby_protoc --ruby_out=#{out_path} --grpc_out=#{out_path} #{proto_files} -I #{proto_paths}`
18
18
 
@@ -20,7 +20,7 @@ module ProtobufTranspiler
20
20
  unless keep_require
21
21
  Dir['app/stubs/**/*.rb'].each do |fp|
22
22
  f = File.read fp
23
- File.write fp, (f.sub /\n(require.*?'\n)+/, '')
23
+ File.write fp, (f.sub %r{\n(require.*?'\n)+}, '')
24
24
  end
25
25
  end
26
26
 
@@ -30,7 +30,7 @@ module ProtobufTranspiler
30
30
  .each { |dir|
31
31
  requires = Dir.chdir dir do
32
32
  curr_dir = Dir.pwd.split('/').last
33
- Dir['*.rb'].map { |s| "require_relative './#{curr_dir}/#{s.sub(/.rb$/, '')}'" }
33
+ Dir['*.rb'].map { |s| "require_relative './#{curr_dir}/#{s.sub %r{.rb$}, ''}'" }
34
34
  end
35
35
  File.write "#{dir}.rb", requires.join("\n")
36
36
  }
@@ -52,6 +52,7 @@ module ProtobufTranspiler
52
52
  stubs_modules.each do |m|
53
53
  out = m
54
54
  .constants
55
+ .sort
55
56
  .map { |c| m.const_get c }
56
57
  .each_with_object({ messages: [], services: [] }) { |c, acc|
57
58
  if c.is_a? Class
@@ -60,7 +61,7 @@ module ProtobufTranspiler
60
61
  acc[:services] << module_annotations(c)
61
62
  end
62
63
  }
63
- types_file, services_file = Dir["app/stubs/#{m.name.downcase}/*.rb"]
64
+ types_file, services_file = Dir["app/stubs/#{m.name.underscore}/*.rb"]
64
65
  .sort_by { |s| s.scan('services').count }
65
66
  [types_file, services_file]
66
67
  .zip([out[:messages], out[:services]])
@@ -70,20 +71,64 @@ module ProtobufTranspiler
70
71
 
71
72
  private
72
73
 
73
- ANNOTATE_DELIMITER = '===== Protobuf Annotation ====='
74
+ ANNOTATE_DELIMITER = '# ===== Protobuf Annotation ====='
74
75
 
75
- def class_annotations c
76
- c
77
- .descriptor.entries.map { |d| "\t#{d.name}: #{d.type}" }
78
- .prepend("#{c.name}")
79
- .join "\n"
76
+ def class_annotations klass
77
+ oneof_fields, oneof_annotations = lambda do |descriptor|
78
+ [
79
+ descriptor.each_oneof
80
+ .flat_map { |o| o.entries.map(&:name) },
81
+ descriptor.each_oneof
82
+ .map { |o| ["#{o.name}:", o.entries.map { |e| "\t| #{e.name}: #{type_handler e}" }].join("\n") }
83
+ .map { |s| s.gsub(%r{\t}, "\t\t").prepend("\t") + "\n" }
84
+ ]
85
+ end.call(klass.descriptor)
86
+
87
+ map_fields = lambda do |descriptor, instance|
88
+ descriptor.entries
89
+ .map(&:name)
90
+ .filter { |n| instance[n].class == Google::Protobuf::Map }
91
+ end.call(klass.descriptor, klass.new)
92
+
93
+ [
94
+ klass.name.to_s,
95
+ klass.constants(false).sort
96
+ .map { |msg| klass.const_get msg }
97
+ .map { |msg_class| class_annotations(msg_class) }
98
+ .map { |s| s.gsub(%r{\t}, "\t\t").prepend("\t") }
99
+ .prepend("\n"),
100
+ oneof_annotations,
101
+ klass.descriptor.entries
102
+ .reject{|d|oneof_fields.include? d.name}
103
+ .map { |d|
104
+ "\t#{d.name}: "+
105
+ type_handler(d, map_fields)
106
+ }
107
+ .join("\n"),
108
+ "\n"
109
+
110
+ ].join('')
80
111
  end
81
112
 
82
- def module_annotations m
83
- m
113
+ def type_handler d, map_fields = []
114
+ case
115
+ when d.is_a?(Symbol)
116
+ d
117
+ when map_fields.include?(d.name)
118
+ d.subtype.entries.then { |k,v| "Map<#{k.type}, #{type_handler(v)}>" }
119
+ when d.type == :message
120
+ d.subtype.msgclass.then{|t| d.label == :repeated ? "[#{t}]" : t}
121
+ else
122
+ d.type.then{|t| d.label == :repeated ? "[#{t}]" : t}
123
+ end.to_s
124
+ end
125
+
126
+ def module_annotations mod
127
+ mod
84
128
  .const_get('Service')
85
- .rpc_descs.map { |_, d| "\t#{d.name}(#{d.input}): #{d.output}" }
86
- .prepend("#{m.name}")
129
+ .rpc_descs.sort
130
+ .map { |_, d| "\t#{d.name}(#{d.input}): #{d.output}" }
131
+ .prepend(mod.name.to_s)
87
132
  .join "\n"
88
133
  end
89
134
 
@@ -92,13 +137,33 @@ module ProtobufTranspiler
92
137
  content = content.join("\n").gsub(%r{^}, '# ')
93
138
  new_content = if old_content.match? ANNOTATE_DELIMITER
94
139
  # replace annotation content
95
- old_content.sub %r{(?<=#{ANNOTATE_DELIMITER})(.|\n)*?(?=##{ANNOTATE_DELIMITER})}, "\n#{content}\n"
140
+ old_content.sub %r{(?<=#{ANNOTATE_DELIMITER}\n)(.|\n)*?(?=\n#{ANNOTATE_DELIMITER})}, "\n#{content}"
96
141
  else
97
142
  # find first spot after comments
98
143
  # add and fill annotation
99
- old_content.sub %r{^[^#]}, "\n# #{ANNOTATE_DELIMITER}\n#{content}\n# #{ANNOTATE_DELIMITER}\n\n"
144
+ old_content.sub %r{^[^#]}, "\n#{ANNOTATE_DELIMITER}\n\n#{content}\n#{ANNOTATE_DELIMITER}\n\n"
100
145
  end
101
146
  File.write file, new_content
102
147
  end
103
148
  end
104
149
  end
150
+
151
+ class GRPC::RpcDesc::Stream
152
+
153
+ def to_s
154
+ "stream #{type}"
155
+ end
156
+ end
157
+
158
+ monkey_patch_descriptor = Module.new do
159
+ def each_oneof(&)
160
+ return super if block_given?
161
+
162
+ Enumerator.new do |y|
163
+ super do |d|
164
+ y << d
165
+ end
166
+ end
167
+ end
168
+ end
169
+ Google::Protobuf::Descriptor.prepend monkey_patch_descriptor
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: protobuf_transpiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Moku S.r.l.
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2023-07-24 00:00:00.000000000 Z
12
+ date: 2023-08-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: google-protobuf