protod 0.1.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 +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