protod 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.bundle/config +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +585 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +165 -0
- data/LICENSE.txt +21 -0
- data/README.md +37 -0
- data/Rakefile +12 -0
- data/lib/generators/protod/gruf_generator.rb +43 -0
- data/lib/generators/protod/task_generator.rb +23 -0
- data/lib/protod/configuration.rb +78 -0
- data/lib/protod/interpreter/active_record.rb +161 -0
- data/lib/protod/interpreter/builtin.rb +328 -0
- data/lib/protod/interpreter/rpc.rb +206 -0
- data/lib/protod/interpreter.rb +180 -0
- data/lib/protod/proto/builder.rb +70 -0
- data/lib/protod/proto/features.rb +32 -0
- data/lib/protod/proto/field.rb +88 -0
- data/lib/protod/proto/message.rb +95 -0
- data/lib/protod/proto/oneof.rb +46 -0
- data/lib/protod/proto/package.rb +120 -0
- data/lib/protod/proto/part.rb +191 -0
- data/lib/protod/proto/procedure.rb +42 -0
- data/lib/protod/proto/service.rb +42 -0
- data/lib/protod/protocol_buffers.rb +46 -0
- data/lib/protod/rake_task.rb +91 -0
- data/lib/protod/rpc/handler.rb +114 -0
- data/lib/protod/rpc/request.rb +68 -0
- data/lib/protod/rpc/response.rb +68 -0
- data/lib/protod/ruby_ident.rb +49 -0
- data/lib/protod/version.rb +5 -0
- data/lib/protod.rb +103 -0
- data/sig/protod.rbs +4 -0
- metadata +136 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Protod
|
4
|
+
module Proto
|
5
|
+
class Service < Part
|
6
|
+
include Findable
|
7
|
+
|
8
|
+
attribute :procedures, default: -> { [] }
|
9
|
+
|
10
|
+
findable_callback_for(:procedure, key: %i[ident ruby_ident ruby_method_name]) do |key, value|
|
11
|
+
@procedure_map ? @procedure_map.fetch(key)[value] : procedures.find { _1.public_send(key) == value }
|
12
|
+
end
|
13
|
+
|
14
|
+
def ruby_ident
|
15
|
+
ident.const_name
|
16
|
+
end
|
17
|
+
|
18
|
+
def pb_const
|
19
|
+
parent.pb_const.const_get(ident).const_get('Service')
|
20
|
+
end
|
21
|
+
|
22
|
+
def freeze
|
23
|
+
procedures.each { _1.depth = depth + 1 }
|
24
|
+
procedures.each.with_index(1) { |p, i| p.index = i }
|
25
|
+
|
26
|
+
@procedure_map = self.class.findable_keys_for(:procedure).index_with { |k| procedures.index_by(&k.to_sym) }
|
27
|
+
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_proto
|
32
|
+
procedure_part = procedures.map { _1.to_proto }.join("\n").presence
|
33
|
+
procedure_part = "\n#{procedure_part}\n" if procedure_part
|
34
|
+
|
35
|
+
[
|
36
|
+
format_proto("service %s {%s", ident, procedure_part),
|
37
|
+
format_proto("}")
|
38
|
+
].join
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
Protod.setup!
|
2
|
+
|
3
|
+
pb_dir = File.absolute_path(Protod.configuration.pb_root_dir)
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
|
6
|
+
|
7
|
+
Protod::Proto::Package.roots.flat_map(&:all_packages)
|
8
|
+
.reject(&:external?)
|
9
|
+
.reject { _1.services.blank? }
|
10
|
+
.each do |package|
|
11
|
+
dirs = package.full_ident.split('.')
|
12
|
+
file = dirs.pop
|
13
|
+
|
14
|
+
require Pathname.new(pb_dir).join(*dirs, "#{file}_services_pb")
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'google/protobuf/well_known_types'
|
18
|
+
|
19
|
+
class Protod
|
20
|
+
module ProtocolBuffers
|
21
|
+
module GoogleProtobufStructStringified
|
22
|
+
def from_hash(hash)
|
23
|
+
super(hash.stringify_keys)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module GoogleProtobufValueStringified
|
28
|
+
def from_ruby(value)
|
29
|
+
case value
|
30
|
+
when ::Symbol
|
31
|
+
self.string_value = value.to_s
|
32
|
+
else
|
33
|
+
super(value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Google::Protobuf::Struct
|
41
|
+
class << self
|
42
|
+
prepend Protod::ProtocolBuffers::GoogleProtobufStructStringified
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Google::Protobuf::Value.prepend Protod::ProtocolBuffers::GoogleProtobufValueStringified
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/tasklib'
|
3
|
+
|
4
|
+
class Protod
|
5
|
+
class RakeTask < Rake::TaskLib
|
6
|
+
class Builder
|
7
|
+
attr_accessor :name
|
8
|
+
|
9
|
+
def initialize(&body)
|
10
|
+
body&.call(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
def build
|
14
|
+
Protod::RakeTask.new(**{ name: name }.compact)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(name: :protod)
|
19
|
+
super()
|
20
|
+
|
21
|
+
@name = name
|
22
|
+
|
23
|
+
define_generate_proto_task
|
24
|
+
define_generate_pb_task
|
25
|
+
define_run_gruf
|
26
|
+
end
|
27
|
+
|
28
|
+
def define_generate_proto_task
|
29
|
+
desc 'Generate proto files'
|
30
|
+
task("#{@name}:generate:proto": :environment) do
|
31
|
+
Protod.setup!
|
32
|
+
|
33
|
+
root = Pathname.new(Protod.configuration.proto_root_dir)
|
34
|
+
|
35
|
+
Protod::Proto::Package.roots.flat_map { _1.all_packages.reject(&:external?).reject(&:empty?) }.each do |package|
|
36
|
+
path = root.join(*package.full_ident.split('.').tap { _1.last << '.proto' })
|
37
|
+
|
38
|
+
FileUtils.mkdir_p(path.parent) unless File.exist?(path.parent)
|
39
|
+
|
40
|
+
puts "Start to generate #{path} ..."
|
41
|
+
File.write(path, package.to_proto)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def define_generate_pb_task
|
47
|
+
desc 'Generate protocol buffers files'
|
48
|
+
task("#{@name}:generate:pb": :environment) do
|
49
|
+
Protod.setup!
|
50
|
+
|
51
|
+
proto_dir = Pathname.new(Protod.configuration.proto_root_dir)
|
52
|
+
pb_dir = File.absolute_path(Pathname.new(Protod.configuration.pb_root_dir))
|
53
|
+
|
54
|
+
FileUtils.mkdir_p(pb_dir) unless File.exist?(pb_dir)
|
55
|
+
|
56
|
+
Dir.mktmpdir do |dir|
|
57
|
+
dir = Pathname(dir)
|
58
|
+
|
59
|
+
Protod::Proto::Package.roots.flat_map(&:all_packages).filter { _1.url.present? }.each.with_index(1) do |package, i|
|
60
|
+
args = [package.url, dir.join("_ext#{i}_#{package.url.split('/').last}")]
|
61
|
+
options = { depth: 1, branch: package.branch }.compact
|
62
|
+
|
63
|
+
option_part = options.map { |k, v| "--#{k} #{v}" }.join(' ')
|
64
|
+
arg_part = args.map { Shellwords.shellescape(_1) }.join(' ')
|
65
|
+
cmd = "git clone #{option_part} #{arg_part}"
|
66
|
+
|
67
|
+
puts "#{cmd}"
|
68
|
+
system(cmd) or raise "Failed to generate pb!"
|
69
|
+
end
|
70
|
+
|
71
|
+
include_option = Dir.glob("#{dir}/*").map { "-I#{_1}" }.join(' ')
|
72
|
+
cmd = "bundle exec grpc_tools_ruby_protoc #{include_option} -I#{proto_dir} --ruby_out=#{pb_dir} --grpc_out=#{pb_dir} `find #{proto_dir} -type f -name '*.proto'`"
|
73
|
+
|
74
|
+
puts "#{cmd}"
|
75
|
+
system(cmd) or raise "Failed to generate pb!"
|
76
|
+
end
|
77
|
+
|
78
|
+
puts "Finished to generate pb."
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def define_run_gruf
|
83
|
+
desc 'Run gruf'
|
84
|
+
task("#{@name}:gruf": :environment) do
|
85
|
+
require 'protod/protocol_buffers'
|
86
|
+
|
87
|
+
::Gruf::Cli::Executor.new.run
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
class Protod
|
2
|
+
module Rpc
|
3
|
+
class Handler
|
4
|
+
SERVICE_NAME = 'Handler'
|
5
|
+
PROCEDURE_NAME = 'handle'
|
6
|
+
ONEOF_NAME = 'receiver'
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def build_in(package)
|
10
|
+
package
|
11
|
+
.find_or_push(SERVICE_NAME, by: :ident, into: :services)
|
12
|
+
.find_or_push(Protod::Proto::Procedure.new(ident: PROCEDURE_NAME, streaming_request: true, streaming_response: true), by: :ident, into: :procedures)
|
13
|
+
.tap do |procedure|
|
14
|
+
package
|
15
|
+
.find_or_push(procedure.request_ident, by: :ident, into: :messages)
|
16
|
+
.find_or_push(Protod::Proto::Oneof.new(ident: ONEOF_NAME), by: :ident, into: :fields)
|
17
|
+
|
18
|
+
package
|
19
|
+
.find_or_push(procedure.response_ident, by: :ident, into: :messages)
|
20
|
+
.find_or_push(Protod::Proto::Oneof.new(ident: ONEOF_NAME), by: :ident, into: :fields)
|
21
|
+
end
|
22
|
+
|
23
|
+
new(package)
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_package
|
27
|
+
Protod::Proto::Package.roots.flat_map(&:all_packages).find do
|
28
|
+
_1.find(SERVICE_NAME, by: :ident, as: 'Protod::Proto::Service')
|
29
|
+
&.find(Protod::Proto::Procedure.new(ident: PROCEDURE_NAME), by: :ident)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def find_service_in(package)
|
34
|
+
package.find(Protod::Rpc::Handler::SERVICE_NAME, by: :ident, as: 'Protod::Proto::Service')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(package, logger: ::Logger.new(nil))
|
39
|
+
@package = package
|
40
|
+
@logger = logger
|
41
|
+
|
42
|
+
@procedure = @package
|
43
|
+
.find(SERVICE_NAME, by: :ident, as: 'Protod::Proto::Service')
|
44
|
+
.find(Protod::Proto::Procedure.new(ident: PROCEDURE_NAME), by: :ident)
|
45
|
+
|
46
|
+
@request_receiver_fields = request_proto_message.find(ONEOF_NAME, by: :ident, as: 'Protod::Proto::Oneof')
|
47
|
+
@response_receiver_fields = response_proto_message.find(ONEOF_NAME, by: :ident, as: 'Protod::Proto::Oneof')
|
48
|
+
|
49
|
+
@loaded_objects = {}
|
50
|
+
end
|
51
|
+
|
52
|
+
def request_proto_message
|
53
|
+
@package.find(@procedure.request_ident, by: :ident, as: 'Protod::Proto::Message')
|
54
|
+
end
|
55
|
+
|
56
|
+
def response_proto_message
|
57
|
+
@package.find(@procedure.response_ident, by: :ident, as: 'Protod::Proto::Message')
|
58
|
+
end
|
59
|
+
|
60
|
+
def register_receiver(request_field, response_field)
|
61
|
+
@request_receiver_fields.find_or_push(request_field, by: :ident, into: :fields)
|
62
|
+
@response_receiver_fields.find_or_push(response_field, by: :ident, into: :fields)
|
63
|
+
end
|
64
|
+
|
65
|
+
def handle(req_pb)
|
66
|
+
receiver_name = req_pb.public_send(ONEOF_NAME)
|
67
|
+
|
68
|
+
return unless receiver_name
|
69
|
+
|
70
|
+
req_packet = @request_receiver_fields.find(receiver_name, by: :ident, as: 'Protod::Proto::Field').then do |f|
|
71
|
+
raise InvalidArgument, "Not found acceptable receiver : #{receiver_name}" unless f
|
72
|
+
|
73
|
+
f.interpreter.to_rb_from(req_pb.public_send(receiver_name))
|
74
|
+
end
|
75
|
+
|
76
|
+
receiver = if req_packet.receiver_id
|
77
|
+
@loaded_objects[req_packet.receiver_id.to_s] or raise InvalidArgument, "Invalid object_id in request for #{receiver_name}"
|
78
|
+
else
|
79
|
+
req_packet.receiver
|
80
|
+
end
|
81
|
+
|
82
|
+
raise InvalidArgument, "Not found receiver in request for #{receiver_name}" unless receiver
|
83
|
+
raise InvalidArgument, "Not found #{req_packet.procedure} in receiver public methods for #{receiver_name}" unless receiver.respond_to?(req_packet.procedure)
|
84
|
+
|
85
|
+
@logger.debug("protod/handle call #{receiver_name}##{req_packet.procedure} : #{req_packet.args} #{req_packet.kwargs}")
|
86
|
+
rb = receiver.public_send(req_packet.procedure, *req_packet.args, **req_packet.kwargs)
|
87
|
+
|
88
|
+
memorize_object_id_of(rb)
|
89
|
+
|
90
|
+
res_pb = @response_receiver_fields.find(receiver_name, by: :ident, as: 'Protod::Proto::Field').then do |f|
|
91
|
+
f.interpreter.to_pb_from(ResponsePacket.new(procedure: req_packet.procedure, object: rb))
|
92
|
+
end
|
93
|
+
|
94
|
+
response_pb_const.new(receiver_name.to_sym => res_pb)
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def response_pb_const
|
100
|
+
@response_pb_const ||= @package.find(@procedure.response_ident, by: :ident, as: 'Protod::Proto::Message').pb_const
|
101
|
+
end
|
102
|
+
|
103
|
+
def memorize_object_id_of(value)
|
104
|
+
@loaded_objects[value.object_id.to_s] = value
|
105
|
+
value.each { memorize_object_id_of(_1) } if Protod::Proto::Field.should_repeated_with(value.class)
|
106
|
+
end
|
107
|
+
|
108
|
+
class InvalidArgument < StandardError; end
|
109
|
+
|
110
|
+
RequestPacket = Struct.new(:receiver_id, :receiver, :procedure, :args, :kwargs, keyword_init: true)
|
111
|
+
ResponsePacket = Struct.new(:procedure, :object, keyword_init: true)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class Protod
|
2
|
+
module Rpc
|
3
|
+
class Request
|
4
|
+
class << self
|
5
|
+
def register_for(*ruby_idents, with:, force: true, ignore: false, &body)
|
6
|
+
ruby_idents.map { Protod::RubyIdent.absolute_of(_1) }.each do |ruby_ident|
|
7
|
+
next if map.key?(ruby_ident) && ignore
|
8
|
+
|
9
|
+
raise ArgumentError, "Request already regsitered for #{ruby_ident}" if map.key?(ruby_ident) && !force
|
10
|
+
|
11
|
+
map[ruby_ident] = Class.new(with, &body).tap do |const|
|
12
|
+
const.ruby_ident = Protod::RubyIdent.build_from(ruby_ident)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def find_by(ruby_ident)
|
18
|
+
map[Protod::RubyIdent.absolute_of(ruby_ident)]
|
19
|
+
end
|
20
|
+
|
21
|
+
def keys
|
22
|
+
map.keys
|
23
|
+
end
|
24
|
+
|
25
|
+
def clear!
|
26
|
+
@map = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def map
|
32
|
+
@map ||= {}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Base
|
37
|
+
class_attribute :ruby_ident
|
38
|
+
end
|
39
|
+
|
40
|
+
class Receiver
|
41
|
+
ONEOF_NAME = 'procedure'
|
42
|
+
|
43
|
+
class << self
|
44
|
+
def register_for(*ruby_idents, with: Base, **options, &body)
|
45
|
+
Protod::Rpc::Request.register_for(*ruby_idents, **options.merge(with: with), &body)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Base < Protod::Rpc::Request::Base
|
50
|
+
class_attribute :procedures
|
51
|
+
|
52
|
+
def self.push_procedure(*names, singleton: false)
|
53
|
+
ruby_idents = names.map { Protod::RubyIdent.new(const_name: ruby_ident, method_name: _1, singleton: singleton) }
|
54
|
+
|
55
|
+
Protod::Rpc::Request.register_for(*ruby_idents, with: Protod::Rpc::Request::Base, force: false, ignore: true)
|
56
|
+
|
57
|
+
self.procedures ||= []
|
58
|
+
self.procedures.push(*ruby_idents)
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.procedure_pushed?(name, singleton: false)
|
62
|
+
procedures&.include?(Protod::RubyIdent.new(const_name: ruby_ident, method_name: name, singleton: singleton)) || false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class Protod
|
2
|
+
module Rpc
|
3
|
+
class Response
|
4
|
+
class << self
|
5
|
+
def register_for(*ruby_idents, with:, force: true, ignore: false, &body)
|
6
|
+
ruby_idents.map { Protod::RubyIdent.absolute_of(_1) }.each do |ruby_ident|
|
7
|
+
next if map.key?(ruby_ident) && ignore
|
8
|
+
|
9
|
+
raise ArgumentError, "Response already regsitered for #{ruby_ident}" if map.key?(ruby_ident) && !force
|
10
|
+
|
11
|
+
map[ruby_ident] = Class.new(with, &body).tap do |const|
|
12
|
+
const.ruby_ident = Protod::RubyIdent.build_from(ruby_ident)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def find_by(ruby_ident)
|
18
|
+
map[Protod::RubyIdent.absolute_of(ruby_ident)]
|
19
|
+
end
|
20
|
+
|
21
|
+
def keys
|
22
|
+
map.keys
|
23
|
+
end
|
24
|
+
|
25
|
+
def clear!
|
26
|
+
@map = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def map
|
32
|
+
@map ||= {}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Base
|
37
|
+
class_attribute :ruby_ident
|
38
|
+
end
|
39
|
+
|
40
|
+
class Receiver
|
41
|
+
ONEOF_NAME = 'procedure'
|
42
|
+
|
43
|
+
class << self
|
44
|
+
def register_for(*ruby_idents, with: Base, **options, &body)
|
45
|
+
Protod::Rpc::Response.register_for(*ruby_idents, **options.merge(with: with), &body)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Base < Protod::Rpc::Response::Base
|
50
|
+
class_attribute :procedures
|
51
|
+
|
52
|
+
def self.push_procedure(*names, singleton: false)
|
53
|
+
ruby_idents = names.map { Protod::RubyIdent.new(const_name: ruby_ident, method_name: _1, singleton: singleton) }
|
54
|
+
|
55
|
+
Protod::Rpc::Response.register_for(*ruby_idents.map(&:to_s), with: Protod::Rpc::Response::Base, force: false, ignore: true)
|
56
|
+
|
57
|
+
self.procedures ||= []
|
58
|
+
self.procedures.push(*ruby_idents)
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.procedure_pushed?(name, singleton: false)
|
62
|
+
procedures&.include?(Protod::RubyIdent.new(const_name: ruby_ident, method_name: name, singleton: singleton)) || false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Protod
|
2
|
+
class RubyIdent
|
3
|
+
include ActiveModel::Model
|
4
|
+
include ActiveModel::Attributes
|
5
|
+
|
6
|
+
attribute :const_name, :string
|
7
|
+
attribute :method_name, :string
|
8
|
+
attribute :singleton, :boolean, default: false
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def build_from(string)
|
12
|
+
return if string.blank?
|
13
|
+
|
14
|
+
string = string.gsub('__', '::')
|
15
|
+
|
16
|
+
const_name, method_name, singleton = case
|
17
|
+
when string.include?('.')
|
18
|
+
[*string.split('.'), true]
|
19
|
+
when string.include?('#')
|
20
|
+
[*string.split('#'), false]
|
21
|
+
else
|
22
|
+
[string, nil, false]
|
23
|
+
end
|
24
|
+
|
25
|
+
return unless const_name.safe_constantize
|
26
|
+
|
27
|
+
new(const_name: const_name, method_name: method_name, singleton: singleton)
|
28
|
+
end
|
29
|
+
|
30
|
+
def absolute_of(ruby_ident)
|
31
|
+
return if ruby_ident.blank?
|
32
|
+
|
33
|
+
"::#{ruby_ident.to_s.delete_prefix('::')}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def const_name
|
38
|
+
self.class.absolute_of(super)
|
39
|
+
end
|
40
|
+
|
41
|
+
def ==(other)
|
42
|
+
to_s == other.to_s
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
[const_name, method_name].compact.join(singleton ? '.' : '#')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/protod.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rbs'
|
4
|
+
require 'active_support/all'
|
5
|
+
require 'active_model'
|
6
|
+
|
7
|
+
require_relative "protod/version"
|
8
|
+
require_relative 'protod/configuration'
|
9
|
+
require_relative 'protod/ruby_ident'
|
10
|
+
require_relative 'protod/proto/features'
|
11
|
+
require_relative 'protod/proto/part'
|
12
|
+
require_relative 'protod/proto/package'
|
13
|
+
require_relative 'protod/proto/service'
|
14
|
+
require_relative 'protod/proto/procedure'
|
15
|
+
require_relative 'protod/proto/message'
|
16
|
+
require_relative 'protod/proto/field'
|
17
|
+
require_relative 'protod/proto/oneof'
|
18
|
+
require_relative 'protod/proto/builder'
|
19
|
+
require_relative 'protod/interpreter'
|
20
|
+
require_relative 'protod/interpreter/builtin'
|
21
|
+
require_relative 'protod/interpreter/active_record'
|
22
|
+
require_relative 'protod/interpreter/rpc'
|
23
|
+
require_relative 'protod/rpc/request'
|
24
|
+
require_relative 'protod/rpc/response'
|
25
|
+
require_relative 'protod/rpc/handler'
|
26
|
+
|
27
|
+
class Protod
|
28
|
+
class << self
|
29
|
+
def configure(&body)
|
30
|
+
if @configuration
|
31
|
+
body.call(@configuration)
|
32
|
+
else
|
33
|
+
@configures ||= []
|
34
|
+
@configures.push(body)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def configuration
|
39
|
+
@configuration ||= Protod::Configuration.new.tap do |c|
|
40
|
+
# Interpreters will be needed by Protod::Configuration#register_interpreter_for
|
41
|
+
Protod::Interpreter::Builtin.setup!
|
42
|
+
Protod::Interpreter::ActiveRecord.setup!
|
43
|
+
Protod::Interpreter::Rpc.setup!
|
44
|
+
|
45
|
+
@configures&.each { _1.call(c) }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def clear!
|
50
|
+
@configures = nil
|
51
|
+
@configuration = nil
|
52
|
+
Protod::Proto::Package.clear!
|
53
|
+
Protod::Rpc::Request.clear!
|
54
|
+
Protod::Rpc::Response.clear!
|
55
|
+
Protod::Interpreter.clear!
|
56
|
+
end
|
57
|
+
|
58
|
+
def setup!
|
59
|
+
Protod.configuration.builders.each(&:build)
|
60
|
+
Protod::Proto::Package.roots.each(&:freeze)
|
61
|
+
Protod::Interpreter.setup_reverse_lookup!
|
62
|
+
end
|
63
|
+
|
64
|
+
concerning :GlobalUtilities do
|
65
|
+
delegate :find_or_register_package, to: Protod::Proto::Package
|
66
|
+
delegate :rbs_environment, :rbs_definition_builder, to: :configuration
|
67
|
+
|
68
|
+
def rbs_method_type_for(ruby_ident)
|
69
|
+
method_types = rbs_definition_for(ruby_ident.const_name, singleton: ruby_ident.singleton).methods[ruby_ident.method_name.to_sym]&.method_types
|
70
|
+
|
71
|
+
raise NotImplementedError, "Not found rbs for #{ruby_ident}" unless method_types
|
72
|
+
|
73
|
+
m = method_types.find { _1.block.nil? || _1.block.required.! } || method_types.first
|
74
|
+
|
75
|
+
raise ArgumentError, "Unsupported receiving block method : #{ruby_ident}" if m.block&.required
|
76
|
+
|
77
|
+
m
|
78
|
+
end
|
79
|
+
|
80
|
+
def rbs_definition_for(const_name, singleton:)
|
81
|
+
const_names = const_name.delete_prefix('::').split('::')
|
82
|
+
name = const_names.pop.to_sym
|
83
|
+
namespace = const_names.empty? ? RBS::Namespace.root : RBS::Namespace.new(path: const_names.map(&:to_sym), absolute: true)
|
84
|
+
|
85
|
+
rbs_type_name = RBS::TypeName.new(name: name, namespace: namespace)
|
86
|
+
|
87
|
+
raise NotImplementedError, "Not found rbs for #{const_name}" unless rbs_environment.class_decls.key?(rbs_type_name)
|
88
|
+
|
89
|
+
if singleton
|
90
|
+
rbs_definition_builder.build_singleton(rbs_type_name)
|
91
|
+
else
|
92
|
+
rbs_definition_builder.build_instance(rbs_type_name)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
module Types
|
99
|
+
Binary = Object.new
|
100
|
+
UnsignedInteger = Object.new
|
101
|
+
Json = Object.new
|
102
|
+
end
|
103
|
+
end
|
data/sig/protod.rbs
ADDED