rbi 0.1.13 → 0.2.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/Gemfile +2 -2
- data/lib/rbi/formatter.rb +4 -16
- data/lib/rbi/index.rb +1 -1
- data/lib/rbi/model.rb +38 -36
- data/lib/rbi/parser.rb +90 -53
- data/lib/rbi/printer.rb +512 -611
- data/lib/rbi/rewriters/attr_to_methods.rb +169 -0
- data/lib/rbi/rewriters/flatten_singleton_methods.rb +65 -0
- data/lib/rbi/rewriters/flatten_visibilities.rb +65 -0
- data/lib/rbi/rewriters/group_nodes.rb +46 -47
- data/lib/rbi/rewriters/merge_trees.rb +15 -45
- data/lib/rbi/rewriters/{nest_non_public_methods.rb → nest_non_public_members.rb} +4 -4
- data/lib/rbi/rewriters/nest_top_level_members.rb +68 -0
- data/lib/rbi/type.rb +765 -0
- data/lib/rbi/type_parser.rb +320 -0
- data/lib/rbi/type_visitor.rb +112 -0
- data/lib/rbi/version.rb +1 -1
- data/lib/rbi/visitor.rb +228 -2
- data/lib/rbi.rb +15 -1
- metadata +19 -18
data/lib/rbi/type.rb
ADDED
@@ -0,0 +1,765 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RBI
|
5
|
+
# The base class for all RBI types.
|
6
|
+
class Type
|
7
|
+
extend T::Sig
|
8
|
+
extend T::Helpers
|
9
|
+
|
10
|
+
abstract!
|
11
|
+
|
12
|
+
# Simple
|
13
|
+
|
14
|
+
# A type that represents a simple class name like `String` or `Foo`.
|
15
|
+
#
|
16
|
+
# It can also be a qualified name like `::Foo` or `Foo::Bar`.
|
17
|
+
class Simple < Type
|
18
|
+
extend T::Sig
|
19
|
+
|
20
|
+
sig { returns(String) }
|
21
|
+
attr_reader :name
|
22
|
+
|
23
|
+
sig { params(name: String).void }
|
24
|
+
def initialize(name)
|
25
|
+
super()
|
26
|
+
@name = name
|
27
|
+
end
|
28
|
+
|
29
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
30
|
+
def ==(other)
|
31
|
+
Simple === other && @name == other.name
|
32
|
+
end
|
33
|
+
|
34
|
+
sig { override.returns(String) }
|
35
|
+
def to_rbi
|
36
|
+
@name
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Literals
|
41
|
+
|
42
|
+
# `T.anything`.
|
43
|
+
class Anything < Type
|
44
|
+
extend T::Sig
|
45
|
+
|
46
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
47
|
+
def ==(other)
|
48
|
+
Anything === other
|
49
|
+
end
|
50
|
+
|
51
|
+
sig { override.returns(String) }
|
52
|
+
def to_rbi
|
53
|
+
"T.anything"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# `T.attached_class`.
|
58
|
+
class AttachedClass < Type
|
59
|
+
extend T::Sig
|
60
|
+
|
61
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
62
|
+
def ==(other)
|
63
|
+
AttachedClass === other
|
64
|
+
end
|
65
|
+
|
66
|
+
sig { override.returns(String) }
|
67
|
+
def to_rbi
|
68
|
+
"T.attached_class"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# `T::Boolean`.
|
73
|
+
class Boolean < Type
|
74
|
+
extend T::Sig
|
75
|
+
|
76
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
77
|
+
def ==(other)
|
78
|
+
Boolean === other
|
79
|
+
end
|
80
|
+
|
81
|
+
sig { override.returns(String) }
|
82
|
+
def to_rbi
|
83
|
+
"T::Boolean"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# `T.noreturn`.
|
88
|
+
class NoReturn < Type
|
89
|
+
extend T::Sig
|
90
|
+
|
91
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
92
|
+
def ==(other)
|
93
|
+
NoReturn === other
|
94
|
+
end
|
95
|
+
|
96
|
+
sig { override.returns(String) }
|
97
|
+
def to_rbi
|
98
|
+
"T.noreturn"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# `T.self_type`.
|
103
|
+
class SelfType < Type
|
104
|
+
extend T::Sig
|
105
|
+
|
106
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
107
|
+
def ==(other)
|
108
|
+
SelfType === other
|
109
|
+
end
|
110
|
+
|
111
|
+
sig { override.returns(String) }
|
112
|
+
def to_rbi
|
113
|
+
"T.self_type"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# `T.untyped`.
|
118
|
+
class Untyped < Type
|
119
|
+
extend T::Sig
|
120
|
+
|
121
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
122
|
+
def ==(other)
|
123
|
+
Untyped === other
|
124
|
+
end
|
125
|
+
|
126
|
+
sig { override.returns(String) }
|
127
|
+
def to_rbi
|
128
|
+
"T.untyped"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# `void`.
|
133
|
+
class Void < Type
|
134
|
+
extend T::Sig
|
135
|
+
|
136
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
137
|
+
def ==(other)
|
138
|
+
Void === other
|
139
|
+
end
|
140
|
+
|
141
|
+
sig { override.returns(String) }
|
142
|
+
def to_rbi
|
143
|
+
"void"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Composites
|
148
|
+
|
149
|
+
# The class of another type like `T::Class[Foo]`.
|
150
|
+
class Class < Type
|
151
|
+
extend T::Sig
|
152
|
+
|
153
|
+
sig { returns(Type) }
|
154
|
+
attr_reader :type
|
155
|
+
|
156
|
+
sig { params(type: Type).void }
|
157
|
+
def initialize(type)
|
158
|
+
super()
|
159
|
+
@type = type
|
160
|
+
end
|
161
|
+
|
162
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
163
|
+
def ==(other)
|
164
|
+
Class === other && @type == other.type
|
165
|
+
end
|
166
|
+
|
167
|
+
sig { override.returns(String) }
|
168
|
+
def to_rbi
|
169
|
+
"T::Class[#{@type}]"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# The singleton class of another type like `T.class_of(Foo)`.
|
174
|
+
class ClassOf < Type
|
175
|
+
extend T::Sig
|
176
|
+
|
177
|
+
sig { returns(Simple) }
|
178
|
+
attr_reader :type
|
179
|
+
|
180
|
+
sig { returns(T.nilable(Type)) }
|
181
|
+
attr_reader :type_parameter
|
182
|
+
|
183
|
+
sig { params(type: Simple, type_parameter: T.nilable(Type)).void }
|
184
|
+
def initialize(type, type_parameter = nil)
|
185
|
+
super()
|
186
|
+
@type = type
|
187
|
+
@type_parameter = type_parameter
|
188
|
+
end
|
189
|
+
|
190
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
191
|
+
def ==(other)
|
192
|
+
ClassOf === other && @type == other.type && @type_parameter == other.type_parameter
|
193
|
+
end
|
194
|
+
|
195
|
+
sig { override.returns(String) }
|
196
|
+
def to_rbi
|
197
|
+
if @type_parameter
|
198
|
+
"T.class_of(#{@type.to_rbi})[#{@type_parameter.to_rbi}]"
|
199
|
+
else
|
200
|
+
"T.class_of(#{@type.to_rbi})"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# A type that can be `nil` like `T.nilable(String)`.
|
206
|
+
class Nilable < Type
|
207
|
+
extend T::Sig
|
208
|
+
|
209
|
+
sig { returns(Type) }
|
210
|
+
attr_reader :type
|
211
|
+
|
212
|
+
sig { params(type: Type).void }
|
213
|
+
def initialize(type)
|
214
|
+
super()
|
215
|
+
@type = type
|
216
|
+
end
|
217
|
+
|
218
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
219
|
+
def ==(other)
|
220
|
+
Nilable === other && @type == other.type
|
221
|
+
end
|
222
|
+
|
223
|
+
sig { override.returns(String) }
|
224
|
+
def to_rbi
|
225
|
+
"T.nilable(#{@type.to_rbi})"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# A type that is composed of multiple types like `T.all(String, Integer)`.
|
230
|
+
class Composite < Type
|
231
|
+
extend T::Sig
|
232
|
+
extend T::Helpers
|
233
|
+
|
234
|
+
abstract!
|
235
|
+
|
236
|
+
sig { returns(T::Array[Type]) }
|
237
|
+
attr_reader :types
|
238
|
+
|
239
|
+
sig { params(types: T::Array[Type]).void }
|
240
|
+
def initialize(types)
|
241
|
+
super()
|
242
|
+
@types = types
|
243
|
+
end
|
244
|
+
|
245
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
246
|
+
def ==(other)
|
247
|
+
self.class === other && @types.sort_by(&:to_rbi) == other.types.sort_by(&:to_rbi)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# A type that is intersection of multiple types like `T.all(String, Integer)`.
|
252
|
+
class All < Composite
|
253
|
+
extend T::Sig
|
254
|
+
|
255
|
+
sig { override.returns(String) }
|
256
|
+
def to_rbi
|
257
|
+
"T.all(#{@types.map(&:to_rbi).join(", ")})"
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
# A type that is union of multiple types like `T.any(String, Integer)`.
|
262
|
+
class Any < Composite
|
263
|
+
extend T::Sig
|
264
|
+
|
265
|
+
sig { override.returns(String) }
|
266
|
+
def to_rbi
|
267
|
+
"T.any(#{@types.map(&:to_rbi).join(", ")})"
|
268
|
+
end
|
269
|
+
|
270
|
+
sig { returns(T::Boolean) }
|
271
|
+
def nilable?
|
272
|
+
@types.any? { |type| type.nilable? || (type.is_a?(Simple) && type.name == "NilClass") }
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
# Generics
|
277
|
+
|
278
|
+
# A generic type like `T::Array[String]` or `T::Hash[Symbol, Integer]`.
|
279
|
+
class Generic < Type
|
280
|
+
extend T::Sig
|
281
|
+
|
282
|
+
sig { returns(String) }
|
283
|
+
attr_reader :name
|
284
|
+
|
285
|
+
sig { returns(T::Array[Type]) }
|
286
|
+
attr_reader :params
|
287
|
+
|
288
|
+
sig { params(name: String, params: Type).void }
|
289
|
+
def initialize(name, *params)
|
290
|
+
super()
|
291
|
+
@name = name
|
292
|
+
@params = T.let(params, T::Array[Type])
|
293
|
+
end
|
294
|
+
|
295
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
296
|
+
def ==(other)
|
297
|
+
Generic === other && @name == other.name && @params == other.params
|
298
|
+
end
|
299
|
+
|
300
|
+
sig { override.returns(String) }
|
301
|
+
def to_rbi
|
302
|
+
"#{@name}[#{@params.map(&:to_rbi).join(", ")}]"
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
# A type parameter like `T.type_parameter(:U)`.
|
307
|
+
class TypeParameter < Type
|
308
|
+
extend T::Sig
|
309
|
+
|
310
|
+
sig { returns(Symbol) }
|
311
|
+
attr_reader :name
|
312
|
+
|
313
|
+
sig { params(name: Symbol).void }
|
314
|
+
def initialize(name)
|
315
|
+
super()
|
316
|
+
@name = name
|
317
|
+
end
|
318
|
+
|
319
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
320
|
+
def ==(other)
|
321
|
+
TypeParameter === other && @name == other.name
|
322
|
+
end
|
323
|
+
|
324
|
+
sig { override.returns(String) }
|
325
|
+
def to_rbi
|
326
|
+
"T.type_parameter(#{@name.inspect})"
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
# Tuples and shapes
|
331
|
+
|
332
|
+
# A tuple type like `[String, Integer]`.
|
333
|
+
class Tuple < Type
|
334
|
+
extend T::Sig
|
335
|
+
|
336
|
+
sig { returns(T::Array[Type]) }
|
337
|
+
attr_reader :types
|
338
|
+
|
339
|
+
sig { params(types: T::Array[Type]).void }
|
340
|
+
def initialize(types)
|
341
|
+
super()
|
342
|
+
@types = types
|
343
|
+
end
|
344
|
+
|
345
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
346
|
+
def ==(other)
|
347
|
+
Tuple === other && @types == other.types
|
348
|
+
end
|
349
|
+
|
350
|
+
sig { override.returns(String) }
|
351
|
+
def to_rbi
|
352
|
+
"[#{@types.map(&:to_rbi).join(", ")}]"
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
# A shape type like `{name: String, age: Integer}`.
|
357
|
+
class Shape < Type
|
358
|
+
extend T::Sig
|
359
|
+
|
360
|
+
sig { returns(T::Hash[T.any(String, Symbol), Type]) }
|
361
|
+
attr_reader :types
|
362
|
+
|
363
|
+
sig { params(types: T::Hash[T.any(String, Symbol), Type]).void }
|
364
|
+
def initialize(types)
|
365
|
+
super()
|
366
|
+
@types = types
|
367
|
+
end
|
368
|
+
|
369
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
370
|
+
def ==(other)
|
371
|
+
Shape === other && @types.sort_by { |t| t.first.to_s } == other.types.sort_by { |t| t.first.to_s }
|
372
|
+
end
|
373
|
+
|
374
|
+
sig { override.returns(String) }
|
375
|
+
def to_rbi
|
376
|
+
if @types.empty?
|
377
|
+
"{}"
|
378
|
+
else
|
379
|
+
"{ " + @types.map { |name, type| "#{name}: #{type.to_rbi}" }.join(", ") + " }"
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
# Proc
|
385
|
+
|
386
|
+
# A proc type like `T.proc.void`.
|
387
|
+
class Proc < Type
|
388
|
+
extend T::Sig
|
389
|
+
|
390
|
+
sig { returns(T::Hash[Symbol, Type]) }
|
391
|
+
attr_reader :proc_params
|
392
|
+
|
393
|
+
sig { returns(Type) }
|
394
|
+
attr_reader :proc_returns
|
395
|
+
|
396
|
+
sig { returns(T.nilable(Type)) }
|
397
|
+
attr_reader :proc_bind
|
398
|
+
|
399
|
+
sig { void }
|
400
|
+
def initialize
|
401
|
+
super
|
402
|
+
@proc_params = T.let({}, T::Hash[Symbol, Type])
|
403
|
+
@proc_returns = T.let(Type.void, Type)
|
404
|
+
@proc_bind = T.let(nil, T.nilable(Type))
|
405
|
+
end
|
406
|
+
|
407
|
+
sig { override.params(other: BasicObject).returns(T::Boolean) }
|
408
|
+
def ==(other)
|
409
|
+
return false unless Proc === other
|
410
|
+
return false unless @proc_params == other.proc_params
|
411
|
+
return false unless @proc_returns == other.proc_returns
|
412
|
+
return false unless @proc_bind == other.proc_bind
|
413
|
+
|
414
|
+
true
|
415
|
+
end
|
416
|
+
|
417
|
+
sig { params(params: Type).returns(T.self_type) }
|
418
|
+
def params(**params)
|
419
|
+
@proc_params = params
|
420
|
+
self
|
421
|
+
end
|
422
|
+
|
423
|
+
sig { params(type: T.untyped).returns(T.self_type) }
|
424
|
+
def returns(type)
|
425
|
+
@proc_returns = type
|
426
|
+
self
|
427
|
+
end
|
428
|
+
|
429
|
+
sig { returns(T.self_type) }
|
430
|
+
def void
|
431
|
+
@proc_returns = RBI::Type.void
|
432
|
+
self
|
433
|
+
end
|
434
|
+
|
435
|
+
sig { params(type: T.untyped).returns(T.self_type) }
|
436
|
+
def bind(type)
|
437
|
+
@proc_bind = type
|
438
|
+
self
|
439
|
+
end
|
440
|
+
|
441
|
+
sig { override.returns(String) }
|
442
|
+
def to_rbi
|
443
|
+
rbi = +"T.proc"
|
444
|
+
|
445
|
+
if @proc_bind
|
446
|
+
rbi << ".bind(#{@proc_bind})"
|
447
|
+
end
|
448
|
+
|
449
|
+
unless @proc_params.empty?
|
450
|
+
rbi << ".params("
|
451
|
+
rbi << @proc_params.map { |name, type| "#{name}: #{type.to_rbi}" }.join(", ")
|
452
|
+
rbi << ")"
|
453
|
+
end
|
454
|
+
|
455
|
+
rbi << case @proc_returns
|
456
|
+
when Void
|
457
|
+
".void"
|
458
|
+
else
|
459
|
+
".returns(#{@proc_returns})"
|
460
|
+
end
|
461
|
+
|
462
|
+
rbi
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
# Type builder
|
467
|
+
|
468
|
+
class << self
|
469
|
+
extend T::Sig
|
470
|
+
|
471
|
+
# Simple
|
472
|
+
|
473
|
+
# Builds a simple type like `String` or `::Foo::Bar`.
|
474
|
+
#
|
475
|
+
# It raises a `NameError` if the name is not a valid Ruby class identifier.
|
476
|
+
sig { params(name: String).returns(Simple) }
|
477
|
+
def simple(name)
|
478
|
+
# TODO: should we allow creating the instance anyway and move this to a `validate!` method?
|
479
|
+
raise NameError, "Invalid type name: `#{name}`" unless valid_identifier?(name)
|
480
|
+
|
481
|
+
Simple.new(name)
|
482
|
+
end
|
483
|
+
|
484
|
+
# Literals
|
485
|
+
|
486
|
+
# Builds a type that represents `T.anything`.
|
487
|
+
sig { returns(Anything) }
|
488
|
+
def anything
|
489
|
+
Anything.new
|
490
|
+
end
|
491
|
+
|
492
|
+
# Builds a type that represents `T.attached_class`.
|
493
|
+
sig { returns(AttachedClass) }
|
494
|
+
def attached_class
|
495
|
+
AttachedClass.new
|
496
|
+
end
|
497
|
+
|
498
|
+
# Builds a type that represents `T::Boolean`.
|
499
|
+
sig { returns(Boolean) }
|
500
|
+
def boolean
|
501
|
+
Boolean.new
|
502
|
+
end
|
503
|
+
|
504
|
+
# Builds a type that represents `T.noreturn`.
|
505
|
+
sig { returns(NoReturn) }
|
506
|
+
def noreturn
|
507
|
+
NoReturn.new
|
508
|
+
end
|
509
|
+
|
510
|
+
# Builds a type that represents `T.self_type`.
|
511
|
+
sig { returns(SelfType) }
|
512
|
+
def self_type
|
513
|
+
SelfType.new
|
514
|
+
end
|
515
|
+
|
516
|
+
# Builds a type that represents `T.untyped`.
|
517
|
+
sig { returns(Untyped) }
|
518
|
+
def untyped
|
519
|
+
Untyped.new
|
520
|
+
end
|
521
|
+
|
522
|
+
# Builds a type that represents `void`.
|
523
|
+
sig { returns(Void) }
|
524
|
+
def void
|
525
|
+
Void.new
|
526
|
+
end
|
527
|
+
|
528
|
+
# Composites
|
529
|
+
|
530
|
+
# Builds a type that represents the class of another type like `T::Class[Foo]`.
|
531
|
+
sig { params(type: Type).returns(Class) }
|
532
|
+
def t_class(type)
|
533
|
+
Class.new(type)
|
534
|
+
end
|
535
|
+
|
536
|
+
# Builds a type that represents the singleton class of another type like `T.class_of(Foo)`.
|
537
|
+
sig { params(type: Simple, type_parameter: T.nilable(Type)).returns(ClassOf) }
|
538
|
+
def class_of(type, type_parameter = nil)
|
539
|
+
ClassOf.new(type, type_parameter)
|
540
|
+
end
|
541
|
+
|
542
|
+
# Builds a type that represents a nilable of another type like `T.nilable(String)`.
|
543
|
+
#
|
544
|
+
# Note that this method transforms types such as `T.nilable(T.untyped)` into `T.untyped`, so
|
545
|
+
# it may return something other than a `RBI::Type::Nilable`.
|
546
|
+
sig { params(type: Type).returns(Type) }
|
547
|
+
def nilable(type)
|
548
|
+
# TODO: should we move this logic to a `flatten!`, `normalize!` or `simplify!` method?
|
549
|
+
return type if type.is_a?(Untyped)
|
550
|
+
|
551
|
+
if type.nilable?
|
552
|
+
type
|
553
|
+
else
|
554
|
+
Nilable.new(type)
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
# Builds a type that represents an intersection of multiple types like `T.all(String, Integer)`.
|
559
|
+
#
|
560
|
+
# Note that this method transforms types such as `T.all(String, String)` into `String`, so
|
561
|
+
# it may return something other than a `All`.
|
562
|
+
sig { params(type1: Type, type2: Type, types: Type).returns(Type) }
|
563
|
+
def all(type1, type2, *types)
|
564
|
+
types = [type1, type2, *types]
|
565
|
+
|
566
|
+
# TODO: should we move this logic to a `flatten!`, `normalize!` or `simplify!` method?
|
567
|
+
flattened = types.flatten.flat_map do |type|
|
568
|
+
case type
|
569
|
+
when All
|
570
|
+
type.types
|
571
|
+
else
|
572
|
+
type
|
573
|
+
end
|
574
|
+
end.uniq
|
575
|
+
|
576
|
+
if flattened.size == 1
|
577
|
+
T.must(flattened.first)
|
578
|
+
else
|
579
|
+
raise ArgumentError, "RBI::Type.all should have at least 2 types supplied" if flattened.size < 2
|
580
|
+
|
581
|
+
All.new(flattened)
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
# Builds a type that represents a union of multiple types like `T.any(String, Integer)`.
|
586
|
+
#
|
587
|
+
# Note that this method transforms types such as `T.any(String, NilClass)` into `T.nilable(String)`, so
|
588
|
+
# it may return something other than a `Any`.
|
589
|
+
sig { params(type1: Type, type2: Type, types: Type).returns(Type) }
|
590
|
+
def any(type1, type2, *types)
|
591
|
+
types = [type1, type2, *types]
|
592
|
+
|
593
|
+
# TODO: should we move this logic to a `flatten!`, `normalize!` or `simplify!` method?
|
594
|
+
flattened = types.flatten.flat_map do |type|
|
595
|
+
case type
|
596
|
+
when Any
|
597
|
+
type.types
|
598
|
+
else
|
599
|
+
type
|
600
|
+
end
|
601
|
+
end
|
602
|
+
|
603
|
+
is_nilable = T.let(false, T::Boolean)
|
604
|
+
|
605
|
+
types = flattened.filter_map do |type|
|
606
|
+
case type
|
607
|
+
when Simple
|
608
|
+
if type.name == "NilClass"
|
609
|
+
is_nilable = true
|
610
|
+
nil
|
611
|
+
else
|
612
|
+
type
|
613
|
+
end
|
614
|
+
when Nilable
|
615
|
+
is_nilable = true
|
616
|
+
type.type
|
617
|
+
else
|
618
|
+
type
|
619
|
+
end
|
620
|
+
end.uniq
|
621
|
+
|
622
|
+
has_true_class = types.any? { |type| type.is_a?(Simple) && type.name == "TrueClass" }
|
623
|
+
has_false_class = types.any? { |type| type.is_a?(Simple) && type.name == "FalseClass" }
|
624
|
+
|
625
|
+
if has_true_class && has_false_class
|
626
|
+
types = types.reject { |type| type.is_a?(Simple) && (type.name == "TrueClass" || type.name == "FalseClass") }
|
627
|
+
types << boolean
|
628
|
+
end
|
629
|
+
|
630
|
+
type = case types.size
|
631
|
+
when 0
|
632
|
+
if is_nilable
|
633
|
+
is_nilable = false
|
634
|
+
simple("NilClass")
|
635
|
+
else
|
636
|
+
raise ArgumentError, "RBI::Type.any should have at least 2 types supplied"
|
637
|
+
end
|
638
|
+
when 1
|
639
|
+
T.must(types.first)
|
640
|
+
else
|
641
|
+
Any.new(types)
|
642
|
+
end
|
643
|
+
|
644
|
+
if is_nilable
|
645
|
+
nilable(type)
|
646
|
+
else
|
647
|
+
type
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
# Generics
|
652
|
+
|
653
|
+
# Builds a type that represents a generic type like `T::Array[String]` or `T::Hash[Symbol, Integer]`.
|
654
|
+
sig { params(name: String, params: T.any(Type, T::Array[Type])).returns(Generic) }
|
655
|
+
def generic(name, *params)
|
656
|
+
T.unsafe(Generic).new(name, *params.flatten)
|
657
|
+
end
|
658
|
+
|
659
|
+
# Builds a type that represents a type parameter like `T.type_parameter(:U)`.
|
660
|
+
sig { params(name: Symbol).returns(TypeParameter) }
|
661
|
+
def type_parameter(name)
|
662
|
+
TypeParameter.new(name)
|
663
|
+
end
|
664
|
+
|
665
|
+
# Tuples and shapes
|
666
|
+
|
667
|
+
# Builds a type that represents a tuple type like `[String, Integer]`.
|
668
|
+
sig { params(types: T.any(Type, T::Array[Type])).returns(Tuple) }
|
669
|
+
def tuple(*types)
|
670
|
+
Tuple.new(types.flatten)
|
671
|
+
end
|
672
|
+
|
673
|
+
# Builds a type that represents a shape type like `{name: String, age: Integer}`.
|
674
|
+
sig { params(types: T::Hash[T.any(String, Symbol), Type]).returns(Shape) }
|
675
|
+
def shape(types = {})
|
676
|
+
Shape.new(types)
|
677
|
+
end
|
678
|
+
|
679
|
+
# Proc
|
680
|
+
|
681
|
+
# Builds a type that represents a proc type like `T.proc.void`.
|
682
|
+
sig { returns(Proc) }
|
683
|
+
def proc
|
684
|
+
Proc.new
|
685
|
+
end
|
686
|
+
|
687
|
+
# We mark the constructor as `protected` because we want to force the use of factories on `Type` to create types
|
688
|
+
protected :new
|
689
|
+
|
690
|
+
private
|
691
|
+
|
692
|
+
sig { params(name: String).returns(T::Boolean) }
|
693
|
+
def valid_identifier?(name)
|
694
|
+
Prism.parse("class self::#{name.delete_prefix("::")}; end").success?
|
695
|
+
end
|
696
|
+
end
|
697
|
+
|
698
|
+
sig { void }
|
699
|
+
def initialize
|
700
|
+
@nilable = T.let(false, T::Boolean)
|
701
|
+
end
|
702
|
+
|
703
|
+
# Returns a new type that is `nilable` if it is not already.
|
704
|
+
#
|
705
|
+
# If the type is already nilable, it returns itself.
|
706
|
+
# ```ruby
|
707
|
+
# type = RBI::Type.simple("String")
|
708
|
+
# type.to_rbi # => "String"
|
709
|
+
# type.nilable.to_rbi # => "T.nilable(String)"
|
710
|
+
# type.nilable.nilable.to_rbi # => "T.nilable(String)"
|
711
|
+
# ```
|
712
|
+
sig { returns(Type) }
|
713
|
+
def nilable
|
714
|
+
Type.nilable(self)
|
715
|
+
end
|
716
|
+
|
717
|
+
# Returns the non-nilable version of the type.
|
718
|
+
# If the type is already non-nilable, it returns itself.
|
719
|
+
# If the type is nilable, it returns the inner type.
|
720
|
+
#
|
721
|
+
# ```ruby
|
722
|
+
# type = RBI::Type.nilable(RBI::Type.simple("String"))
|
723
|
+
# type.to_rbi # => "T.nilable(String)"
|
724
|
+
# type.non_nilable.to_rbi # => "String"
|
725
|
+
# type.non_nilable.non_nilable.to_rbi # => "String"
|
726
|
+
# ```
|
727
|
+
sig { returns(Type) }
|
728
|
+
def non_nilable
|
729
|
+
# TODO: Should this logic be moved into a builder method?
|
730
|
+
case self
|
731
|
+
when Nilable
|
732
|
+
type
|
733
|
+
else
|
734
|
+
self
|
735
|
+
end
|
736
|
+
end
|
737
|
+
|
738
|
+
# Returns whether the type is nilable.
|
739
|
+
sig { returns(T::Boolean) }
|
740
|
+
def nilable?
|
741
|
+
is_a?(Nilable)
|
742
|
+
end
|
743
|
+
|
744
|
+
sig { abstract.params(other: BasicObject).returns(T::Boolean) }
|
745
|
+
def ==(other); end
|
746
|
+
|
747
|
+
sig { params(other: BasicObject).returns(T::Boolean) }
|
748
|
+
def eql?(other)
|
749
|
+
self == other
|
750
|
+
end
|
751
|
+
|
752
|
+
sig { override.returns(Integer) }
|
753
|
+
def hash
|
754
|
+
to_rbi.hash
|
755
|
+
end
|
756
|
+
|
757
|
+
sig { abstract.returns(String) }
|
758
|
+
def to_rbi; end
|
759
|
+
|
760
|
+
sig { override.returns(String) }
|
761
|
+
def to_s
|
762
|
+
to_rbi
|
763
|
+
end
|
764
|
+
end
|
765
|
+
end
|