protobuf_transpiler 1.0.0 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 55572283d38aaaf17ae92233d0a4e276f1f4fa969ecea798d85c838b46070605
4
- data.tar.gz: a1b7299db9e0ac59d5c818b729e5515400a9f0127f18bf99cb074685d8f7fb60
3
+ metadata.gz: '0872a221c991587b5b5dde741f68f412c30a38db4ffdef9b51629d058ba9c1f0'
4
+ data.tar.gz: 4fe978a2ea8180b0677048e8622540e95c7f78bdae6a18b7984be7d5ded5ec7d
5
5
  SHA512:
6
- metadata.gz: c157a107eada279ba863e049248cfb38a8d573cb11c97fe7a92b8cf9af245f04338433845021381b9e5d2c51d880621bc82bf32a8e371a59ca0f2d4b71b19ae8
7
- data.tar.gz: e9240d2f92d78141d79e993ca8fda889540a7fa14d7c72fd8556d25e35e6aebba092ac80cac9768a53989579b0d83f2f8241e9de0d7fb1a11b2b19801434b5e1
6
+ metadata.gz: 113d630819223b40ee24f319ee429aca18abc8e3f5a4b5a8ad9a685174dff6389940531f5a3f2157829e48646e8ea22589ffc8fdc6311f4c4092e1fdc17eb15a
7
+ data.tar.gz: 65cf4a6fdc76306138598464c5b04b24da511a5b0593d8143733039b93560e5fd04a7a182ffb1a01c56f4d2fb070817f4b0fee5fd4fd025e1d3a73a1a5f328f4
data/CHANGELOG.md CHANGED
@@ -8,6 +8,20 @@
8
8
  ### Bug fixes
9
9
  )-->
10
10
 
11
+ ## 1.1.1 2023-11-13
12
+ ### Bug fixes
13
+ - require google-protobuf where its monkey patch is made
14
+
15
+ ## 1.1.0 2023-08-21
16
+ ### New features
17
+ - Add annotation support for:
18
+ - streams
19
+ - oneofs
20
+ - maps
21
+ - nested messages
22
+ ### Bug fixes
23
+ - Annotate task now correctly replaces existing annotations
24
+
11
25
  ## 1.0.0 2023-07-24
12
26
 
13
27
  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.1'
5
5
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "google/protobuf"
3
4
  require_relative "protobuf_transpiler/version"
4
5
 
5
6
  module ProtobufTranspiler
@@ -12,7 +13,7 @@ module ProtobufTranspiler
12
13
  proto_paths = proto_files
13
14
  .split.map { |p| p.sub %r{(?<=public).*}, '' }
14
15
  .uniq.join ' '
15
- out_path = "#{Rails.root}/app/stubs/"
16
+ out_path = "#{Rails.root}/app/stubs/"
16
17
  FileUtils.mkdir_p out_path
17
18
  `grpc_tools_ruby_protoc --ruby_out=#{out_path} --grpc_out=#{out_path} #{proto_files} -I #{proto_paths}`
18
19
 
@@ -20,7 +21,7 @@ module ProtobufTranspiler
20
21
  unless keep_require
21
22
  Dir['app/stubs/**/*.rb'].each do |fp|
22
23
  f = File.read fp
