tapioca 0.4.20 → 0.4.21
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/lib/tapioca/compilers/dsl/protobuf.rb +132 -16
- data/lib/tapioca/generator.rb +4 -9
- data/lib/tapioca/generic_type_registry.rb +22 -19
- data/lib/tapioca/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 832665c6f2a41c3eb5cfda2b0939b4a3f2d29eb624b64de49565b8275f461326
|
4
|
+
data.tar.gz: 29e1f7066050ce4f308b1dc8591dd7de236e19560618a37c9120a4835ac1b295
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a16a1125e343398d7a2190aea74ed2fafc3b9ad5d4aaac8a2b72ae4a75cd65bdb651dcf84528189eec39296eebb42382f847221651190e611f1c7260923653ba
|
7
|
+
data.tar.gz: d636730273b8eb9d828de5609b73c73cb677ec0cf372a1ae5d028604ec53422cbe3c607d557c0b4070dadf704c0023cef1dfb40d09ddb61327d7793db65a0ef0
|
@@ -62,33 +62,99 @@ module Tapioca
|
|
62
62
|
# end
|
63
63
|
# ~~~
|
64
64
|
class Protobuf < Base
|
65
|
+
# Parlour doesn't support type members out of the box, so adding the
|
66
|
+
# ability to do that here. This should be upstreamed.
|
67
|
+
class TypeMember < Parlour::RbiGenerator::RbiObject
|
68
|
+
extend T::Sig
|
69
|
+
|
70
|
+
sig { params(other: Object).returns(T::Boolean) }
|
71
|
+
def ==(other)
|
72
|
+
TypeMember === other && name == other.name
|
73
|
+
end
|
74
|
+
|
75
|
+
sig do
|
76
|
+
override
|
77
|
+
.params(indent_level: Integer, options: Parlour::RbiGenerator::Options)
|
78
|
+
.returns(T::Array[String])
|
79
|
+
end
|
80
|
+
def generate_rbi(indent_level, options)
|
81
|
+
[options.indented(indent_level, "#{name} = type_member")]
|
82
|
+
end
|
83
|
+
|
84
|
+
sig do
|
85
|
+
override
|
86
|
+
.params(others: T::Array[Parlour::RbiGenerator::RbiObject])
|
87
|
+
.returns(T::Boolean)
|
88
|
+
end
|
89
|
+
def mergeable?(others)
|
90
|
+
others.all? { |other| self == other }
|
91
|
+
end
|
92
|
+
|
93
|
+
sig { override.params(others: T::Array[Parlour::RbiGenerator::RbiObject]).void }
|
94
|
+
def merge_into_self(others); end
|
95
|
+
|
96
|
+
sig { override.returns(String) }
|
97
|
+
def describe
|
98
|
+
"Type Member (#{name})"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Field < T::Struct
|
103
|
+
prop :name, String
|
104
|
+
prop :type, String
|
105
|
+
prop :init_type, String
|
106
|
+
prop :default, String
|
107
|
+
|
108
|
+
extend T::Sig
|
109
|
+
|
110
|
+
sig { returns(Parlour::RbiGenerator::Parameter) }
|
111
|
+
def to_init
|
112
|
+
Parlour::RbiGenerator::Parameter.new("#{name}:", type: init_type, default: default)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
65
116
|
extend T::Sig
|
66
117
|
|
67
118
|
sig do
|
68
119
|
override.params(
|
69
120
|
root: Parlour::RbiGenerator::Namespace,
|
70
|
-
constant:
|
121
|
+
constant: Module
|
71
122
|
).void
|
72
123
|
end
|
73
124
|
def decorate(root, constant)
|
74
|
-
descriptor = T.let(T.unsafe(constant).descriptor, Google::Protobuf::Descriptor)
|
75
|
-
return unless descriptor.any?
|
76
|
-
|
77
125
|
root.path(constant) do |klass|
|
78
|
-
|
79
|
-
|
126
|
+
if constant == Google::Protobuf::RepeatedField
|
127
|
+
create_type_members(klass, "Elem")
|
128
|
+
elsif constant == Google::Protobuf::Map
|
129
|
+
create_type_members(klass, "Key", "Value")
|
130
|
+
else
|
131
|
+
descriptor = T.let(T.unsafe(constant).descriptor, Google::Protobuf::Descriptor)
|
132
|
+
fields = descriptor.map { |desc| create_descriptor_method(klass, desc) }
|
133
|
+
fields.sort_by!(&:name)
|
134
|
+
|
135
|
+
create_method(klass, "initialize", parameters: fields.map!(&:to_init))
|
80
136
|
end
|
81
137
|
end
|
82
138
|
end
|
83
139
|
|
84
140
|
sig { override.returns(T::Enumerable[Module]) }
|
85
141
|
def gather_constants
|
86
|
-
|
87
|
-
|
142
|
+
marker = Google::Protobuf::MessageExts::ClassMethods
|
143
|
+
results = T.cast(ObjectSpace.each_object(marker).to_a, T::Array[Module])
|
144
|
+
results.any? ? results + [Google::Protobuf::RepeatedField, Google::Protobuf::Map] : []
|
88
145
|
end
|
89
146
|
|
90
147
|
private
|
91
148
|
|
149
|
+
sig { params(klass: Parlour::RbiGenerator::Namespace, names: String).void }
|
150
|
+
def create_type_members(klass, *names)
|
151
|
+
klass.create_extend("T::Generic")
|
152
|
+
|
153
|
+
names.each do |name|
|
154
|
+
klass.children << TypeMember.new(klass.generator, name)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
92
158
|
sig do
|
93
159
|
params(
|
94
160
|
descriptor: Google::Protobuf::FieldDescriptor
|
@@ -113,30 +179,80 @@ module Tapioca
|
|
113
179
|
end
|
114
180
|
end
|
115
181
|
|
182
|
+
sig { params(descriptor: Google::Protobuf::FieldDescriptor).returns(Field) }
|
183
|
+
def field_of(descriptor)
|
184
|
+
if descriptor.label == :repeated
|
185
|
+
# Here we're going to check if the submsg_name is named according to
|
186
|
+
# how Google names map entries.
|
187
|
+
# https://github.com/protocolbuffers/protobuf/blob/f82e26/ruby/ext/google/protobuf_c/defs.c#L1963-L1966
|
188
|
+
if descriptor.submsg_name.to_s.end_with?("_MapEntry_#{descriptor.name}")
|
189
|
+
key = descriptor.subtype.lookup('key')
|
190
|
+
value = descriptor.subtype.lookup('value')
|
191
|
+
|
192
|
+
key_type = type_of(key)
|
193
|
+
value_type = type_of(value)
|
194
|
+
type = "Google::Protobuf::Map[#{key_type}, #{value_type}]"
|
195
|
+
|
196
|
+
default_args = [key.type.inspect, value.type.inspect]
|
197
|
+
default_args << value_type if %i[enum message].include?(value.type)
|
198
|
+
|
199
|
+
Field.new(
|
200
|
+
name: descriptor.name,
|
201
|
+
type: type,
|
202
|
+
init_type: "T.any(#{type}, T::Hash[#{key_type}, #{value_type}])",
|
203
|
+
default: "Google::Protobuf::Map.new(#{default_args.join(', ')})"
|
204
|
+
)
|
205
|
+
else
|
206
|
+
elem_type = type_of(descriptor)
|
207
|
+
type = "Google::Protobuf::RepeatedField[#{elem_type}]"
|
208
|
+
|
209
|
+
default_args = [descriptor.type.inspect]
|
210
|
+
default_args << elem_type if %i[enum message].include?(descriptor.type)
|
211
|
+
|
212
|
+
Field.new(
|
213
|
+
name: descriptor.name,
|
214
|
+
type: type,
|
215
|
+
init_type: "T.any(#{type}, T::Array[#{elem_type}])",
|
216
|
+
default: "Google::Protobuf::RepeatedField.new(#{default_args.join(', ')})"
|
217
|
+
)
|
218
|
+
end
|
219
|
+
else
|
220
|
+
type = type_of(descriptor)
|
221
|
+
|
222
|
+
Field.new(
|
223
|
+
name: descriptor.name,
|
224
|
+
type: type,
|
225
|
+
init_type: type,
|
226
|
+
default: "nil"
|
227
|
+
)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
116
231
|
sig do
|
117
232
|
params(
|
118
233
|
klass: Parlour::RbiGenerator::Namespace,
|
119
234
|
desc: Google::Protobuf::FieldDescriptor,
|
120
|
-
).
|
235
|
+
).returns(Field)
|
121
236
|
end
|
122
237
|
def create_descriptor_method(klass, desc)
|
123
|
-
|
124
|
-
type = type_of(desc)
|
238
|
+
field = field_of(desc)
|
125
239
|
|
126
240
|
create_method(
|
127
241
|
klass,
|
128
|
-
name,
|
129
|
-
return_type: type
|
242
|
+
field.name,
|
243
|
+
return_type: field.type
|
130
244
|
)
|
131
245
|
|
132
246
|
create_method(
|
133
247
|
klass,
|
134
|
-
"#{name}=",
|
248
|
+
"#{field.name}=",
|
135
249
|
parameters: [
|
136
|
-
Parlour::RbiGenerator::Parameter.new("value", type: type),
|
250
|
+
Parlour::RbiGenerator::Parameter.new("value", type: field.type),
|
137
251
|
],
|
138
|
-
return_type: type
|
252
|
+
return_type: field.type
|
139
253
|
)
|
254
|
+
|
255
|
+
field
|
140
256
|
end
|
141
257
|
end
|
142
258
|
end
|
data/lib/tapioca/generator.rb
CHANGED
@@ -145,8 +145,6 @@ module Tapioca
|
|
145
145
|
}
|
146
146
|
)
|
147
147
|
|
148
|
-
constant_lookup = {}
|
149
|
-
|
150
148
|
compiler.run do |constant, contents|
|
151
149
|
constant_name = Module.instance_method(:name).bind(constant).call
|
152
150
|
|
@@ -159,13 +157,12 @@ module Tapioca
|
|
159
157
|
|
160
158
|
if filename
|
161
159
|
rbi_files_to_purge.delete(filename)
|
162
|
-
constant_lookup[filename.relative_path_from(outpath)] = constant_name
|
163
160
|
end
|
164
161
|
end
|
165
162
|
say("")
|
166
163
|
|
167
164
|
if should_verify
|
168
|
-
perform_dsl_verification(outpath
|
165
|
+
perform_dsl_verification(outpath)
|
169
166
|
else
|
170
167
|
purge_stale_dsl_rbi_files(rbi_files_to_purge)
|
171
168
|
|
@@ -596,17 +593,15 @@ module Tapioca
|
|
596
593
|
end.sort
|
597
594
|
end
|
598
595
|
|
599
|
-
sig { params(dir: Pathname
|
600
|
-
def perform_dsl_verification(dir
|
596
|
+
sig { params(dir: Pathname).void }
|
597
|
+
def perform_dsl_verification(dir)
|
601
598
|
diff = verify_dsl_rbi(tmp_dir: dir)
|
602
599
|
|
603
600
|
if diff.empty?
|
604
601
|
say("Nothing to do, all RBIs are up-to-date.")
|
605
602
|
else
|
606
|
-
constants = T.unsafe(constant_lookup).values_at(*diff.keys).join(" ")
|
607
|
-
|
608
603
|
say("RBI files are out-of-date, please run:")
|
609
|
-
say(" `#{Config::DEFAULT_COMMAND} dsl
|
604
|
+
say(" `#{Config::DEFAULT_COMMAND} dsl`")
|
610
605
|
|
611
606
|
say("")
|
612
607
|
|
@@ -100,7 +100,7 @@ module Tapioca
|
|
100
100
|
# the generic class `Foo[Bar]` is still a `Foo`. That is:
|
101
101
|
# `Foo[Bar].new.is_a?(Foo)` should be true, which isn't the case
|
102
102
|
# if we just clone the class. But subclassing works just fine.
|
103
|
-
|
103
|
+
create_safe_subclass(constant)
|
104
104
|
else
|
105
105
|
# This can only be a module and it is fine to just clone modules
|
106
106
|
# since they can't have instances and will not have `is_a?` relationships.
|
@@ -151,28 +151,31 @@ module Tapioca
|
|
151
151
|
end
|
152
152
|
|
153
153
|
sig { params(constant: Class).returns(Class) }
|
154
|
-
def
|
155
|
-
#
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
#
|
161
|
-
|
162
|
-
|
163
|
-
# Get the filename the sealed class was declared in
|
164
|
-
decl_file = constant.instance_variable_get(:@sorbet_sealed_module_decl_file)
|
154
|
+
def create_safe_subclass(constant)
|
155
|
+
# Lookup the "inherited" class method
|
156
|
+
inherited_method = constant.method(:inherited)
|
157
|
+
# and the module that defines it
|
158
|
+
owner = inherited_method.owner
|
159
|
+
|
160
|
+
# If no one has overriden the inherited method yet, just subclass
|
161
|
+
return Class.new(constant) if Class == owner
|
162
|
+
|
165
163
|
begin
|
166
|
-
#
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
164
|
+
# Otherwise, some inherited method could be preventing us
|
165
|
+
# from creating subclasses, so let's override it and rescue
|
166
|
+
owner.send(:define_method, :inherited) do |s|
|
167
|
+
begin
|
168
|
+
inherited_method.call(s)
|
169
|
+
rescue
|
170
|
+
# Ignoring errors
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
171
174
|
# return a subclass
|
172
175
|
Class.new(constant)
|
173
176
|
ensure
|
174
|
-
# Reinstate the original
|
175
|
-
|
177
|
+
# Reinstate the original inherited method back.
|
178
|
+
owner.send(:define_method, :inherited, inherited_method)
|
176
179
|
end
|
177
180
|
end
|
178
181
|
|
data/lib/tapioca/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tapioca
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ufuk Kayserilioglu
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: exe
|
13
13
|
cert_chain: []
|
14
|
-
date: 2021-04-
|
14
|
+
date: 2021-04-22 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|