proto_plugin 0.1.0 → 0.3.0
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/README.md +7 -2
- data/exe/protoc-gen-proto-plugin-demo +6 -4
- data/lib/proto_plugin/base.rb +86 -2
- data/lib/proto_plugin/context.rb +59 -0
- data/lib/proto_plugin/enum_descriptor.rb +49 -0
- data/lib/proto_plugin/file_descriptor.rb +89 -0
- data/lib/proto_plugin/message_descriptor.rb +74 -0
- data/lib/proto_plugin/method_descriptor.rb +73 -0
- data/lib/proto_plugin/service_descriptor.rb +55 -0
- data/lib/proto_plugin/utils.rb +33 -0
- data/lib/proto_plugin/version.rb +3 -1
- data/lib/proto_plugin.rb +9 -1
- metadata +14 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d119edf1d041fd9838fe8e63e00be22d1e7592dccc95033e094eb65b282913e3
|
4
|
+
data.tar.gz: cf6966a0c8afebfc1c573ee75151e3c494cfd8400d873d374cfecc0d45e1c8bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3dabe171b0c94f545334b1741b3eb7512a3351888f4079b4ccde46a55be9f7ed4123d6c189252f65d41f80ef695523d098870df3aa0b48c6568bca87956e7dd1
|
7
|
+
data.tar.gz: 2716675a6bfc4afccbe8eb743b3158338cb74e3177a5d1a053cd5e31473524c8a943508dc57a9a8839fc043f7dbea2763f9005052cf0ff66a0c51b04fecd7075
|
data/README.md
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
gem install proto_plugin
|
11
11
|
```
|
12
12
|
|
13
|
-
##
|
13
|
+
## Getting Started
|
14
14
|
|
15
15
|
Creating a `protoc` plugin is as simple as creating a new executable script.
|
16
16
|
|
@@ -24,7 +24,7 @@ require "proto_plugin"
|
|
24
24
|
class MyCoolPlugin < ProtoPlugin::Base
|
25
25
|
def run
|
26
26
|
request.file_to_generate.each do |f|
|
27
|
-
name = File.basename(f, ".proto")
|
27
|
+
name = File.basename(f.name, ".proto")
|
28
28
|
|
29
29
|
add_file(name: "#{name}.txt", content: <<~TXT)
|
30
30
|
This file was generated from #{name}.proto!
|
@@ -36,6 +36,11 @@ end
|
|
36
36
|
MyCoolPlugin.run!
|
37
37
|
```
|
38
38
|
|
39
|
+
> [!TIP]
|
40
|
+
> For more details on the available API, see the docs: https://cocoahero.github.io/proto_plugin
|
41
|
+
|
42
|
+
### Usage
|
43
|
+
|
39
44
|
To invoke the plugin, first make sure you have `protoc` [installed](https://github.com/protocolbuffers/protobuf#protobuf-compiler-installation). Then in a terminal, run:
|
40
45
|
|
41
46
|
```bash
|
@@ -5,10 +5,12 @@ require "proto_plugin"
|
|
5
5
|
|
6
6
|
class Demo < ProtoPlugin::Base
|
7
7
|
def run
|
8
|
-
|
9
|
-
name = File.basename(f, ".proto")
|
10
|
-
add_file(
|
11
|
-
|
8
|
+
files_to_generate.each do |f|
|
9
|
+
name = File.basename(f.name, ".proto")
|
10
|
+
add_file(path: "#{name}.txt", content: <<~TXT)
|
11
|
+
Parameters: #{parameters}
|
12
|
+
|
13
|
+
This file was generated from #{f.name}!
|
12
14
|
TXT
|
13
15
|
end
|
14
16
|
end
|
data/lib/proto_plugin/base.rb
CHANGED
@@ -4,8 +4,31 @@ require "google/protobuf"
|
|
4
4
|
require "google/protobuf/plugin_pb"
|
5
5
|
|
6
6
|
module ProtoPlugin
|
7
|
+
# The primary base class to inherit from when implementing a plugin.
|
8
|
+
#
|
9
|
+
# ```ruby
|
10
|
+
# require 'proto_plugin'
|
11
|
+
#
|
12
|
+
# class MyCoolPlugin < ProtoPlugin::Base
|
13
|
+
# def run
|
14
|
+
# # override to provide your implementation
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# MyCoolPlugin.run!
|
19
|
+
# ````
|
20
|
+
# @abstract
|
7
21
|
class Base
|
8
22
|
class << self
|
23
|
+
##
|
24
|
+
# The preferred way of invoking a plugin.
|
25
|
+
#
|
26
|
+
# Decodes a `Google::Protobuf::Compiler::CodeGeneratorRequest` message
|
27
|
+
# from `input:`, invokes the plugin by calling `#run`, and then encodes
|
28
|
+
# `response` to the stream specified by `output:`.
|
29
|
+
#
|
30
|
+
# @param input [IO] The stream that the request is decoded from.
|
31
|
+
# @param output [IO] The stream that the response is encoded to.
|
9
32
|
def run!(input: $stdin, output: $stdout)
|
10
33
|
plugin = new(
|
11
34
|
request: Google::Protobuf::Compiler::CodeGeneratorRequest.decode(
|
@@ -21,27 +44,88 @@ module ProtoPlugin
|
|
21
44
|
end
|
22
45
|
end
|
23
46
|
|
47
|
+
# The request message the plugin was initialized with.
|
48
|
+
# @return [Google::Protobuf::Compiler::CodeGeneratorRequest]
|
24
49
|
attr_reader :request
|
25
50
|
|
51
|
+
# The context for the current invocation of the plugin.
|
52
|
+
# @return [Context]
|
53
|
+
attr_reader :context
|
54
|
+
|
55
|
+
# The response message to be sent back to `protoc`.
|
56
|
+
# @return [Google::Protobuf::Compiler::CodeGeneratorResponse]
|
26
57
|
attr_reader :response
|
27
58
|
|
59
|
+
# Initializes a new instance of the plugin with a given
|
60
|
+
# `Google::Protobuf::Compiler::CodeGeneratorRequest`.
|
28
61
|
def initialize(request:)
|
29
62
|
@request = request
|
63
|
+
@context = Context.new(request: request)
|
30
64
|
@response = Google::Protobuf::Compiler::CodeGeneratorResponse.new(
|
31
65
|
supported_features: supported_features.reduce(&:|),
|
32
66
|
)
|
33
67
|
end
|
34
68
|
|
69
|
+
# Convenience method for accessing the parameters passed to the plugin.
|
70
|
+
#
|
71
|
+
# @example `protoc --myplugin_opt=key=value --myplugin_opt=bare`
|
72
|
+
# {"key" => "value", "bare" => nil}
|
73
|
+
#
|
74
|
+
# @return [Hash]
|
75
|
+
def parameters
|
76
|
+
@parameters ||= request.parameter&.split(",")&.each_with_object({}) do |param, hash|
|
77
|
+
key, value = param.split("=")
|
78
|
+
hash[key] = value
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns an array of `ProtoPlugin::FileDescriptor` representing the files that
|
83
|
+
# were passed to `protoc` to be generated.
|
84
|
+
#
|
85
|
+
# @example `protoc --myplugin_out=. input_one.proto input_two.proto`
|
86
|
+
# [
|
87
|
+
# <ProtoPlugin::FileDescriptor: name: "input_one.proto">,
|
88
|
+
# <ProtoPlugin::FileDescriptor: name: "input_two.proto">
|
89
|
+
# ]
|
90
|
+
#
|
91
|
+
# @return [Array<FileDescriptor>]
|
92
|
+
def files_to_generate
|
93
|
+
@files_to_generate ||= request.file_to_generate.filter_map do |filename|
|
94
|
+
lookup_file(name: filename)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Finds an imported file descriptor with the given `name` attribute.
|
99
|
+
#
|
100
|
+
# @return [ProtoPlugin::FileDescriptor]
|
101
|
+
# @return [nil] if the file was not found
|
102
|
+
def lookup_file(name:)
|
103
|
+
context.file_by_filename(name)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns the list of supported `CodeGeneratorResponse::Feature` values by the plugin. The returned
|
107
|
+
# values are bitwise or-ed together and set on `response`.
|
108
|
+
#
|
109
|
+
# Defaults to `CodeGeneratorResponse::Feature::FEATURE_NONE`.
|
35
110
|
def supported_features
|
36
111
|
[Google::Protobuf::Compiler::CodeGeneratorResponse::Feature::FEATURE_NONE]
|
37
112
|
end
|
38
113
|
|
39
|
-
|
114
|
+
# Convenience method for appending a `CodeGeneratorResponse::File` message to `response`.
|
115
|
+
#
|
116
|
+
# The path is relative to the directory specified when invoking `protoc`. For example,
|
117
|
+
# specifiying `--myplugin_out=gen` will result in `gen/:path`.
|
118
|
+
#
|
119
|
+
# @param path [String] The relative path to write the file's content.
|
120
|
+
# @param content [String] The content which will be written to the file.
|
121
|
+
def add_file(path:, content:)
|
40
122
|
@response.file << Google::Protobuf::Compiler::CodeGeneratorResponse::File.new(
|
41
|
-
name:
|
123
|
+
name: path, content: content,
|
42
124
|
)
|
43
125
|
end
|
44
126
|
|
127
|
+
# The primary entrypoint. Override to provide your plugin's implementation.
|
128
|
+
# @abstract
|
45
129
|
def run
|
46
130
|
end
|
47
131
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ProtoPlugin
|
4
|
+
# An object that is responsible for organizing the graph of imported descriptors for
|
5
|
+
# a given invocation of a plugin.
|
6
|
+
#
|
7
|
+
# It provides many helpers for looking up a file, message, or other descriptor.
|
8
|
+
class Context
|
9
|
+
# Initializes a context from a given `Google::Protobuf::Compiler::CodeGeneratorRequest`.
|
10
|
+
def initialize(request:)
|
11
|
+
index_files_by_filename(request.proto_file)
|
12
|
+
index_types_by_proto_name
|
13
|
+
end
|
14
|
+
|
15
|
+
# Finds an imported file descriptor with the given `name` attribute.
|
16
|
+
#
|
17
|
+
# @return [ProtoPlugin::FileDescriptor]
|
18
|
+
# @return [nil] if the file was not found
|
19
|
+
def file_by_filename(name)
|
20
|
+
@files_by_filename[name]
|
21
|
+
end
|
22
|
+
|
23
|
+
def type_by_proto_name(name)
|
24
|
+
@types_by_proto_name[name]
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def index_files_by_filename(files)
|
30
|
+
@files_by_filename = files.each_with_object({}) do |fd, hash|
|
31
|
+
hash[fd.name] = FileDescriptor.new(self, fd)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def index_types_by_proto_name
|
36
|
+
@types_by_proto_name = @files_by_filename.values.each_with_object({}) do |fd, hash|
|
37
|
+
package = fd.package || ""
|
38
|
+
package = ".#{package}" unless package.empty?
|
39
|
+
index_enums_by_name(fd.enums, hash, prefix: package)
|
40
|
+
index_messages_by_name(fd.messages, hash, prefix: package)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def index_enums_by_name(enums, hash, prefix:)
|
45
|
+
enums.each do |e|
|
46
|
+
hash["#{prefix}.#{e.name}"] = e
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def index_messages_by_name(msgs, hash, prefix:)
|
51
|
+
msgs.each do |m|
|
52
|
+
path = "#{prefix}.#{m.name}"
|
53
|
+
index_enums_by_name(m.enums, hash, prefix: path)
|
54
|
+
index_messages_by_name(m.messages, hash, prefix: path)
|
55
|
+
hash[path] = m
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "delegate"
|
4
|
+
|
5
|
+
module ProtoPlugin
|
6
|
+
# A wrapper class around `Google::Protobuf::EnumDescriptorProto`
|
7
|
+
# which provides helpers and more idiomatic Ruby access patterns.
|
8
|
+
#
|
9
|
+
# Any method not defined directly is delegated to the descriptor the wrapper was initialized with.
|
10
|
+
#
|
11
|
+
# @see https://github.com/protocolbuffers/protobuf/blob/v28.2/src/google/protobuf/descriptor.proto#L336
|
12
|
+
class EnumDescriptor < SimpleDelegator
|
13
|
+
# @return [Google::Protobuf::EnumDescriptorProto]
|
14
|
+
attr_reader :descriptor
|
15
|
+
|
16
|
+
# The file or message descriptor this enum was defined within.
|
17
|
+
#
|
18
|
+
# @return [FileDescriptor] if defined as a root enum
|
19
|
+
# @return [MessageDescriptor] if defined as a nested enum (inverse of `enum_type`)
|
20
|
+
attr_reader :parent
|
21
|
+
|
22
|
+
# @param descriptor [Google::Protobuf::EnumDescriptorProto]
|
23
|
+
# @param parent [FileDescriptorFileDescriptorProto, MessageDescriptor]
|
24
|
+
# The file or message descriptor this enum was defined within.
|
25
|
+
def initialize(descriptor, parent)
|
26
|
+
super(descriptor)
|
27
|
+
@descriptor = descriptor
|
28
|
+
@parent = parent
|
29
|
+
end
|
30
|
+
|
31
|
+
# The full name of the enum, including parent namespace.
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# "My::Ruby::Package::EnumName"
|
35
|
+
#
|
36
|
+
# @return [String]
|
37
|
+
def full_name
|
38
|
+
@full_name ||= begin
|
39
|
+
prefix = case parent
|
40
|
+
when MessageDescriptor
|
41
|
+
parent.full_name
|
42
|
+
when FileDescriptor
|
43
|
+
parent.namespace
|
44
|
+
end
|
45
|
+
"#{prefix}::#{name}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "delegate"
|
4
|
+
|
5
|
+
module ProtoPlugin
|
6
|
+
# A wrapper class around `Google::Protobuf::FileDescriptorProto`
|
7
|
+
# which provides helpers and more idiomatic Ruby access patterns.
|
8
|
+
#
|
9
|
+
# Any method not defined directly is delegated to the descriptor the wrapper was initialized with.
|
10
|
+
#
|
11
|
+
# @see https://github.com/protocolbuffers/protobuf/blob/v28.2/src/google/protobuf/descriptor.proto#L97
|
12
|
+
# Google::Protobuf::FileDescriptorProto
|
13
|
+
class FileDescriptor < SimpleDelegator
|
14
|
+
# @return [Google::Protobuf::FileDescriptorProto]
|
15
|
+
attr_reader :descriptor
|
16
|
+
|
17
|
+
# @param context [Context]
|
18
|
+
# @param descriptor [Google::Protobuf::FileDescriptorProto]
|
19
|
+
def initialize(context, descriptor)
|
20
|
+
super(descriptor)
|
21
|
+
@context = context
|
22
|
+
@descriptor = descriptor
|
23
|
+
end
|
24
|
+
|
25
|
+
# The enums defined as children of this file.
|
26
|
+
#
|
27
|
+
# @return [Array<EnumDescriptor>]
|
28
|
+
#
|
29
|
+
# @see https://github.com/protocolbuffers/protobuf/blob/v28.2/src/google/protobuf/descriptor.proto#L111
|
30
|
+
# Google::Protobuf::DescriptorProto#enum_type
|
31
|
+
def enums
|
32
|
+
@enums ||= @descriptor.enum_type.map do |e|
|
33
|
+
EnumDescriptor.new(e, self)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# The messages defined as children of this file.
|
38
|
+
#
|
39
|
+
# @return [Array<MessageDescriptor>]
|
40
|
+
#
|
41
|
+
# @see https://github.com/protocolbuffers/protobuf/blob/v28.2/src/google/protobuf/descriptor.proto#L110
|
42
|
+
# Google::Protobuf::DescriptorProto#message_type
|
43
|
+
def messages
|
44
|
+
@messages ||= @descriptor.message_type.map do |m|
|
45
|
+
MessageDescriptor.new(m, self)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns the Ruby namespace (module) for the file.
|
50
|
+
#
|
51
|
+
# If the `ruby_package` option was specified, then that value
|
52
|
+
# is returned directly. Otherwise, the `package` value is
|
53
|
+
# transformed to Ruby module notation.
|
54
|
+
#
|
55
|
+
# @example Using `package my.protobuf.package;`
|
56
|
+
# file.namespace #=> "My::Protobuf::Package"
|
57
|
+
# @example Using `option ruby_package = "My::Ruby::Package";`
|
58
|
+
# file.namespace #=> "My::Ruby::Package"
|
59
|
+
#
|
60
|
+
# @param split [Boolean] Returns the namespace as an array of module names.
|
61
|
+
#
|
62
|
+
# @return [String] The namespace for the file.
|
63
|
+
# @return [Array<String>] If `split: true`, the namespace as an array of module names.
|
64
|
+
def namespace(split: false)
|
65
|
+
@namespace ||= begin
|
66
|
+
namespace = @descriptor.options&.ruby_package
|
67
|
+
if !namespace || namespace.empty?
|
68
|
+
namespace = @descriptor.package.split(".")
|
69
|
+
.map { |token| Utils.camelize(token) }
|
70
|
+
.join("::")
|
71
|
+
end
|
72
|
+
namespace
|
73
|
+
end
|
74
|
+
split ? @namespace.split("::") : @namespace
|
75
|
+
end
|
76
|
+
|
77
|
+
# The services defined in this file.
|
78
|
+
#
|
79
|
+
# @return [Array<ServiceDescriptor>]
|
80
|
+
#
|
81
|
+
# @see https://github.com/protocolbuffers/protobuf/blob/v28.2/src/google/protobuf/descriptor.proto#L112
|
82
|
+
# Google::Protobuf::DescriptorProto#service
|
83
|
+
def services
|
84
|
+
@services ||= @descriptor.service.map do |s|
|
85
|
+
ServiceDescriptor.new(s, self, @context)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "delegate"
|
4
|
+
|
5
|
+
module ProtoPlugin
|
6
|
+
# A wrapper class around `Google::Protobuf::DescriptorProto`
|
7
|
+
# which provides helpers and more idiomatic Ruby access patterns.
|
8
|
+
#
|
9
|
+
# Any method not defined directly is delegated to the descriptor the wrapper was initialized with.
|
10
|
+
#
|
11
|
+
# @see https://github.com/protocolbuffers/protobuf/blob/v28.2/src/google/protobuf/descriptor.proto#L134
|
12
|
+
# Google::Protobuf::DescriptorProto
|
13
|
+
class MessageDescriptor < SimpleDelegator
|
14
|
+
# @return [Google::Protobuf::DescriptorProto]
|
15
|
+
attr_reader :descriptor
|
16
|
+
|
17
|
+
# The file or message descriptor this message was defined within.
|
18
|
+
#
|
19
|
+
# @return [FileDescriptor] if defined as a root message
|
20
|
+
# @return [MessageDescriptor] if defined as a nested message (inverse of `nested_type`)
|
21
|
+
attr_reader :parent
|
22
|
+
|
23
|
+
# @param descriptor [Google::Protobuf::DescriptorProto]
|
24
|
+
# @param parent [FileDescriptorFileDescriptorProto, MessageDescriptor]
|
25
|
+
# The file or message descriptor this message was defined within.
|
26
|
+
def initialize(descriptor, parent)
|
27
|
+
super(descriptor)
|
28
|
+
@descriptor = descriptor
|
29
|
+
@parent = parent
|
30
|
+
end
|
31
|
+
|
32
|
+
# The enums defined as children of this message.
|
33
|
+
#
|
34
|
+
# @return [Array<EnumDescriptor>]
|
35
|
+
#
|
36
|
+
# @see https://github.com/protocolbuffers/protobuf/blob/v28.2/src/google/protobuf/descriptor.proto#L141
|
37
|
+
# Google::Protobuf::DescriptorProto#enum_type
|
38
|
+
def enums
|
39
|
+
@enums ||= @descriptor.enum_type.map do |e|
|
40
|
+
EnumDescriptor.new(e, self)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# The messages defined as children of this message.
|
45
|
+
#
|
46
|
+
# @return [Array<MessageDescriptor>]
|
47
|
+
#
|
48
|
+
# @see https://github.com/protocolbuffers/protobuf/blob/v28.2/src/google/protobuf/descriptor.proto#L140
|
49
|
+
# Google::Protobuf::DescriptorProto#nested_type
|
50
|
+
def messages
|
51
|
+
@nested_messages ||= @descriptor.nested_type.map do |m|
|
52
|
+
MessageDescriptor.new(m, self)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# The full name of the message, including parent namespace.
|
57
|
+
#
|
58
|
+
# @example
|
59
|
+
# "My::Ruby::Package::MessageName"
|
60
|
+
#
|
61
|
+
# @return [String]
|
62
|
+
def full_name
|
63
|
+
@full_name ||= begin
|
64
|
+
prefix = case parent
|
65
|
+
when MessageDescriptor
|
66
|
+
parent.full_name
|
67
|
+
when FileDescriptor
|
68
|
+
parent.namespace
|
69
|
+
end
|
70
|
+
"#{prefix}::#{name}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "delegate"
|
4
|
+
|
5
|
+
module ProtoPlugin
|
6
|
+
# A wrapper class around `Google::Protobuf::MethodDescriptorProto`
|
7
|
+
# which provides helpers and more idiomatic Ruby access patterns.
|
8
|
+
#
|
9
|
+
# Any method not defined directly is delegated to the descriptor the wrapper was initialized with.
|
10
|
+
#
|
11
|
+
# @see https://github.com/protocolbuffers/protobuf/blob/v28.2/src/google/protobuf/descriptor.proto#L381
|
12
|
+
class MethodDescriptor < SimpleDelegator
|
13
|
+
# @return [Google::Protobuf::MethodDescriptorProto]
|
14
|
+
attr_reader :descriptor
|
15
|
+
|
16
|
+
# The service this method was defined in.
|
17
|
+
#
|
18
|
+
# @return [ServiceDescriptor]
|
19
|
+
attr_reader :service
|
20
|
+
|
21
|
+
# @param descriptor [Google::Protobuf::MethodDescriptorProto]
|
22
|
+
# @param service [ServiceDescriptor] The service this method was defined in.
|
23
|
+
# @param context [Context]
|
24
|
+
def initialize(descriptor, service, context)
|
25
|
+
super(descriptor)
|
26
|
+
@descriptor = descriptor
|
27
|
+
@service = service
|
28
|
+
@context = context
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the `MessageDescriptor` of the method's input type.
|
32
|
+
#
|
33
|
+
# @return [MessageDescriptor]
|
34
|
+
def input
|
35
|
+
@context.type_by_proto_name(input_type)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns the `MessageDescriptor` of the method's output type.
|
39
|
+
#
|
40
|
+
# @return [MessageDescriptor]
|
41
|
+
def output
|
42
|
+
@context.type_by_proto_name(output_type)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns true if the client may stream multiple client messages.
|
46
|
+
#
|
47
|
+
# @return [Boolean]
|
48
|
+
def client_streaming?
|
49
|
+
descriptor.client_streaming
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns true if the server may stream multiple server messages.
|
53
|
+
#
|
54
|
+
# @return [Boolean]
|
55
|
+
def server_streaming?
|
56
|
+
descriptor.server_streaming
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns true if both the client and server only may send single messages.
|
60
|
+
#
|
61
|
+
# @return [Boolean]
|
62
|
+
def unary?
|
63
|
+
!client_streaming? && !server_streaming?
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns true if both the client and server may send multiple streamed messages.
|
67
|
+
#
|
68
|
+
# @return [Boolean]
|
69
|
+
def bidirectional_streaming?
|
70
|
+
client_streaming? && server_streaming?
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "delegate"
|
4
|
+
|
5
|
+
module ProtoPlugin
|
6
|
+
# A wrapper class around `Google::Protobuf::ServiceDescriptorProto`
|
7
|
+
# which provides helpers and more idiomatic Ruby access patterns.
|
8
|
+
#
|
9
|
+
# Any method not defined directly is delegated to the descriptor the wrapper was initialized with.
|
10
|
+
#
|
11
|
+
# @see https://github.com/protocolbuffers/protobuf/blob/v28.2/src/google/protobuf/descriptor.proto#L373
|
12
|
+
class ServiceDescriptor < SimpleDelegator
|
13
|
+
# @return [Google::Protobuf::ServiceDescriptorProto]
|
14
|
+
attr_reader :descriptor
|
15
|
+
|
16
|
+
# The file this service was defined within.
|
17
|
+
#
|
18
|
+
# @return [FileDescriptor]
|
19
|
+
attr_reader :parent
|
20
|
+
|
21
|
+
# @param descriptor [Google::Protobuf::ServiceDescriptorProto]
|
22
|
+
# @param parent [FileDescriptor] The file this service was defined within.
|
23
|
+
# @param context [Context]
|
24
|
+
def initialize(descriptor, parent, context)
|
25
|
+
super(descriptor)
|
26
|
+
@descriptor = descriptor
|
27
|
+
@parent = parent
|
28
|
+
@context = context
|
29
|
+
end
|
30
|
+
|
31
|
+
# The full name of the service, including parent namespace.
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# "My::Ruby::Package::ServiceName"
|
35
|
+
#
|
36
|
+
# @return [String]
|
37
|
+
def full_name
|
38
|
+
@full_name ||= "#{parent.namespace}::#{name}"
|
39
|
+
end
|
40
|
+
|
41
|
+
# The methods defined for the service.
|
42
|
+
#
|
43
|
+
# @note This method is named `rpc_methods` to avoid conflicting with Object#methods.
|
44
|
+
#
|
45
|
+
# @return [Array<MethodDescriptor>]
|
46
|
+
#
|
47
|
+
# @see https://github.com/protocolbuffers/protobuf/blob/v28.2/src/google/protobuf/descriptor.proto#L375
|
48
|
+
# Google::Protobuf::ServiceDescriptorProto#method
|
49
|
+
def rpc_methods
|
50
|
+
@rpc_methods ||= @descriptor["method"].map do |m|
|
51
|
+
MethodDescriptor.new(m, self, @context)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ProtoPlugin
|
4
|
+
# A set of utility functions used by the library.
|
5
|
+
module Utils
|
6
|
+
class << self
|
7
|
+
# Converts string to UpperCamelCase.
|
8
|
+
#
|
9
|
+
# @param value [String]
|
10
|
+
#
|
11
|
+
# @return [String]
|
12
|
+
def camelize(value)
|
13
|
+
string = value.to_s
|
14
|
+
|
15
|
+
if string.match?(/\A[a-z\d]*\z/)
|
16
|
+
return string.capitalize
|
17
|
+
else
|
18
|
+
string = string.sub(/^[a-z\d]*/) do |match|
|
19
|
+
match.capitalize! || match
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
string.gsub!(%r{(?:_|(/))([a-z\d]*)}i) do
|
24
|
+
word = ::Regexp.last_match(2)
|
25
|
+
substituted = word.capitalize! || word
|
26
|
+
::Regexp.last_match(1) ? "::#{substituted}" : substituted
|
27
|
+
end
|
28
|
+
|
29
|
+
string
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/proto_plugin/version.rb
CHANGED
data/lib/proto_plugin.rb
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# Easily build protobuf compiler plugins in Ruby.
|
3
4
|
module ProtoPlugin
|
4
5
|
end
|
5
6
|
|
6
|
-
require_relative "proto_plugin/
|
7
|
+
require_relative "proto_plugin/utils"
|
8
|
+
require_relative "proto_plugin/context"
|
9
|
+
require_relative "proto_plugin/file_descriptor"
|
10
|
+
require_relative "proto_plugin/enum_descriptor"
|
11
|
+
require_relative "proto_plugin/message_descriptor"
|
12
|
+
require_relative "proto_plugin/service_descriptor"
|
13
|
+
require_relative "proto_plugin/method_descriptor"
|
7
14
|
require_relative "proto_plugin/base"
|
15
|
+
require_relative "proto_plugin/version"
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: proto_plugin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Baker
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-02-27 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: google-protobuf
|
@@ -24,7 +23,6 @@ dependencies:
|
|
24
23
|
- - "~>"
|
25
24
|
- !ruby/object:Gem::Version
|
26
25
|
version: '4.28'
|
27
|
-
description:
|
28
26
|
email:
|
29
27
|
- jonathan@jmb.dev
|
30
28
|
executables:
|
@@ -37,6 +35,13 @@ files:
|
|
37
35
|
- exe/protoc-gen-proto-plugin-demo
|
38
36
|
- lib/proto_plugin.rb
|
39
37
|
- lib/proto_plugin/base.rb
|
38
|
+
- lib/proto_plugin/context.rb
|
39
|
+
- lib/proto_plugin/enum_descriptor.rb
|
40
|
+
- lib/proto_plugin/file_descriptor.rb
|
41
|
+
- lib/proto_plugin/message_descriptor.rb
|
42
|
+
- lib/proto_plugin/method_descriptor.rb
|
43
|
+
- lib/proto_plugin/service_descriptor.rb
|
44
|
+
- lib/proto_plugin/utils.rb
|
40
45
|
- lib/proto_plugin/version.rb
|
41
46
|
homepage: https://github.com/cocoahero/proto_plugin
|
42
47
|
licenses:
|
@@ -44,8 +49,9 @@ licenses:
|
|
44
49
|
metadata:
|
45
50
|
homepage_uri: https://github.com/cocoahero/proto_plugin
|
46
51
|
source_code_uri: https://github.com/cocoahero/proto_plugin
|
52
|
+
documentation_uri: https://cocoahero.github.io/proto_plugin
|
47
53
|
allowed_push_host: https://rubygems.org
|
48
|
-
|
54
|
+
funding_uri: https://github.com/sponsors/cocoahero
|
49
55
|
rdoc_options: []
|
50
56
|
require_paths:
|
51
57
|
- lib
|
@@ -53,15 +59,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
53
59
|
requirements:
|
54
60
|
- - "~>"
|
55
61
|
- !ruby/object:Gem::Version
|
56
|
-
version: '3.
|
62
|
+
version: '3.1'
|
57
63
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
64
|
requirements:
|
59
65
|
- - ">="
|
60
66
|
- !ruby/object:Gem::Version
|
61
67
|
version: '0'
|
62
68
|
requirements: []
|
63
|
-
rubygems_version: 3.
|
64
|
-
signing_key:
|
69
|
+
rubygems_version: 3.6.2
|
65
70
|
specification_version: 4
|
66
|
-
summary: Easily build
|
71
|
+
summary: Easily build protobuf compiler plugins in Ruby.
|
67
72
|
test_files: []
|