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 +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +17 -5
- data/lib/protobuf_transpiler/version.rb +1 -1
- data/lib/protobuf_transpiler.rb +82 -16
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0872a221c991587b5b5dde741f68f412c30a38db4ffdef9b51629d058ba9c1f0'
|
4
|
+
data.tar.gz: 4fe978a2ea8180b0677048e8622540e95c7f78bdae6a18b7984be7d5ded5ec7d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
├── mod1
|
41
|
+
│ └── sample1.proto
|
42
|
+
├── mod2
|
43
|
+
│ └── sample2.proto
|
44
44
|
```
|
45
|
-
you will get the
|
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
|
|
data/lib/protobuf_transpiler.rb
CHANGED
@@ -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
|
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
|
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
|
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.
|
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
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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
|
83
|
-
|
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.
|
86
|
-
.
|
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)*?(
|
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#
|
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.
|
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-
|
12
|
+
date: 2023-11-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: google-protobuf
|