23
- File.write fp, (f.sub /\n(require.*?'\n)+/, '')
24
+ File.write fp, (f.sub %r{\n(require.*?'\n)+}, '')
24
25
  end
25
26
  end
26
27
 
@@ -30,7 +31,7 @@ module ProtobufTranspiler
30
31
  .each { |dir|
31
32
  requires = Dir.chdir dir do
32
33
  curr_dir = Dir.pwd.split('/').last
33
- Dir['*.rb'].map { |s| "require_relative './#{curr_dir}/#{s.sub(/.rb$/, '')}'" }
34
+ Dir['*.rb'].map { |s| "require_relative './#{curr_dir}/#{s.sub %r{.rb$}, ''}'" }
34
35
  end
35
36
  File.write "#{dir}.rb", requires.join("\n")
36
37
  }
@@ -52,6 +53,7 @@ module ProtobufTranspiler
52
53
  stubs_modules.each do |m|
53
54
  out = m
54
55
  .constants
56
+ .sort
55
57
  .map { |c| m.const_get c }
56
58
  .each_with_object({ messages: [], services: [] }) { |c, acc|
57
59
  if c.is_a? Class
@@ -60,7 +62,7 @@ module ProtobufTranspiler
60
62
  acc[:services] << module_annotations(c)
61
63
  end
62
64
  }
63
- types_file, services_file = Dir["app/stubs/#{m.name.downcase}/*.rb"]
65
+ types_file, services_file = Dir["app/stubs/#{m.name.underscore}/*.rb"]
64
66
  .sort_by { |s| s.scan('services').count }
65
67
  [types_file, services_file]
66
68
  .zip([out[:messages], out[:services]])
@@ -70,20 +72,64 @@ module ProtobufTranspiler
70
72
 
71
73
  private
72
74
 
73
- ANNOTATE_DELIMITER = '===== Protobuf Annotation ====='
75
+ ANNOTATE_DELIMITER = '# ===== Protobuf Annotation ====='
74
76
 
75
- def class_annotations c
76
- c
77
- .descriptor.entries.map { |d| "\t#{d.name}: #{d.type}" }
78
- .prepend("#{c.name}")
79
- .join "\n"
77
+ def class_annotations klass
78
+ oneof_fields, oneof_annotations = lambda do |descriptor|
79
+ [
80
+ descriptor.each_oneof
81
+ .flat_map { |o| o.entries.map(&:name) },
82
+ descriptor.each_oneof
83
+ .map { |o| ["#{o.name}:", o.entries.map { |e| "\t| #{e.name}: #{type_handler e}" }].join("\n") }
84
+ .map { |s| s.gsub(%r{\t}, "\t\t").prepend("\t") + "\n" }
85
+ ]
86
+ end.call(klass.descriptor)
87
+
88
+ map_fields = lambda do |descriptor, instance|
89
+ descriptor.entries
90
+ .map(&:name)
91
+ .filter { |n| instance[n].class == Google::Protobuf::Map }
92
+ end.call(klass.descriptor, klass.new)
93
+
94
+ [
95
+ klass.name.to_s,
96
+ klass.constants(false).sort
97
+ .map { |msg| klass.const_get msg }
98
+ .map { |msg_class| class_annotations(msg_class) }
99
+ .map { |s| s.gsub(%r{\t}, "\t\t").prepend("\t") }
100
+ .prepend("\n"),
101
+ oneof_annotations,
102
+ klass.descriptor.entries
103
+ .reject{|d|oneof_fields.include? d.name}
104
+ .map { |d|
105
+ "\t#{d.name}: "+
106
+ type_handler(d, map_fields)
107
+ }
108
+ .join("\n"),
109
+ "\n"
110
+
111
+ ].join('')
80
112
  end
81
113
 
82
- def module_annotations m
83
- m
114
+ def type_handler d, map_fields = []
115
+ case
116
+ when d.is_a?(Symbol)
117
+ d
118
+ when map_fields.include?(d.name)
119
+ d.subtype.entries.then { |k,v| "Map<#{k.type}, #{type_handler(v)}>" }
120
+ when d.type == :message
121
+ d.subtype.msgclass.then{|t| d.label == :repeated ? "[#{t}]" : t}
122
+ else
123
+ d.type.then{|t| d.label == :repeated ? "[#{t}]" : t}
124
+ end.to_s
125
+ end
126
+
127
+ def module_annotations mod
128
+ mod
84
129
  .const_get('Service')
85
- .rpc_descs.map { |_, d| "\t#{d.name}(#{d.input}): #{d.output}" }
86
- .prepend("#{m.name}")
130
+ .rpc_descs.sort
131
+ .map { |_, d| "\t#{d.name}(#{d.input}): #{d.output}" }
132
+ .prepend(mod.name.to_s)
87
133
  .join "\n"
88
134
  end
89
135
 
@@ -92,13 +138,33 @@ module ProtobufTranspiler
92
138
  content = content.join("\n").gsub(%r{^}, '# ')
93
139
  new_content = if old_content.match? ANNOTATE_DELIMITER
94
140
  # replace annotation content
95
- old_content.sub %r{(?<=#{ANNOTATE_DELIMITER})(.|\n)*?(?=##{ANNOTATE_DELIMITER})}, "\n#{content}\n"
141
+ old_content.sub %r{(?<=#{ANNOTATE_DELIMITER}\n)(.|\n)*?(?=\n#{ANNOTATE_DELIMITER})}, "\n#{content}"
96
142
  else
97
143
  # find first spot after comments
98
144
  # add and fill annotation
99
- old_content.sub %r{^[^#]}, "\n# #{ANNOTATE_DELIMITER}\n#{content}\n# #{ANNOTATE_DELIMITER}\n\n"
145
+ old_content.sub %r{^[^#]}, "\n#{ANNOTATE_DELIMITER}\n\n#{content}\n#{ANNOTATE_DELIMITER}\n\n"
100
146
  end
101
147
  File.write file, new_content
102
148
  end
103
149
  end
104
150
  end
151
+
152
+ class GRPC::RpcDesc::Stream
153
+
154
+ def to_s
155
+ "stream #{type}"
156
+ end
157
+ end
158
+
159
+ monkey_patch_descriptor = Module.new do
160
+ def each_oneof(&)
161
+ return super if block_given?
162
+
163
+ Enumerator.new do |y|
164
+ super do |d|
165
+ y << d
166
+ end
167
+ end
168
+ end
169
+ end
170
+ 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.1
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-11-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: google-protobuf