rbs 3.3.2 → 3.4.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/.github/workflows/comments.yml +2 -5
- data/.github/workflows/ruby.yml +7 -8
- data/.github/workflows/typecheck.yml +37 -0
- data/CHANGELOG.md +65 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +11 -11
- data/README.md +1 -0
- data/Rakefile +2 -2
- data/Steepfile +2 -2
- data/core/array.rbs +19 -49
- data/core/basic_object.rbs +2 -2
- data/core/comparable.rbs +17 -8
- data/core/complex.rbs +82 -43
- data/core/data.rbs +2 -4
- data/core/dir.rbs +635 -295
- data/core/enumerable.rbs +11 -18
- data/core/enumerator.rbs +37 -31
- data/core/errors.rbs +4 -0
- data/core/false_class.rbs +34 -15
- data/core/fiber.rbs +23 -0
- data/core/file.rbs +329 -120
- data/core/float.rbs +17 -32
- data/core/gc.rbs +17 -11
- data/core/hash.rbs +22 -44
- data/core/integer.rbs +82 -113
- data/core/io/buffer.rbs +90 -47
- data/core/io.rbs +54 -121
- data/core/kernel.rbs +442 -489
- data/core/match_data.rbs +55 -56
- data/core/module.rbs +45 -1
- data/core/nil_class.rbs +98 -35
- data/core/numeric.rbs +22 -32
- data/core/object_space/weak_key_map.rbs +102 -0
- data/core/process.rbs +1242 -655
- data/core/ractor.rbs +139 -120
- data/core/range.rbs +100 -4
- data/core/rational.rbs +0 -4
- data/core/rbs/unnamed/argf.rbs +16 -8
- data/core/rbs/unnamed/env_class.rbs +0 -24
- data/core/refinement.rbs +8 -0
- data/core/regexp.rbs +1149 -598
- data/core/ruby_vm.rbs +126 -12
- data/core/rubygems/platform.rbs +9 -0
- data/core/rubygems/rubygems.rbs +1 -1
- data/core/rubygems/version.rbs +5 -1
- data/core/set.rbs +20 -22
- data/core/signal.rbs +4 -4
- data/core/string.rbs +283 -230
- data/core/string_io.rbs +2 -14
- data/core/struct.rbs +404 -24
- data/core/symbol.rbs +1 -19
- data/core/thread.rbs +29 -12
- data/core/time.rbs +227 -104
- data/core/trace_point.rbs +2 -5
- data/core/true_class.rbs +54 -21
- data/core/warning.rbs +14 -11
- data/docs/data_and_struct.md +29 -0
- data/docs/gem.md +58 -0
- data/docs/syntax.md +3 -5
- data/docs/tools.md +1 -0
- data/ext/rbs_extension/lexer.c +643 -559
- data/ext/rbs_extension/lexer.re +5 -1
- data/ext/rbs_extension/parser.c +12 -3
- data/ext/rbs_extension/unescape.c +7 -47
- data/lib/rbs/cli/diff.rb +4 -1
- data/lib/rbs/cli/validate.rb +280 -0
- data/lib/rbs/cli.rb +2 -194
- data/lib/rbs/collection/config.rb +5 -6
- data/lib/rbs/collection/sources/git.rb +1 -1
- data/lib/rbs/collection.rb +1 -0
- data/lib/rbs/diff.rb +7 -4
- data/lib/rbs/errors.rb +11 -0
- data/lib/rbs/test/errors.rb +10 -2
- data/lib/rbs/test/guaranteed.rb +2 -3
- data/lib/rbs/test/type_check.rb +15 -10
- data/lib/rbs/test.rb +3 -3
- data/lib/rbs/types.rb +29 -0
- data/lib/rbs/unit_test/convertibles.rb +176 -0
- data/lib/rbs/unit_test/spy.rb +136 -0
- data/lib/rbs/unit_test/type_assertions.rb +341 -0
- data/lib/rbs/unit_test/with_aliases.rb +143 -0
- data/lib/rbs/unit_test.rb +6 -0
- data/lib/rbs/version.rb +1 -1
- data/sig/cli/validate.rbs +43 -0
- data/sig/diff.rbs +3 -1
- data/sig/errors.rbs +8 -0
- data/sig/rbs.rbs +1 -1
- data/sig/test/errors.rbs +52 -0
- data/sig/test/guranteed.rbs +9 -0
- data/sig/test/type_check.rbs +19 -0
- data/sig/test.rbs +82 -0
- data/sig/types.rbs +6 -1
- data/sig/unit_test/convertibles.rbs +154 -0
- data/sig/unit_test/spy.rbs +28 -0
- data/sig/unit_test/type_assertions.rbs +194 -0
- data/sig/unit_test/with_aliases.rbs +136 -0
- data/stdlib/base64/0/base64.rbs +307 -45
- data/stdlib/bigdecimal/0/big_decimal.rbs +35 -15
- data/stdlib/coverage/0/coverage.rbs +2 -2
- data/stdlib/csv/0/csv.rbs +25 -55
- data/stdlib/date/0/date.rbs +1 -43
- data/stdlib/date/0/date_time.rbs +1 -13
- data/stdlib/delegate/0/delegator.rbs +186 -0
- data/stdlib/delegate/0/kernel.rbs +47 -0
- data/stdlib/delegate/0/simple_delegator.rbs +98 -0
- data/stdlib/did_you_mean/0/did_you_mean.rbs +1 -1
- data/stdlib/erb/0/erb.rbs +2 -2
- data/stdlib/fileutils/0/fileutils.rbs +0 -19
- data/stdlib/io-console/0/io-console.rbs +12 -1
- data/stdlib/ipaddr/0/ipaddr.rbs +2 -1
- data/stdlib/json/0/json.rbs +320 -81
- data/stdlib/logger/0/logger.rbs +9 -5
- data/stdlib/minitest/0/minitest/test/lifecycle_hooks.rbs +6 -6
- data/stdlib/monitor/0/monitor.rbs +78 -0
- data/stdlib/net-http/0/net-http.rbs +1880 -543
- data/stdlib/objspace/0/objspace.rbs +19 -13
- data/stdlib/openssl/0/openssl.rbs +508 -127
- data/stdlib/optparse/0/optparse.rbs +25 -11
- data/stdlib/pathname/0/pathname.rbs +1 -1
- data/stdlib/pp/0/pp.rbs +2 -5
- data/stdlib/prettyprint/0/prettyprint.rbs +2 -2
- data/stdlib/pstore/0/pstore.rbs +2 -4
- data/stdlib/rdoc/0/comment.rbs +1 -2
- data/stdlib/resolv/0/resolv.rbs +4 -2
- data/stdlib/socket/0/socket.rbs +2 -2
- data/stdlib/socket/0/unix_socket.rbs +2 -2
- data/stdlib/strscan/0/string_scanner.rbs +3 -2
- data/stdlib/tempfile/0/tempfile.rbs +1 -1
- data/stdlib/uri/0/common.rbs +245 -123
- metadata +24 -4
- data/lib/rbs/test/spy.rb +0 -6
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module RBS
|
|
3
|
+
module UnitTest
|
|
4
|
+
module TypeAssertions
|
|
5
|
+
module ClassMethods
|
|
6
|
+
attr_reader :target
|
|
7
|
+
|
|
8
|
+
def library(*libs)
|
|
9
|
+
if @libs
|
|
10
|
+
raise "Multiple #library calls are not allowed"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
@libs = libs
|
|
14
|
+
@env = nil
|
|
15
|
+
@target = nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
@@env_cache = {}
|
|
19
|
+
|
|
20
|
+
def env
|
|
21
|
+
@env = @@env_cache[@libs] ||=
|
|
22
|
+
begin
|
|
23
|
+
loader = RBS::EnvironmentLoader.new
|
|
24
|
+
(@libs || []).each do |lib|
|
|
25
|
+
loader.add(library: lib, version: nil)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
RBS::Environment.from_loader(loader).resolve_type_names
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def builder
|
|
33
|
+
@builder ||= RBS::DefinitionBuilder.new(env: env)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def testing(type_or_string)
|
|
37
|
+
type = case type_or_string
|
|
38
|
+
when String
|
|
39
|
+
RBS::Parser.parse_type(type_or_string, variables: []) || raise
|
|
40
|
+
else
|
|
41
|
+
type_or_string
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
definition = case type
|
|
45
|
+
when RBS::Types::ClassInstance
|
|
46
|
+
builder.build_instance(type.name)
|
|
47
|
+
when RBS::Types::ClassSingleton
|
|
48
|
+
builder.build_singleton(type.name)
|
|
49
|
+
else
|
|
50
|
+
raise "Test target should be class instance or class singleton: #{type}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
@target = [type, definition] #: [target_type, Definition]
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.included(base)
|
|
58
|
+
base.extend ClassMethods
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def env
|
|
62
|
+
(_ = self.class).env
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def builder
|
|
66
|
+
(_ = self.class).builder
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def targets
|
|
70
|
+
@targets ||= []
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def target
|
|
74
|
+
targets.last || (_ = self.class).target
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def testing(type_or_string)
|
|
78
|
+
type = case type_or_string
|
|
79
|
+
when String
|
|
80
|
+
RBS::Parser.parse_type(type_or_string, variables: [])
|
|
81
|
+
else
|
|
82
|
+
type_or_string
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
definition = case type
|
|
86
|
+
when RBS::Types::ClassInstance
|
|
87
|
+
builder.build_instance(type.name)
|
|
88
|
+
when RBS::Types::ClassSingleton
|
|
89
|
+
builder.build_singleton(type.name)
|
|
90
|
+
else
|
|
91
|
+
raise "Test target should be class instance or class singleton: #{type}"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
targets.push(
|
|
95
|
+
[
|
|
96
|
+
type, #: target_type
|
|
97
|
+
definition
|
|
98
|
+
]
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
if block_given?
|
|
102
|
+
begin
|
|
103
|
+
yield
|
|
104
|
+
ensure
|
|
105
|
+
targets.pop
|
|
106
|
+
end
|
|
107
|
+
else
|
|
108
|
+
[type, definition]
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def instance_class
|
|
113
|
+
type, _ = target
|
|
114
|
+
|
|
115
|
+
case type
|
|
116
|
+
when RBS::Types::ClassSingleton, RBS::Types::ClassInstance
|
|
117
|
+
Object.const_get(type.name.to_s)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def class_class
|
|
122
|
+
type, _ = target
|
|
123
|
+
|
|
124
|
+
case type
|
|
125
|
+
when RBS::Types::ClassSingleton, RBS::Types::ClassInstance
|
|
126
|
+
Object.const_get(type.name.to_s).singleton_class
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def send_setup(method_type, receiver, method, args, proc)
|
|
131
|
+
mt =
|
|
132
|
+
case method_type
|
|
133
|
+
when String
|
|
134
|
+
RBS::Parser.parse_method_type(method_type, variables: []) || raise
|
|
135
|
+
when RBS::MethodType
|
|
136
|
+
method_type
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
validate_simple_method_type(mt)
|
|
140
|
+
|
|
141
|
+
trace = [] #: Array[Test::CallTrace]
|
|
142
|
+
spy = Spy.wrap(receiver, method)
|
|
143
|
+
spy.callback = -> (result) { trace << result }
|
|
144
|
+
|
|
145
|
+
result = nil #: untyped
|
|
146
|
+
exception = nil #: Exception?
|
|
147
|
+
non_jump_exit = true
|
|
148
|
+
|
|
149
|
+
begin
|
|
150
|
+
result = catch do |tag|
|
|
151
|
+
@break_tag = tag
|
|
152
|
+
spy.wrapped_object.__send__(method, *args, &proc)
|
|
153
|
+
ensure
|
|
154
|
+
@break_tag = nil
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
non_jump_exit = false
|
|
158
|
+
rescue Exception => exn
|
|
159
|
+
exception = exn
|
|
160
|
+
ensure
|
|
161
|
+
if non_jump_exit && !exception
|
|
162
|
+
raise "`break` nor `return` from blocks given to `assert_send_type` are prohibited. Use `#break_from_block` instead."
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
last_trace = trace.last or raise
|
|
167
|
+
|
|
168
|
+
yield(mt, last_trace, result, exception)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
ruby2_keywords def assert_send_type(method_type, receiver, method, *args, &block)
|
|
172
|
+
send_setup(method_type, receiver, method, args, block) do |method_type, trace, result, exception|
|
|
173
|
+
typecheck = RBS::Test::TypeCheck.new(
|
|
174
|
+
self_class: receiver.class,
|
|
175
|
+
builder: builder,
|
|
176
|
+
sample_size: 100,
|
|
177
|
+
unchecked_classes: [],
|
|
178
|
+
instance_class: instance_class,
|
|
179
|
+
class_class: class_class
|
|
180
|
+
)
|
|
181
|
+
errors = typecheck.method_call(method, method_type, trace, errors: [])
|
|
182
|
+
|
|
183
|
+
assert_empty errors.map {|x| RBS::Test::Errors.to_string(x) }, "Call trace does not match with given method type: #{trace.inspect}"
|
|
184
|
+
|
|
185
|
+
method_types = method_types(method)
|
|
186
|
+
all_errors = method_types.map {|t| typecheck.method_call(method, t, trace, errors: []) }
|
|
187
|
+
assert all_errors.any? {|es| es.empty? }, "Call trace does not match one of method definitions:\n #{trace.inspect}\n #{method_types.join(" | ")}"
|
|
188
|
+
|
|
189
|
+
raise exception if exception
|
|
190
|
+
|
|
191
|
+
result
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
ruby2_keywords def refute_send_type(method_type, receiver, method, *args, &block)
|
|
196
|
+
send_setup(method_type, receiver, method, args, block) do |method_type, trace, result, exception|
|
|
197
|
+
method_type = method_type.update(
|
|
198
|
+
block:
|
|
199
|
+
if method_type.block
|
|
200
|
+
RBS::Types::Block.new(
|
|
201
|
+
type: method_type.block.type.with_return_type(RBS::Types::Bases::Any.new(location: nil)),
|
|
202
|
+
required: method_type.block.required,
|
|
203
|
+
self_type: nil
|
|
204
|
+
)
|
|
205
|
+
end,
|
|
206
|
+
type: method_type.type.with_return_type(RBS::Types::Bases::Any.new(location: nil))
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
typecheck = RBS::Test::TypeCheck.new(
|
|
210
|
+
self_class: receiver.class,
|
|
211
|
+
instance_class: instance_class,
|
|
212
|
+
class_class: class_class,
|
|
213
|
+
builder: builder,
|
|
214
|
+
sample_size: 100,
|
|
215
|
+
unchecked_classes: []
|
|
216
|
+
)
|
|
217
|
+
errors = typecheck.method_call(method, method_type, trace, errors: [])
|
|
218
|
+
|
|
219
|
+
assert_operator exception, :is_a?, ::Exception
|
|
220
|
+
assert_empty errors.map {|x| RBS::Test::Errors.to_string(x) }
|
|
221
|
+
|
|
222
|
+
method_types = method_types(method)
|
|
223
|
+
all_errors = method_types.map {|t| typecheck.method_call(method, t, trace, errors: []) }
|
|
224
|
+
assert all_errors.all? {|es| es.size > 0 }, "Call trace unexpectedly matches one of method definitions:\n #{trace.inspect}\n #{method_types.join(" | ")}"
|
|
225
|
+
|
|
226
|
+
result
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def method_types(method)
|
|
231
|
+
type, definition = target
|
|
232
|
+
|
|
233
|
+
case type
|
|
234
|
+
when Types::ClassInstance
|
|
235
|
+
subst = RBS::Substitution.build(definition.type_params, type.args)
|
|
236
|
+
definition.methods[method].method_types.map do |method_type|
|
|
237
|
+
method_type.sub(subst)
|
|
238
|
+
end
|
|
239
|
+
when Types::ClassSingleton
|
|
240
|
+
definition.methods[method].method_types
|
|
241
|
+
else
|
|
242
|
+
raise
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def allows_error(*errors)
|
|
247
|
+
yield
|
|
248
|
+
rescue *errors => exn
|
|
249
|
+
notify "Error allowed: #{exn.inspect}"
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def assert_const_type(type, constant_name)
|
|
253
|
+
constant = Object.const_get(constant_name)
|
|
254
|
+
|
|
255
|
+
typecheck = RBS::Test::TypeCheck.new(
|
|
256
|
+
self_class: constant.class,
|
|
257
|
+
instance_class: instance_class,
|
|
258
|
+
class_class: class_class,
|
|
259
|
+
builder: builder,
|
|
260
|
+
sample_size: 100,
|
|
261
|
+
unchecked_classes: []
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
value_type =
|
|
265
|
+
case type
|
|
266
|
+
when String
|
|
267
|
+
RBS::Parser.parse_type(type, variables: []) || raise
|
|
268
|
+
else
|
|
269
|
+
type
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
assert typecheck.value(constant, value_type), "`#{constant_name}` (#{constant.inspect}) must be compatible with given type `#{value_type}`"
|
|
273
|
+
|
|
274
|
+
type_name = TypeName(constant_name).absolute!
|
|
275
|
+
definition = env.constant_entry(type_name)
|
|
276
|
+
assert definition, "Cannot find RBS type definition of `#{constant_name}`"
|
|
277
|
+
|
|
278
|
+
case definition
|
|
279
|
+
when RBS::Environment::ClassEntry, RBS::Environment::ModuleEntry
|
|
280
|
+
definition_type = RBS::Types::ClassSingleton.new(name: type_name, location: nil)
|
|
281
|
+
when RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry
|
|
282
|
+
type_name = env.normalize_type_name!(type_name)
|
|
283
|
+
definition_type = RBS::Types::ClassSingleton.new(name: type_name, location: nil)
|
|
284
|
+
when RBS::Environment::ConstantEntry
|
|
285
|
+
definition_type = definition.decl.type
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
assert definition_type, "Cannot find RBS entry for `#{constant_name}`"
|
|
289
|
+
definition_type or raise
|
|
290
|
+
assert typecheck.value(constant, definition_type), "`#{constant_name}` (#{constant.inspect}) must be compatible with RBS type definition `#{definition_type}`"
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def assert_type(type, value)
|
|
294
|
+
typecheck = RBS::Test::TypeCheck.new(
|
|
295
|
+
self_class: value.class,
|
|
296
|
+
instance_class: _ = "No `instance` class allowed",
|
|
297
|
+
class_class: _ = "No `class` class allowed",
|
|
298
|
+
builder: builder,
|
|
299
|
+
sample_size: 100,
|
|
300
|
+
unchecked_classes: []
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
type =
|
|
304
|
+
case type
|
|
305
|
+
when String
|
|
306
|
+
RBS::Parser.parse_type(type, variables: []) or raise
|
|
307
|
+
else
|
|
308
|
+
type
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
assert typecheck.value(value, type), "`#{value.inspect}` must be compatible with given type `#{type}`"
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def allow_non_simple_method_type()
|
|
315
|
+
begin
|
|
316
|
+
@allows_non_simple_method_type = true
|
|
317
|
+
yield
|
|
318
|
+
rescue
|
|
319
|
+
@allows_non_simple_method_type = false
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
def validate_simple_method_type(type)
|
|
324
|
+
return if @allows_non_simple_method_type
|
|
325
|
+
|
|
326
|
+
refute_predicate type, :has_self_type?, "`self` types is prohibited in method type: `#{type}`"
|
|
327
|
+
refute_predicate type, :has_classish_type?, "`instance` and `class` types is prohibited in method type: `#{type}`"
|
|
328
|
+
refute_predicate type, :with_nonreturn_void?, "`void` is only allowed at return type or generics parameters: `#{type}`"
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def break_from_block(value = nil)
|
|
332
|
+
raise "Cannot break without `@break_tag`" unless @break_tag
|
|
333
|
+
throw @break_tag, value
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def pass(message = nil)
|
|
337
|
+
assert true, message
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
end
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RBS
|
|
4
|
+
module UnitTest
|
|
5
|
+
module WithAliases
|
|
6
|
+
include Convertibles
|
|
7
|
+
|
|
8
|
+
class WithEnum
|
|
9
|
+
include Enumerable
|
|
10
|
+
|
|
11
|
+
def initialize(enum) = @enum = enum
|
|
12
|
+
|
|
13
|
+
def each(&block) = @enum.each(&block)
|
|
14
|
+
|
|
15
|
+
def and_nil(&block)
|
|
16
|
+
self.and(nil, &_ = block)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def but(*cases, &block)
|
|
20
|
+
return WithEnum.new to_enum(__method__ || raise, *cases) unless block
|
|
21
|
+
|
|
22
|
+
each do |arg|
|
|
23
|
+
yield arg unless cases.any? { (_ = _1) === arg }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def and(*args, &block)
|
|
28
|
+
return WithEnum.new to_enum(__method__ || raise, *args) unless block
|
|
29
|
+
|
|
30
|
+
each(&block)
|
|
31
|
+
args.each do |arg|
|
|
32
|
+
if WithEnum === arg # use `===` as `arg` might not have `.is_a?` on it
|
|
33
|
+
arg.each(&block)
|
|
34
|
+
else
|
|
35
|
+
block.call(_ = arg)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def with(*args, &block)
|
|
42
|
+
return WithEnum.new to_enum(__method__ || raise, *args) unless block
|
|
43
|
+
args.each(&block)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def with_int(value = 3, &block)
|
|
47
|
+
return WithEnum.new to_enum(__method__ || raise, value) unless block
|
|
48
|
+
yield value
|
|
49
|
+
yield ToInt.new(value)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def with_float(value = 0.1)
|
|
53
|
+
return WithEnum.new to_enum(__method__ || raise, value) unless block_given?
|
|
54
|
+
yield value
|
|
55
|
+
yield ToF.new(value)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def with_string(value = '')
|
|
59
|
+
return WithEnum.new to_enum(__method__ || raise, value) unless block_given?
|
|
60
|
+
yield value
|
|
61
|
+
yield ToStr.new(value)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def with_array(*elements)
|
|
65
|
+
return WithEnum.new to_enum(__method__ || raise, *elements) unless block_given?
|
|
66
|
+
|
|
67
|
+
yield _ = elements
|
|
68
|
+
yield ToArray.new(*elements)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def with_hash(hash = {})
|
|
72
|
+
return WithEnum.new to_enum(__method__ || raise, hash) unless block_given?
|
|
73
|
+
|
|
74
|
+
yield _ = hash
|
|
75
|
+
yield ToHash.new(hash)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def with_io(io = $stdout)
|
|
79
|
+
return WithEnum.new to_enum(__method__ || raise, io) unless block_given?
|
|
80
|
+
yield io
|
|
81
|
+
yield ToIO.new(io)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def with_path(path = "/tmp/foo.txt", &block)
|
|
85
|
+
return WithEnum.new to_enum(__method__ || raise, path) unless block
|
|
86
|
+
|
|
87
|
+
with_string(path, &block)
|
|
88
|
+
block.call ToPath.new(path)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def with_encoding(encoding = Encoding::UTF_8, &block)
|
|
92
|
+
return WithEnum.new to_enum(__method__ || raise, encoding) unless block
|
|
93
|
+
|
|
94
|
+
block.call encoding
|
|
95
|
+
with_string(encoding.to_s, &block)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def with_interned(value = :&, &block)
|
|
99
|
+
return WithEnum.new to_enum(__method__ || raise, value) unless block
|
|
100
|
+
|
|
101
|
+
with_string(value.to_s, &block)
|
|
102
|
+
block.call value.to_sym
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def with_bool(&block)
|
|
106
|
+
return WithEnum.new to_enum(__method__ || raise) unless block
|
|
107
|
+
yield true
|
|
108
|
+
yield false
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def with_boolish(&block)
|
|
112
|
+
return WithEnum.new to_enum(__method__ || raise) unless block
|
|
113
|
+
with_bool(&block)
|
|
114
|
+
[nil, 1, Object.new, BlankSlate.new, "hello, world!"].each(&block)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
alias with_untyped with_boolish
|
|
118
|
+
|
|
119
|
+
def with_range(start, stop, exclude_end = false)
|
|
120
|
+
# If you need fixed starting and stopping points, you can just do `with_range with(1), with(2)`.
|
|
121
|
+
raise ArgumentError, '`start` must be from a `with` method' unless start.is_a? WithEnum
|
|
122
|
+
raise ArgumentError, '`stop` must be from a `with` method' unless stop.is_a? WithEnum
|
|
123
|
+
|
|
124
|
+
start.each do |lower|
|
|
125
|
+
stop.each do |upper|
|
|
126
|
+
yield CustomRange.new(lower, upper, exclude_end)
|
|
127
|
+
|
|
128
|
+
# `Range` requires `begin <=> end` to return non-nil, but doesn't actually
|
|
129
|
+
# end up using the return value of it. This is to add that in when needed.
|
|
130
|
+
def lower.<=>(rhs) = :not_nil unless defined? lower.<=>
|
|
131
|
+
|
|
132
|
+
# If `lower <=> rhs` is defined but nil, then that means we're going to be constructing
|
|
133
|
+
# an illegal range (eg `3..ToInt.new(4)`). So, we need to skip yielding an invalid range
|
|
134
|
+
# in that case.
|
|
135
|
+
next if defined?(lower.<=>) && nil == (lower <=> upper)
|
|
136
|
+
|
|
137
|
+
yield Range.new(lower, upper, exclude_end)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
data/lib/rbs/version.rb
CHANGED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module RBS
|
|
2
|
+
class CLI
|
|
3
|
+
class Validate
|
|
4
|
+
class Errors
|
|
5
|
+
@limit: Integer?
|
|
6
|
+
@exit_error: boolish
|
|
7
|
+
@has_syntax_error: bool
|
|
8
|
+
@errors: Array[BaseError]
|
|
9
|
+
|
|
10
|
+
def initialize: (limit: Integer?, exit_error: boolish) -> void
|
|
11
|
+
|
|
12
|
+
def add: (BaseError) -> void
|
|
13
|
+
|
|
14
|
+
def finish: () -> void
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def build_message: (BaseError) -> String
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
@env: Environment
|
|
22
|
+
@builder: RBS::DefinitionBuilder
|
|
23
|
+
@validator: RBS::Validator
|
|
24
|
+
@errors: Errors
|
|
25
|
+
|
|
26
|
+
def initialize: (args: Array[String], options: LibraryOptions) -> void
|
|
27
|
+
|
|
28
|
+
def run: () -> void
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def validate_class_module_definition: () -> void
|
|
33
|
+
def validate_class_module_alias_definition: () -> void
|
|
34
|
+
def validate_interface: () -> void
|
|
35
|
+
def validate_constant: () -> void
|
|
36
|
+
def validate_global: () -> void
|
|
37
|
+
def validate_type_alias: () -> void
|
|
38
|
+
def no_self_type_validator: (::RBS::Types::t | ::RBS::MethodType type) -> void
|
|
39
|
+
def no_classish_type_validator: (::RBS::Types::t | ::RBS::MethodType type) -> void
|
|
40
|
+
def void_type_context_validator: (::RBS::Types::t | ::RBS::MethodType type, ?bool allowed_here) -> void
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/sig/diff.rbs
CHANGED
|
@@ -4,12 +4,14 @@ module RBS
|
|
|
4
4
|
@library_options: RBS::CLI::LibraryOptions
|
|
5
5
|
@after_path: Array[String]
|
|
6
6
|
@before_path: Array[String]
|
|
7
|
+
@detail: boolish
|
|
7
8
|
|
|
8
9
|
def initialize: (
|
|
9
10
|
type_name: TypeName,
|
|
10
11
|
library_options: RBS::CLI::LibraryOptions,
|
|
11
12
|
?after_path: Array[String],
|
|
12
|
-
?before_path: Array[String]
|
|
13
|
+
?before_path: Array[String],
|
|
14
|
+
?detail: boolish
|
|
13
15
|
) -> void
|
|
14
16
|
|
|
15
17
|
def each_diff: () { (String before, String after) -> void } -> void
|
data/sig/errors.rbs
CHANGED
|
@@ -357,4 +357,12 @@ module RBS
|
|
|
357
357
|
|
|
358
358
|
def location: () -> AST::Declarations::AliasDecl::loc?
|
|
359
359
|
end
|
|
360
|
+
|
|
361
|
+
class WillSyntaxError < BaseError
|
|
362
|
+
include RBS::DetailedMessageable
|
|
363
|
+
|
|
364
|
+
def initialize: (String message, location: Location[untyped, untyped]?) -> void
|
|
365
|
+
|
|
366
|
+
def location: () -> Location[untyped, untyped]?
|
|
367
|
+
end
|
|
360
368
|
end
|
data/sig/rbs.rbs
CHANGED
data/sig/test/errors.rbs
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module RBS
|
|
2
|
+
module Test
|
|
3
|
+
module Errors
|
|
4
|
+
type t = ArgumentTypeError | BlockArgumentError | ArgumentError | BlockArgumentError | ReturnTypeError | BlockReturnTypeError
|
|
5
|
+
| UnexpectedBlockError | MissingBlockError | UnresolvedOverloadingError
|
|
6
|
+
|
|
7
|
+
# Type of a argument value given to a method call is not compatible with the type from method type
|
|
8
|
+
class ArgumentTypeError
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Type of a argument value given to a block yield is not compatible with the type from method type
|
|
12
|
+
class BlockArgumentTypeError
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Incompatible number of args/keyword args is given to a method call
|
|
16
|
+
class ArgumentError
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Incompatible number of args is given to a block yield
|
|
20
|
+
class BlockArgumentError
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Type of return value from a method call is incompatible
|
|
24
|
+
class ReturnTypeError
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Type of return value from a block yield is incompatible
|
|
28
|
+
class BlockReturnTypeError
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Unexpected block is given
|
|
32
|
+
class UnexpectedBlockError
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Required block is missing
|
|
36
|
+
class MissingBlockError
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Any other error
|
|
40
|
+
class UnresolvedOverloadingError
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.format_param: (Types::Function::Param) -> String
|
|
44
|
+
|
|
45
|
+
RESPOND_TO: UnboundMethod
|
|
46
|
+
|
|
47
|
+
def self.inspect_: (untyped) -> String
|
|
48
|
+
|
|
49
|
+
def self.to_string: (t) -> String
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module RBS
|
|
2
|
+
module Test
|
|
3
|
+
class TypeCheck
|
|
4
|
+
def initialize: (self_class: Module, builder: DefinitionBuilder, sample_size: Integer, unchecked_classes: Array[Module], instance_class: Module, class_class: Module) -> void
|
|
5
|
+
|
|
6
|
+
# Confirm if given `CallTrace` is compatible with `MethodType`
|
|
7
|
+
#
|
|
8
|
+
# Returns an array with detected errors.
|
|
9
|
+
#
|
|
10
|
+
def method_call: (Symbol, MethodType, CallTrace, errors: Array[Errors::t]) -> Array[Errors::t]
|
|
11
|
+
|
|
12
|
+
# Test if given `value` is compatible to type
|
|
13
|
+
#
|
|
14
|
+
# Returns `true` if the value has the type.
|
|
15
|
+
#
|
|
16
|
+
def value: (untyped value, Types::t) -> bool
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|