protoc-gen-twirp_ruby 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 +13 -0
- data/README.md +71 -15
- data/exe/protoc-gen-twirp_ruby +15 -2
- data/lib/google/protobuf/compiler/plugin_pb.rb +1 -23
- data/lib/google/protobuf/descriptor_pb.rb +2 -23
- data/lib/twirp/protoc_plugin/code_generator.rb +74 -127
- data/lib/twirp/protoc_plugin/compiler_plugin_ext/code_generator_request_ext.rb +55 -0
- data/lib/twirp/protoc_plugin/core_ext/file/delete_extension.rb +11 -0
- data/lib/twirp/protoc_plugin/core_ext/string/camel_case.rb +24 -0
- data/lib/twirp/protoc_plugin/core_ext/string/capitalize_first.rb +14 -0
- data/lib/twirp/protoc_plugin/core_ext/string/snake_case.rb +14 -0
- data/lib/twirp/protoc_plugin/descriptor_ext/file_descriptor_proto_ext.rb +204 -0
- data/lib/twirp/protoc_plugin/descriptor_ext/service_descriptor_proto_ext.rb +23 -0
- data/lib/twirp/protoc_plugin/process.rb +53 -27
- data/lib/twirp/protoc_plugin/version.rb +1 -1
- metadata +15 -29
- data/.rspec +0 -3
- data/.standard.yml +0 -6
- data/Rakefile +0 -10
- data/example/hello_world.proto +0 -14
- data/example/hello_world_pb.rb +0 -39
- data/example/hello_world_twirp.rb +0 -21
- data/proto/google/protobuf/compiler/plugin.proto +0 -180
- data/proto/google/protobuf/descriptor.proto +0 -1280
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "google/protobuf/compiler/plugin_pb"
|
4
|
+
require "twirp/protoc_plugin/descriptor_ext/file_descriptor_proto_ext"
|
5
|
+
|
6
|
+
class Google::Protobuf::Compiler::CodeGeneratorRequest
|
7
|
+
class << self
|
8
|
+
alias_method :old_decode, :decode
|
9
|
+
|
10
|
+
def decode(bytes)
|
11
|
+
request = old_decode(bytes)
|
12
|
+
request.send(:populate_dependency_proto_files!)
|
13
|
+
|
14
|
+
request
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# Access the [`Google::Protobuf::RepeatedField`] of [Google::Protobuf::FileDescriptorProto]
|
21
|
+
# as a proper Array, memoizing the value in the process.
|
22
|
+
#
|
23
|
+
# This memoized value stabilizes the test suite when run via `rake spec` (whereas, interestingly,
|
24
|
+
# running standalone `rspec` was fine). I'm not certain why that is, but I wonder if it has to
|
25
|
+
# do with memory pressure and garbage collection that runs during `rake spec` but not `rspec`
|
26
|
+
# (because `rspec` loads less into memory)... and memoizing the value forces the GC to keep the
|
27
|
+
# `FileDescriptorProto` references around.
|
28
|
+
#
|
29
|
+
# Before this change, the `populate_dependency_proto_files!` method would execute and modify
|
30
|
+
# the `file_descriptor_proto`, but sometimes the changes inside the enumerator wouldn't "stick"
|
31
|
+
# after the enumeration went out of scope. (Again, only via the `rake spec` command, not via
|
32
|
+
# `rspec`). This resulted in the `dependency_proto_files` value being unexpectedly `nil` when at
|
33
|
+
# the very least an empty array was expected.
|
34
|
+
#
|
35
|
+
# @return [Array<Google::Protobuf::FileDescriptorProto>]
|
36
|
+
def proto_files
|
37
|
+
@proto_files ||= proto_file.to_ary
|
38
|
+
end
|
39
|
+
|
40
|
+
def populate_dependency_proto_files!
|
41
|
+
proto_files.each do |file_descriptor_proto|
|
42
|
+
file_descriptor_proto.dependency_proto_files = []
|
43
|
+
|
44
|
+
file_descriptor_proto.dependency.each do |dependent_file_name|
|
45
|
+
file_descriptor_proto.dependency_proto_files << proto_file_for(dependent_file_name)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# @param name [String]
|
51
|
+
# @return [Google::Protobuf::FileDescriptorProto, nil]
|
52
|
+
def proto_file_for(name)
|
53
|
+
proto_files.find { |proto_file| proto_file.name == name }
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class File
|
4
|
+
# @param filename [String] a filename string (with optional path),
|
5
|
+
# e.g. "some/example/hello.proto"
|
6
|
+
# @return [String] the filename (preserving optional path) minus the file extension,
|
7
|
+
# e.g. "some/example/hello"
|
8
|
+
def self.delete_extension(filename)
|
9
|
+
filename.delete_suffix(File.extname(filename))
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "twirp/protoc_plugin/core_ext/string/capitalize_first"
|
4
|
+
|
5
|
+
class String
|
6
|
+
# Returns the string converted to either lowerCamelCase or UpperCamelCase.
|
7
|
+
#
|
8
|
+
# Inspired by https://github.com/rails/rails/blob/6f0d1ad14b92b9f5906e44740fce8b4f1c7075dc/activesupport/lib/active_support/inflector/methods.rb#L70
|
9
|
+
#
|
10
|
+
# @param uppercase_first_letter [Boolean] true for UpperCamelCase,
|
11
|
+
# false for lowerCamelCase. Defaults to true.
|
12
|
+
# @return [String] a copy of the chars of <code>self</code>
|
13
|
+
def camel_case(uppercase_first_letter = true)
|
14
|
+
s = if uppercase_first_letter
|
15
|
+
capitalize_first
|
16
|
+
else
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
s.gsub(/_([a-z\d]*)/i) do
|
21
|
+
$1.capitalize
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class String
|
4
|
+
# Capitalizes the first letter of the string.
|
5
|
+
#
|
6
|
+
# Inspired by https://github.com/rails/rails/blob/6f0d1ad14b92b9f5906e44740fce8b4f1c7075dc/activesupport/lib/active_support/inflector/methods.rb#L166
|
7
|
+
#
|
8
|
+
# @return [String] a string with the first letter capitalized
|
9
|
+
def capitalize_first
|
10
|
+
return "" if empty?
|
11
|
+
|
12
|
+
self[0].upcase + self[1..]
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class String
|
4
|
+
# Converts the string to lower_snake_case.
|
5
|
+
#
|
6
|
+
# Inspired by https://github.com/rails/rails/blob/6f0d1ad14b92b9f5906e44740fce8b4f1c7075dc/activesupport/lib/active_support/inflector/methods.rb#L99
|
7
|
+
#
|
8
|
+
# @return [String] the converted input
|
9
|
+
def snake_case
|
10
|
+
gsub(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
11
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
12
|
+
.downcase
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "google/protobuf/descriptor_pb"
|
4
|
+
require "twirp/protoc_plugin/core_ext/string/camel_case"
|
5
|
+
|
6
|
+
class Google::Protobuf::FileDescriptorProto
|
7
|
+
# The `FileDescriptorProto` contains a `dependency` array of all of the imported file
|
8
|
+
# name strings, in the order in which they appear in the source file.
|
9
|
+
#
|
10
|
+
# We want to create a parallel array, but instead of just the file names, we want
|
11
|
+
# the _references_ to those proto file descriptors. So, we declare the attribute
|
12
|
+
# here. NOTE: We also override `CodeGeneratorRequest` `decode` such that it automatically
|
13
|
+
# populates this array when the request is decoded.
|
14
|
+
#
|
15
|
+
# @return [Array<Google::Protobuf::FileDescriptorProto>]
|
16
|
+
attr_accessor :dependency_proto_files
|
17
|
+
|
18
|
+
# @return [String] the output filename for the proto file's generated twirp code.
|
19
|
+
# For example, given a `name` of e.g. "some/example/hello.proto", the twirp output
|
20
|
+
# filename is "some/example/hello_twirp.rb"
|
21
|
+
def twirp_output_filename
|
22
|
+
File.delete_extension(name) + "_twirp.rb"
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [String] the file name of the generated ruby protobuf code from protoc,
|
26
|
+
# without any path information and missing the ".rb" file extension.
|
27
|
+
#
|
28
|
+
# For example, given a `name` of e.g. "some/example/hello.proto", this helper
|
29
|
+
# returns "hello_rb". The ruby output is expected to be located in the same
|
30
|
+
# directory as the generated twirp output file.
|
31
|
+
def relative_ruby_protobuf_name
|
32
|
+
File.basename(name, File.extname(name)) + "_pb"
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [Boolean] true if the proto file has at least one `service` definition,
|
36
|
+
# false otherwise.
|
37
|
+
def has_service?
|
38
|
+
!service.empty?
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [String] the ruby module for this proto file. Gives precedence to
|
42
|
+
# the `ruby_package` option if specified, then the `package` of the file
|
43
|
+
# (converted to UpperCamelCase). Includes a leading top-level namespace
|
44
|
+
# qualifier "::", e.g.: "::MyCompany::Example::Api". Returns `""` when neither
|
45
|
+
# ruby_package nor package is specified.
|
46
|
+
def ruby_module
|
47
|
+
@ruby_module ||= begin
|
48
|
+
pkg = options.ruby_package unless options&.ruby_package.to_s.empty?
|
49
|
+
pkg ||= split_to_constants(package).join("::").to_s unless package.to_s.empty?
|
50
|
+
|
51
|
+
if pkg.nil?
|
52
|
+
"" # Set to "" instead of nil to properly memoize and avoid re-calculating
|
53
|
+
else
|
54
|
+
"::" + pkg
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Converts a protobuf message type to a string containing the equivalent Ruby constant,
|
60
|
+
# relative to the current proto file's Ruby module.
|
61
|
+
#
|
62
|
+
# Respects the `ruby_package` option, both for the current proto file and for all
|
63
|
+
# message types that are imported if the imported file also specifies a `ruby_package`.
|
64
|
+
#
|
65
|
+
# For example, given ...
|
66
|
+
#
|
67
|
+
# 1) the current file has `package "foo.bar";` and `option ruby_package = "Foo::Bar";`
|
68
|
+
# 2) an imported file has `package "other.file.baz";` and `option ruby_package = "Baz";`
|
69
|
+
# 3) a third imported file has `package "third.file";` without a `ruby_package` option.
|
70
|
+
#
|
71
|
+
# ... then:
|
72
|
+
#
|
73
|
+
# ruby_type_for(".foo.bar.example_message") => "ExampleMessage"
|
74
|
+
# ruby_type_for(".foo.bar.ExampleMessage.NestedMessage") => "ExampleMessage::NestedMessage"
|
75
|
+
# ruby_type_for(".google.protobuf.Empty") => "::Google::Protobuf::Empty"
|
76
|
+
# ruby_type_for(".other.file.baz.example_message") => "::Baz::ExampleMessage"
|
77
|
+
# ruby_type_for(".third.file.example_message") => "::Third::File::ExampleMessage"
|
78
|
+
#
|
79
|
+
# @param message_type [String]
|
80
|
+
# @return [String]
|
81
|
+
def ruby_type_for(message_type)
|
82
|
+
ruby_type = ruby_type_map[message_type]
|
83
|
+
|
84
|
+
# For types in the same module, remove module and trailing "::"
|
85
|
+
ruby_type = ruby_type.delete_prefix(ruby_module + "::") unless ruby_module.empty?
|
86
|
+
|
87
|
+
ruby_type
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
# Converts either a package string like ".some.example.api" or a namespaced
|
93
|
+
# message like ".google.protobuf.Empty" to an Array of Strings that can be
|
94
|
+
# used as Ruby constants (when joined with "::").
|
95
|
+
#
|
96
|
+
# ".some.example.api" becomes ["", Some", "Example", "Api"]
|
97
|
+
# ".google.protobuf.Empty" becomes ["", Google", "Protobuf", "Empty"]
|
98
|
+
#
|
99
|
+
# @param package_or_message [String]
|
100
|
+
# @return [Array<String>]
|
101
|
+
def split_to_constants(package_or_message)
|
102
|
+
package_or_message
|
103
|
+
.split(".")
|
104
|
+
.map { |s| s.camel_case }
|
105
|
+
end
|
106
|
+
|
107
|
+
# @return [Hash<String, String>] the type mappings for the proto file (and all
|
108
|
+
# imported proto files), keyed by the the protobuf name (starting with `.` when
|
109
|
+
# package is specified). Values correspond to the fully qualified Ruby
|
110
|
+
# type, respecting the `ruby_package` option of the file if present.
|
111
|
+
#
|
112
|
+
# For example:
|
113
|
+
# ".example_message" => "ExampleMessage"
|
114
|
+
# ".foo.bar.ExampleMessage => "::Foo::Bar::ExampleMessage"
|
115
|
+
# ".foo.bar.ExampleMessage.NestedMessage" => "::Foo::Bar::ExampleMessage::NestedMessage"
|
116
|
+
# ".google.protobuf.Empty" => "Google::Protobuf::Empty"
|
117
|
+
# ".common.bar.baz.other_type" => "::Common::Baz::OtherType"
|
118
|
+
# (when type is imported from a proto file with package = "common.bar.baz"
|
119
|
+
# and `option ruby_package = "Common::Baz";` specified)
|
120
|
+
def ruby_type_map
|
121
|
+
if @ruby_type_map.nil?
|
122
|
+
@ruby_type_map = build_ruby_type_map(self)
|
123
|
+
end
|
124
|
+
|
125
|
+
@ruby_type_map
|
126
|
+
end
|
127
|
+
|
128
|
+
# Loops through the messages in the proto file, and recurses through the messages in
|
129
|
+
# dependent proto files, to construct the ruby type map for all types within the file.
|
130
|
+
#
|
131
|
+
# @see [#ruby_type_map]
|
132
|
+
# @param proto_file [Google::Protobuf::FileDescriptorProto]
|
133
|
+
# @return [Hash<String, String>]
|
134
|
+
def build_ruby_type_map(proto_file)
|
135
|
+
type_map = {}
|
136
|
+
|
137
|
+
proto_file.message_type.each do |message_type|
|
138
|
+
add_message_type(type_map, proto_file, message_type)
|
139
|
+
end
|
140
|
+
|
141
|
+
proto_file.dependency_proto_files.each do |dependency_proto_file|
|
142
|
+
type_map.merge! build_ruby_type_map(dependency_proto_file)
|
143
|
+
end
|
144
|
+
|
145
|
+
type_map
|
146
|
+
end
|
147
|
+
|
148
|
+
# Adds the message type's key and value to the type map, recursively handling nested message
|
149
|
+
# types along the way.
|
150
|
+
#
|
151
|
+
# @param type_map [Hash<String, String>]
|
152
|
+
# @param proto_file [Google::Protobuf::FileDescriptorProto] The proto file containing the message type
|
153
|
+
# @param message_type [Google::Protobuf::DescriptorProto]
|
154
|
+
# @param parent_key [String, nil] In the recursive case, this is the parent message type key so
|
155
|
+
# that the nested child type can be properly namespaced.
|
156
|
+
# @param parent_value [String, nil] In the recursive case, this is the parent message type value
|
157
|
+
# so that the nested type can be properly namespaced.
|
158
|
+
# @return [void]
|
159
|
+
def add_message_type(type_map, proto_file, message_type, parent_key = nil, parent_value = nil)
|
160
|
+
key = type_map_key(proto_file, message_type, parent_key)
|
161
|
+
value = type_map_value(proto_file, message_type, parent_value)
|
162
|
+
|
163
|
+
type_map[key] = value
|
164
|
+
|
165
|
+
# Recurse over nested types, using the current message_type's key and value as the parent values
|
166
|
+
message_type.nested_type.each do |nested_type|
|
167
|
+
add_message_type(type_map, proto_file, nested_type, key, value)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# @param proto_file [Google::Protobuf::FileDescriptorProto] The proto file containing the message type
|
172
|
+
# @param message_type [Google::Protobuf::DescriptorProto]
|
173
|
+
# @param parent_key [String, nil] In the recursive case, this is the parent message type key so
|
174
|
+
# that the nested child type can be properly namespaced.
|
175
|
+
# @return [String]
|
176
|
+
def type_map_key(proto_file, message_type, parent_key)
|
177
|
+
key_prefix = if !parent_key.nil?
|
178
|
+
"#{parent_key}."
|
179
|
+
elsif proto_file.package.to_s.empty?
|
180
|
+
"."
|
181
|
+
else
|
182
|
+
".#{proto_file.package}."
|
183
|
+
end
|
184
|
+
|
185
|
+
"#{key_prefix}#{message_type.name}"
|
186
|
+
end
|
187
|
+
|
188
|
+
# @param proto_file [Google::Protobuf::FileDescriptorProto] The proto file containing the message type
|
189
|
+
# @param message_type [Google::Protobuf::DescriptorProto]
|
190
|
+
# @param parent_value [String, nil] In the recursive case, this is the parent message type value
|
191
|
+
# so that the nested type can be properly namespaced.
|
192
|
+
# @return [String]
|
193
|
+
def type_map_value(proto_file, message_type, parent_value)
|
194
|
+
value_prefix = if !parent_value.nil?
|
195
|
+
"#{parent_value}::"
|
196
|
+
elsif proto_file.ruby_module.empty?
|
197
|
+
""
|
198
|
+
else
|
199
|
+
"#{proto_file.ruby_module}::"
|
200
|
+
end
|
201
|
+
|
202
|
+
"#{value_prefix}#{message_type.name.camel_case}"
|
203
|
+
end
|
204
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "google/protobuf/descriptor_pb"
|
4
|
+
require "twirp/protoc_plugin/core_ext/string/camel_case"
|
5
|
+
|
6
|
+
class Google::Protobuf::ServiceDescriptorProto
|
7
|
+
def service_class_name
|
8
|
+
# The generated service class name should end in "Service"; A well-named
|
9
|
+
# service may already end with "Service" but we can't guarantee it. Use
|
10
|
+
# class_name_without_service_suffix to #avoid "ServiceService"
|
11
|
+
class_name_without_service_suffix + "Service"
|
12
|
+
end
|
13
|
+
|
14
|
+
def client_class_name
|
15
|
+
class_name_without_service_suffix + "Client"
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def class_name_without_service_suffix
|
21
|
+
name.delete_suffix("Service").camel_case
|
22
|
+
end
|
23
|
+
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require "twirp/protoc_plugin/core_ext/file/delete_extension"
|
4
|
+
require "google/protobuf/compiler/plugin_pb"
|
5
|
+
require "twirp/protoc_plugin/compiler_plugin_ext/code_generator_request_ext"
|
6
|
+
require "twirp/protoc_plugin/descriptor_ext/file_descriptor_proto_ext"
|
4
7
|
require_relative "code_generator"
|
5
8
|
|
6
9
|
module Twirp
|
@@ -10,19 +13,23 @@ module Twirp
|
|
10
13
|
class << self
|
11
14
|
# @param input [String] an encoded [Google::Protobuf::Compiler::CodeGeneratorRequest] message
|
12
15
|
# @return [String] an encoded [Google::Protobuf::Compiler::CodeGeneratorResponse] message
|
13
|
-
# @raise [
|
16
|
+
# @raise [ArgumentError] when a required parameter is missing, a parameter value is invalid, or
|
17
|
+
# an unrecognized parameter is present on the command line
|
14
18
|
def process(input)
|
15
19
|
request = Google::Protobuf::Compiler::CodeGeneratorRequest.decode(input)
|
16
20
|
|
21
|
+
options = extract_options(request.parameter)
|
22
|
+
|
17
23
|
response = Google::Protobuf::Compiler::CodeGeneratorResponse.new
|
18
24
|
response.supported_features = Google::Protobuf::Compiler::CodeGeneratorResponse::Feature::FEATURE_PROTO3_OPTIONAL
|
19
25
|
|
20
|
-
request.proto_file.each do |proto_file|
|
26
|
+
request.proto_file.each do |proto_file| # proto_file: <Google::Protobuf::FileDescriptorProto>
|
21
27
|
next unless request.file_to_generate.include?(proto_file.name)
|
28
|
+
next if options[:skip_empty] && !proto_file.has_service?
|
22
29
|
|
23
30
|
file = Google::Protobuf::Compiler::CodeGeneratorResponse::File.new
|
24
|
-
file.name =
|
25
|
-
file.content = CodeGenerator.new(proto_file,
|
31
|
+
file.name = proto_file.twirp_output_filename
|
32
|
+
file.content = CodeGenerator.new(proto_file, proto_file.relative_ruby_protobuf_name, options).generate
|
26
33
|
|
27
34
|
response.file << file
|
28
35
|
end
|
@@ -32,30 +39,49 @@ module Twirp
|
|
32
39
|
|
33
40
|
private
|
34
41
|
|
35
|
-
# @param
|
36
|
-
# e.g. "some
|
37
|
-
#
|
38
|
-
#
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
+
# @param params [String] the parameters from protoc command line in comma-separated stringified
|
43
|
+
# array format, e.g. "some-flag,key1=value1".
|
44
|
+
#
|
45
|
+
# The only valid parameter is currently the optional "skip-empty" flag.
|
46
|
+
# @return [Hash{Symbol => Boolean, Symbol}]
|
47
|
+
# * :skip_empty [Boolean] indicating whether generation should skip creating a twirp file
|
48
|
+
# for proto files that contain no services. Default false.
|
49
|
+
# * :generate [Symbol] one of: :service, :client, or :both. Default :both.
|
50
|
+
# @raise [ArgumentError] when a required parameter is missing, a parameter value is invalid, or
|
51
|
+
# an unrecognized parameter is present on the command line
|
52
|
+
def extract_options(params)
|
53
|
+
opts = {
|
54
|
+
skip_empty: false,
|
55
|
+
generate: :both
|
56
|
+
}
|
42
57
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
58
|
+
# Process the options passed to the plugin from `protoc`.
|
59
|
+
params.split(",").each do |param|
|
60
|
+
# In the event value contains an =, we want to leave that intact.
|
61
|
+
# Limit the split to just separate the key out.
|
62
|
+
key, value = param.split("=", 2)
|
63
|
+
if key == "skip-empty"
|
64
|
+
unless value.nil? || value.empty?
|
65
|
+
raise ArgumentError, "Unexpected value passed to skip-empty flag: #{value}"
|
66
|
+
end
|
67
|
+
opts[:skip_empty] = true
|
68
|
+
elsif key == "generate"
|
69
|
+
if value.nil? || value.empty?
|
70
|
+
raise ArgumentError, "Unexpected missing value for generate option. Please supply one of: service, client, both."
|
71
|
+
end
|
72
|
+
|
73
|
+
value_as_symbol = value&.to_sym
|
74
|
+
unless %i[service client both].include?(value_as_symbol)
|
75
|
+
raise ArgumentError, "The generate value must be one of: service, client, both. Unexpectedly received: #{value}"
|
76
|
+
end
|
77
|
+
|
78
|
+
opts[:generate] = value_as_symbol
|
79
|
+
else
|
80
|
+
raise ArgumentError, "Invalid option: #{key}"
|
81
|
+
end
|
82
|
+
end
|
50
83
|
|
51
|
-
|
52
|
-
# e.g. "some/example/hello.proto"
|
53
|
-
# @return [String] the file name of the generated ruby protobuf code from protoc,
|
54
|
-
# without any path information, minus the ".rb" extension, e.g. "hello_pb". We
|
55
|
-
# expect the generated twirp file to be in the same directory as the generated
|
56
|
-
# ruby output.
|
57
|
-
def relative_ruby_protobuf(filename)
|
58
|
-
File.basename(filename, File.extname(filename)) + "_pb" # no ".rb" extension
|
84
|
+
opts
|
59
85
|
end
|
60
86
|
end
|
61
87
|
end
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: protoc-gen-twirp_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Darron Schall
|
8
8
|
- Daniel Morrison
|
9
9
|
- Chris Gaffney
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2024-05-
|
13
|
+
date: 2024-05-22 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: google-protobuf
|
@@ -26,20 +26,6 @@ dependencies:
|
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: '0'
|
29
|
-
- !ruby/object:Gem::Dependency
|
30
|
-
name: racc
|
31
|
-
requirement: !ruby/object:Gem::Requirement
|
32
|
-
requirements:
|
33
|
-
- - ">="
|
34
|
-
- !ruby/object:Gem::Version
|
35
|
-
version: '0'
|
36
|
-
type: :runtime
|
37
|
-
prerelease: false
|
38
|
-
version_requirements: !ruby/object:Gem::Requirement
|
39
|
-
requirements:
|
40
|
-
- - ">="
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
version: '0'
|
43
29
|
- !ruby/object:Gem::Dependency
|
44
30
|
name: rake
|
45
31
|
requirement: !ruby/object:Gem::Requirement
|
@@ -96,31 +82,31 @@ dependencies:
|
|
96
82
|
- - ">="
|
97
83
|
- !ruby/object:Gem::Version
|
98
84
|
version: '0'
|
99
|
-
description: A
|
85
|
+
description: A protoc plugin that generates Twirp-Ruby services and clients. A pure
|
86
|
+
Ruby alternative to the Go version that ships with Twirp-Ruby.
|
100
87
|
email: info@collectiveidea.com
|
101
88
|
executables:
|
102
89
|
- protoc-gen-twirp_ruby
|
103
90
|
extensions: []
|
104
91
|
extra_rdoc_files: []
|
105
92
|
files:
|
106
|
-
- ".rspec"
|
107
|
-
- ".standard.yml"
|
108
93
|
- CHANGELOG.md
|
109
94
|
- LICENSE
|
110
95
|
- README.md
|
111
|
-
- Rakefile
|
112
|
-
- example/hello_world.proto
|
113
|
-
- example/hello_world_pb.rb
|
114
|
-
- example/hello_world_twirp.rb
|
115
96
|
- exe/protoc-gen-twirp_ruby
|
116
97
|
- lib/google/protobuf/compiler/plugin_pb.rb
|
117
98
|
- lib/google/protobuf/descriptor_pb.rb
|
118
99
|
- lib/twirp/protoc_plugin.rb
|
119
100
|
- lib/twirp/protoc_plugin/code_generator.rb
|
101
|
+
- lib/twirp/protoc_plugin/compiler_plugin_ext/code_generator_request_ext.rb
|
102
|
+
- lib/twirp/protoc_plugin/core_ext/file/delete_extension.rb
|
103
|
+
- lib/twirp/protoc_plugin/core_ext/string/camel_case.rb
|
104
|
+
- lib/twirp/protoc_plugin/core_ext/string/capitalize_first.rb
|
105
|
+
- lib/twirp/protoc_plugin/core_ext/string/snake_case.rb
|
106
|
+
- lib/twirp/protoc_plugin/descriptor_ext/file_descriptor_proto_ext.rb
|
107
|
+
- lib/twirp/protoc_plugin/descriptor_ext/service_descriptor_proto_ext.rb
|
120
108
|
- lib/twirp/protoc_plugin/process.rb
|
121
109
|
- lib/twirp/protoc_plugin/version.rb
|
122
|
-
- proto/google/protobuf/compiler/plugin.proto
|
123
|
-
- proto/google/protobuf/descriptor.proto
|
124
110
|
- sig/twirp/protoc_plugin.rbs
|
125
111
|
homepage: https://github.com/collectiveidea/protoc-gen-twirp_ruby
|
126
112
|
licenses:
|
@@ -130,7 +116,7 @@ metadata:
|
|
130
116
|
source_code_uri: https://github.com/collectiveidea/protoc-gen-twirp_ruby
|
131
117
|
changelog_uri: https://github.com/collectiveidea/protoc-gen-twirp_ruby/blob/main/CHANGELOG.md
|
132
118
|
bug_tracker_uri: https://github.com/collectiveidea/protoc-gen-twirp_ruby/issues
|
133
|
-
post_install_message:
|
119
|
+
post_install_message:
|
134
120
|
rdoc_options: []
|
135
121
|
require_paths:
|
136
122
|
- lib
|
@@ -146,7 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
146
132
|
version: '0'
|
147
133
|
requirements: []
|
148
134
|
rubygems_version: 3.5.9
|
149
|
-
signing_key:
|
135
|
+
signing_key:
|
150
136
|
specification_version: 4
|
151
|
-
summary: A
|
137
|
+
summary: A protoc plugin for generating Twirp-Ruby clients and/or services
|
152
138
|
test_files: []
|
data/.rspec
DELETED
data/.standard.yml
DELETED
data/Rakefile
DELETED
data/example/hello_world.proto
DELETED
data/example/hello_world_pb.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
3
|
-
# source: example/hello_world.proto
|
4
|
-
|
5
|
-
require 'google/protobuf'
|
6
|
-
|
7
|
-
|
8
|
-
descriptor_data = "\n\x19\x65xample/hello_world.proto\x12\x13\x65xample.hello_world\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\" \n\rHelloResponse\x12\x0f\n\x07message\x18\x01 \x01(\t2c\n\x11HelloWorldService\x12N\n\x05Hello\x12!.example.hello_world.HelloRequest\x1a\".example.hello_world.HelloResponseb\x06proto3"
|
9
|
-
|
10
|
-
pool = Google::Protobuf::DescriptorPool.generated_pool
|
11
|
-
|
12
|
-
begin
|
13
|
-
pool.add_serialized_file(descriptor_data)
|
14
|
-
rescue TypeError
|
15
|
-
# Compatibility code: will be removed in the next major version.
|
16
|
-
require 'google/protobuf/descriptor_pb'
|
17
|
-
parsed = Google::Protobuf::FileDescriptorProto.decode(descriptor_data)
|
18
|
-
parsed.clear_dependency
|
19
|
-
serialized = parsed.class.encode(parsed)
|
20
|
-
file = pool.add_serialized_file(serialized)
|
21
|
-
warn "Warning: Protobuf detected an import path issue while loading generated file #{__FILE__}"
|
22
|
-
imports = [
|
23
|
-
]
|
24
|
-
imports.each do |type_name, expected_filename|
|
25
|
-
import_file = pool.lookup(type_name).file_descriptor
|
26
|
-
if import_file.name != expected_filename
|
27
|
-
warn "- #{file.name} imports #{expected_filename}, but that import was loaded as #{import_file.name}"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
warn "Each proto file must use a consistent fully-qualified name."
|
31
|
-
warn "This will become an error in the next major version."
|
32
|
-
end
|
33
|
-
|
34
|
-
module Example
|
35
|
-
module HelloWorld
|
36
|
-
HelloRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("example.hello_world.HelloRequest").msgclass
|
37
|
-
HelloResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("example.hello_world.HelloResponse").msgclass
|
38
|
-
end
|
39
|
-
end
|