sorbet-runtime 0.4.4788 → 0.4.5059
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/sorbet-runtime.rb +5 -2
- data/lib/types/_types.rb +17 -6
- data/lib/types/boolean.rb +1 -1
- data/lib/types/configuration.rb +10 -0
- data/lib/types/enum.rb +343 -0
- data/lib/types/private/methods/signature_validation.rb +1 -5
- data/lib/types/private/types/type_alias.rb +26 -0
- data/lib/types/props/decorator.rb +24 -9
- data/lib/types/props/type_validation.rb +2 -0
- data/lib/types/props/utils.rb +3 -7
- data/lib/types/sig.rb +6 -6
- data/lib/types/types/attached_class.rb +33 -0
- data/lib/types/types/base.rb +10 -1
- data/lib/types/types/intersection.rb +1 -0
- data/lib/types/types/{opus_enum.rb → t_enum.rb} +3 -3
- data/lib/types/types/typed_enumerable.rb +1 -6
- data/lib/types/types/union.rb +1 -0
- data/lib/types/utils.rb +18 -3
- metadata +8 -8
- data/lib/types/private/error_handler.rb +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '08896772fcca300510e9b2e62c6a16bc70ee4f6eb3bb5409d6e0324f7ae98382'
|
|
4
|
+
data.tar.gz: 98abf40add7ee4518be064fd14b8eded16d8a326910409d9db13ec6a88e23ea1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 55a0df02cbade8623577ce15eb939435b7cb2fca7d2fc043a7fff25dc83d69659eb777021be2efc134c637a625566f84a6523577266f7f0b33bb23c0bcf2cc79
|
|
7
|
+
data.tar.gz: d0f9ae6831387b11d283e0badc92d5629e39dde5d5f8fa4d786a6f784b3bdc9648992485b0787e298a8c5bd8832642df83dcee17e346c337dd951c8daa80d959
|
data/lib/sorbet-runtime.rb
CHANGED
|
@@ -24,7 +24,6 @@ require_relative 'types/_types'
|
|
|
24
24
|
require_relative 'types/private/decl_state'
|
|
25
25
|
require_relative 'types/runtime_profiled'
|
|
26
26
|
require_relative 'types/private/class_utils'
|
|
27
|
-
require_relative 'types/private/error_handler'
|
|
28
27
|
require_relative 'types/private/runtime_levels'
|
|
29
28
|
require_relative 'types/private/methods/_methods'
|
|
30
29
|
require_relative 'types/sig'
|
|
@@ -43,9 +42,10 @@ require_relative 'types/types/fixed_hash'
|
|
|
43
42
|
require_relative 'types/types/intersection'
|
|
44
43
|
require_relative 'types/types/noreturn'
|
|
45
44
|
require_relative 'types/types/proc'
|
|
45
|
+
require_relative 'types/types/attached_class'
|
|
46
46
|
require_relative 'types/types/self_type'
|
|
47
47
|
require_relative 'types/types/simple'
|
|
48
|
-
require_relative 'types/types/
|
|
48
|
+
require_relative 'types/types/t_enum'
|
|
49
49
|
require_relative 'types/types/type_parameter'
|
|
50
50
|
require_relative 'types/types/typed_array'
|
|
51
51
|
require_relative 'types/types/typed_enumerator'
|
|
@@ -57,6 +57,7 @@ require_relative 'types/types/untyped'
|
|
|
57
57
|
require_relative 'types/private/types/not_typed'
|
|
58
58
|
require_relative 'types/private/types/void'
|
|
59
59
|
require_relative 'types/private/types/string_holder'
|
|
60
|
+
require_relative 'types/private/types/type_alias'
|
|
60
61
|
|
|
61
62
|
require_relative 'types/types/type_variable'
|
|
62
63
|
require_relative 'types/types/type_member'
|
|
@@ -98,6 +99,8 @@ require_relative 'types/props/constructor'
|
|
|
98
99
|
require_relative 'types/props/pretty_printable'
|
|
99
100
|
require_relative 'types/props/serializable'
|
|
100
101
|
require_relative 'types/props/type_validation'
|
|
102
|
+
|
|
101
103
|
require_relative 'types/struct'
|
|
104
|
+
require_relative 'types/enum'
|
|
102
105
|
|
|
103
106
|
require_relative 'types/compatibility_patches'
|
data/lib/types/_types.rb
CHANGED
|
@@ -65,6 +65,11 @@ module T
|
|
|
65
65
|
T::Types::SelfType.new
|
|
66
66
|
end
|
|
67
67
|
|
|
68
|
+
# Matches the instance type in a singleton-class context
|
|
69
|
+
def self.experimental_attached_class
|
|
70
|
+
T::Types::AttachedClassType.new
|
|
71
|
+
end
|
|
72
|
+
|
|
68
73
|
# Matches any class that subclasses or includes the provided class
|
|
69
74
|
# or module
|
|
70
75
|
def self.class_of(klass)
|
|
@@ -75,11 +80,11 @@ module T
|
|
|
75
80
|
## END OF THE METHODS TO PASS TO `sig`.
|
|
76
81
|
|
|
77
82
|
|
|
78
|
-
# Constructs a type alias. Used to create a short name for a larger
|
|
79
|
-
#
|
|
80
|
-
# needed for support by the static checker. Example usage:
|
|
83
|
+
# Constructs a type alias. Used to create a short name for a larger type. In Ruby this returns a
|
|
84
|
+
# wrapper that contains a proc that is evaluated to get the underlying type. This syntax however
|
|
85
|
+
# is needed for support by the static checker. Example usage:
|
|
81
86
|
#
|
|
82
|
-
# NilableString = T.type_alias
|
|
87
|
+
# NilableString = T.type_alias {T.nilable(String)}
|
|
83
88
|
#
|
|
84
89
|
# sig {params(arg: NilableString, default: String).returns(String)}
|
|
85
90
|
# def or_else(arg, default)
|
|
@@ -88,8 +93,14 @@ module T
|
|
|
88
93
|
#
|
|
89
94
|
# The name of the type alias is not preserved; Error messages will
|
|
90
95
|
# be printed with reference to the underlying type.
|
|
91
|
-
|
|
92
|
-
|
|
96
|
+
#
|
|
97
|
+
# TODO Remove `type` parameter. This was left in to make life easier while migrating.
|
|
98
|
+
def self.type_alias(type=nil, &blk)
|
|
99
|
+
if blk
|
|
100
|
+
T::Private::Types::TypeAlias.new(blk)
|
|
101
|
+
else
|
|
102
|
+
T::Utils.coerce(type)
|
|
103
|
+
end
|
|
93
104
|
end
|
|
94
105
|
|
|
95
106
|
# References a type paramater which was previously defined with
|
data/lib/types/boolean.rb
CHANGED
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
module T
|
|
5
5
|
# T::Boolean is a type alias helper for the common `T.any(TrueClass, FalseClass)`.
|
|
6
6
|
# Defined separately from _types.rb because it has a dependency on T::Types::Union.
|
|
7
|
-
Boolean = T.type_alias
|
|
7
|
+
Boolean = T.type_alias {T.any(TrueClass, FalseClass)}
|
|
8
8
|
end
|
data/lib/types/configuration.rb
CHANGED
|
@@ -356,6 +356,7 @@ module T::Configuration
|
|
|
356
356
|
String
|
|
357
357
|
Symbol
|
|
358
358
|
Time
|
|
359
|
+
T::Enum
|
|
359
360
|
}).freeze
|
|
360
361
|
|
|
361
362
|
def self.scalar_types
|
|
@@ -382,6 +383,15 @@ module T::Configuration
|
|
|
382
383
|
end
|
|
383
384
|
end
|
|
384
385
|
|
|
386
|
+
def self.enable_legacy_t_enum_migration_mode
|
|
387
|
+
@legacy_t_enum_migration_mode = true
|
|
388
|
+
end
|
|
389
|
+
def self.disable_legacy_t_enum_migration_mode
|
|
390
|
+
@legacy_t_enum_migration_mode = false
|
|
391
|
+
end
|
|
392
|
+
def self.legacy_t_enum_migration_mode?
|
|
393
|
+
@legacy_t_enum_migration_mode || false
|
|
394
|
+
end
|
|
385
395
|
|
|
386
396
|
private_class_method def self.validate_lambda_given!(value)
|
|
387
397
|
if !value.nil? && !value.respond_to?(:call)
|
data/lib/types/enum.rb
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# typed: strict
|
|
3
|
+
|
|
4
|
+
# Enumerations allow for type-safe declarations of a fixed set of values.
|
|
5
|
+
#
|
|
6
|
+
# Every value is a singleton instance of the class (i.e. `Suit::SPADE.is_a?(Suit) == true`).
|
|
7
|
+
#
|
|
8
|
+
# Each value has a corresponding serialized value. By default this is the constant's name converted
|
|
9
|
+
# to lowercase (e.g. `Suit::Club.serialize == 'club'`); however a custom value may be passed to the
|
|
10
|
+
# constructor. Enum will `freeze` the serialized value.
|
|
11
|
+
#
|
|
12
|
+
# @example Declaring an Enum:
|
|
13
|
+
# class Suit < T::Enum
|
|
14
|
+
# enums do
|
|
15
|
+
# CLUB = new
|
|
16
|
+
# SPADE = new
|
|
17
|
+
# DIAMOND = new
|
|
18
|
+
# HEART = new
|
|
19
|
+
# end
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# @example Custom serialization value:
|
|
23
|
+
# class Status < T::Enum
|
|
24
|
+
# enums do
|
|
25
|
+
# READY = new('rdy')
|
|
26
|
+
# ...
|
|
27
|
+
# end
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# @example Accessing values:
|
|
31
|
+
# Suit::SPADE
|
|
32
|
+
#
|
|
33
|
+
# @example Converting from serialized value to enum instance:
|
|
34
|
+
# Suit.deserialize('club') == Suit::CLUB
|
|
35
|
+
#
|
|
36
|
+
# @example Using enums in type signatures:
|
|
37
|
+
# sig {params(suit: Suit).returns(Boolean)}
|
|
38
|
+
# def is_red?(suit); ...; end
|
|
39
|
+
#
|
|
40
|
+
# WARNING: Enum instances are singletons that are shared among all their users. Their internals
|
|
41
|
+
# should be kept immutable to avoid unpredictable action at a distance.
|
|
42
|
+
class T::Enum
|
|
43
|
+
extend T::Sig
|
|
44
|
+
extend T::Props::CustomType
|
|
45
|
+
|
|
46
|
+
# TODO(jez) Might want to restrict this, or make subclasses provide this type
|
|
47
|
+
SerializedVal = T.type_alias {T.untyped}
|
|
48
|
+
private_constant :SerializedVal
|
|
49
|
+
|
|
50
|
+
## Enum class methods ##
|
|
51
|
+
sig {returns(T::Array[T.experimental_attached_class])}
|
|
52
|
+
def self.values
|
|
53
|
+
if @values.nil?
|
|
54
|
+
raise "Attempting to access values of #{self.class} before it has been initialized." \
|
|
55
|
+
" Enums are not initialized until the 'enums do' block they are defined in has finished running."
|
|
56
|
+
end
|
|
57
|
+
@values
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Convert from serialized value to enum instance
|
|
61
|
+
#
|
|
62
|
+
# Note: It would have been nice to make this method final before people started overriding it.
|
|
63
|
+
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
|
64
|
+
sig {params(serialized_val: SerializedVal).returns(T.nilable(T.experimental_attached_class)).checked(:never)}
|
|
65
|
+
def self.try_deserialize(serialized_val)
|
|
66
|
+
if @mapping.nil?
|
|
67
|
+
raise "Attempting to access serialization map of #{self.class} before it has been initialized." \
|
|
68
|
+
" Enums are not initialized until the 'enums do' block they are defined in has finished running."
|
|
69
|
+
end
|
|
70
|
+
@mapping[serialized_val]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Convert from serialized value to enum instance.
|
|
74
|
+
#
|
|
75
|
+
# Note: It would have been nice to make this method final before people started overriding it.
|
|
76
|
+
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
|
77
|
+
#
|
|
78
|
+
# @return [self]
|
|
79
|
+
# @raise [KeyError] if serialized value does not match any instance.
|
|
80
|
+
sig {overridable.params(serialized_val: SerializedVal).returns(T.experimental_attached_class).checked(:never)}
|
|
81
|
+
def self.from_serialized(serialized_val)
|
|
82
|
+
res = try_deserialize(serialized_val)
|
|
83
|
+
if res.nil?
|
|
84
|
+
raise KeyError.new("Enum #{self} key not found: #{serialized_val.inspect}")
|
|
85
|
+
end
|
|
86
|
+
res
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Note: It would have been nice to make this method final before people started overriding it.
|
|
90
|
+
# @return [Boolean] Does the given serialized value correspond with any of this enum's values.
|
|
91
|
+
sig {overridable.params(serialized_val: SerializedVal).returns(T::Boolean)}
|
|
92
|
+
def self.has_serialized?(serialized_val)
|
|
93
|
+
if @mapping.nil?
|
|
94
|
+
raise "Attempting to access serialization map of #{self.class} before it has been initialized." \
|
|
95
|
+
" Enums are not initialized until the 'enums do' block they are defined in has finished running."
|
|
96
|
+
end
|
|
97
|
+
@mapping.include?(serialized_val)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
## T::Props::CustomType
|
|
102
|
+
|
|
103
|
+
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
|
104
|
+
sig {params(value: T.untyped).returns(T::Boolean).checked(:never)}
|
|
105
|
+
def self.instance?(value)
|
|
106
|
+
value.is_a?(self)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
|
110
|
+
sig {params(instance: T.nilable(T::Enum)).returns(SerializedVal).checked(:never)}
|
|
111
|
+
def self.serialize(instance)
|
|
112
|
+
# This is needed otherwise if a Chalk::ODM::Document with a property of the shape
|
|
113
|
+
# T::Hash[T.nilable(MyEnum), Integer] and a value that looks like {nil => 0} is
|
|
114
|
+
# serialized, we throw the error on L102.
|
|
115
|
+
return nil if instance.nil?
|
|
116
|
+
|
|
117
|
+
if self == T::Enum
|
|
118
|
+
raise "Cannot call T::Enum.serialize directly. You must call on a specific child class."
|
|
119
|
+
end
|
|
120
|
+
if instance.class != self
|
|
121
|
+
raise "Cannot call #serialize on a value that is not an instance of #{self}."
|
|
122
|
+
end
|
|
123
|
+
instance.serialize
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
|
127
|
+
sig {params(mongo_value: SerializedVal).returns(T.experimental_attached_class).checked(:never)}
|
|
128
|
+
def self.deserialize(mongo_value)
|
|
129
|
+
if self == T::Enum
|
|
130
|
+
raise "Cannot call T::Enum.deserialize directly. You must call on a specific child class."
|
|
131
|
+
end
|
|
132
|
+
self.from_serialized(mongo_value)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
## Enum instance methods ##
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
sig {returns(T.self_type)}
|
|
140
|
+
def dup
|
|
141
|
+
self
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
sig {returns(T.self_type).checked(:tests)}
|
|
145
|
+
def clone
|
|
146
|
+
self
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Note: Failed CriticalMethodsNoRuntimeTypingTest
|
|
150
|
+
sig {returns(SerializedVal).checked(:never)}
|
|
151
|
+
def serialize
|
|
152
|
+
assert_bound!
|
|
153
|
+
@serialized_val
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
sig {params(args: T.untyped).returns(T.untyped)}
|
|
157
|
+
def to_json(*args)
|
|
158
|
+
serialize.to_json(*args)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
sig {returns(String)}
|
|
162
|
+
def to_s
|
|
163
|
+
inspect
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
sig {returns(String)}
|
|
167
|
+
def inspect
|
|
168
|
+
"#<#{self.class.name}::#{@const_name || '__UNINITIALIZED__'}>"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
sig {params(other: BasicObject).returns(T.nilable(Integer))}
|
|
172
|
+
def <=>(other)
|
|
173
|
+
case other
|
|
174
|
+
when self.class
|
|
175
|
+
self.serialize <=> other.serialize
|
|
176
|
+
else
|
|
177
|
+
nil
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
# NB: Do not call this method. This exists to allow for a safe migration path in places where enum
|
|
183
|
+
# values are compared directly against string values.
|
|
184
|
+
#
|
|
185
|
+
# Ruby's string has a weird quirk where `'my_string' == obj` calls obj.==('my_string') if obj
|
|
186
|
+
# responds to the `to_str` method. It does not actually call `to_str` however.
|
|
187
|
+
#
|
|
188
|
+
# See https://ruby-doc.org/core-2.4.0/String.html#method-i-3D-3D
|
|
189
|
+
sig {returns(String)}
|
|
190
|
+
def to_str
|
|
191
|
+
msg = 'Implicit conversion of Enum instances to strings is not allowed. Call #serialize instead.'
|
|
192
|
+
if T::Configuration.legacy_t_enum_migration_mode?
|
|
193
|
+
T::Configuration.soft_assert_handler(
|
|
194
|
+
msg,
|
|
195
|
+
storytime: {class: self.class.name},
|
|
196
|
+
)
|
|
197
|
+
serialize.to_s
|
|
198
|
+
else
|
|
199
|
+
raise NoMethodError.new(msg)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
sig {params(other: BasicObject).returns(T::Boolean).checked(:never)}
|
|
204
|
+
def ==(other)
|
|
205
|
+
case other
|
|
206
|
+
when String
|
|
207
|
+
if T::Configuration.legacy_t_enum_migration_mode?
|
|
208
|
+
comparison_assertion_failed(:==, other)
|
|
209
|
+
self.serialize == other
|
|
210
|
+
else
|
|
211
|
+
false
|
|
212
|
+
end
|
|
213
|
+
else
|
|
214
|
+
super(other)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
sig {params(other: BasicObject).returns(T::Boolean).checked(:never)}
|
|
219
|
+
def ===(other)
|
|
220
|
+
case other
|
|
221
|
+
when String
|
|
222
|
+
if T::Configuration.legacy_t_enum_migration_mode?
|
|
223
|
+
comparison_assertion_failed(:===, other)
|
|
224
|
+
self.serialize == other
|
|
225
|
+
else
|
|
226
|
+
false
|
|
227
|
+
end
|
|
228
|
+
else
|
|
229
|
+
super(other)
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
sig {params(method: Symbol, other: T.untyped).void}
|
|
234
|
+
private def comparison_assertion_failed(method, other)
|
|
235
|
+
T::Configuration.soft_assert_handler(
|
|
236
|
+
'Enum to string comparison not allowed. Compare to the Enum instance directly instead. See go/enum-migration',
|
|
237
|
+
storytime: {
|
|
238
|
+
class: self.class.name,
|
|
239
|
+
self: self.inspect,
|
|
240
|
+
other: other,
|
|
241
|
+
other_class: other.class.name,
|
|
242
|
+
method: method,
|
|
243
|
+
}
|
|
244
|
+
)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
## Private implementation ##
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
sig {params(serialized_val: SerializedVal).void}
|
|
252
|
+
private def initialize(serialized_val=nil)
|
|
253
|
+
raise 'T::Enum is abstract' if self.class == T::Enum
|
|
254
|
+
if !self.class.started_initializing?
|
|
255
|
+
raise "Must instantiate all enum values of #{self.class} inside 'enums do'."
|
|
256
|
+
end
|
|
257
|
+
if self.class.fully_initialized?
|
|
258
|
+
raise "Cannot instantiate a new enum value of #{self.class} after it has been initialized."
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
serialized_val = serialized_val.frozen? ? serialized_val : serialized_val.dup.freeze
|
|
262
|
+
@serialized_val = T.let(serialized_val, T.nilable(SerializedVal))
|
|
263
|
+
@const_name = T.let(nil, T.nilable(Symbol))
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
sig {returns(NilClass).checked(:never)}
|
|
267
|
+
private def assert_bound!
|
|
268
|
+
if @const_name.nil?
|
|
269
|
+
raise "Attempting to access Enum value on #{self.class} before it has been initialized." \
|
|
270
|
+
" Enums are not initialized until the 'enums do' block they are defined in has finished running."
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
sig {params(const_name: Symbol).void}
|
|
275
|
+
def _bind_name(const_name)
|
|
276
|
+
@const_name = const_name
|
|
277
|
+
@serialized_val = const_to_serialized_val(const_name) if @serialized_val.nil?
|
|
278
|
+
freeze
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
sig {params(const_name: Symbol).returns(String)}
|
|
282
|
+
private def const_to_serialized_val(const_name)
|
|
283
|
+
# Historical note: We convert to lowercase names because the majority of existing calls to
|
|
284
|
+
# `make_accessible` were arrays of lowercase strings. Doing this conversion allowed for the
|
|
285
|
+
# least amount of repetition in migrated declarations.
|
|
286
|
+
const_name.to_s.downcase.freeze
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
sig {returns(T::Boolean)}
|
|
290
|
+
def self.started_initializing?
|
|
291
|
+
@started_initializing = T.let(@started_initializing, T.nilable(T::Boolean))
|
|
292
|
+
@started_initializing ||= false
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
sig {returns(T::Boolean)}
|
|
296
|
+
def self.fully_initialized?
|
|
297
|
+
@fully_initialized = T.let(@fully_initialized, T.nilable(T::Boolean))
|
|
298
|
+
@fully_initialized ||= false
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Entrypoint for allowing people to register new enum values.
|
|
302
|
+
# All enum values must be defined within this block.
|
|
303
|
+
sig {params(blk: T.proc.void).void}
|
|
304
|
+
def self.enums(&blk)
|
|
305
|
+
raise "enums cannot be defined for T::Enum" if self == T::Enum
|
|
306
|
+
raise "Enum #{self} was already initialized" if @fully_initialized
|
|
307
|
+
raise "Enum #{self} is still initializing" if @started_initializing
|
|
308
|
+
|
|
309
|
+
@started_initializing = true
|
|
310
|
+
|
|
311
|
+
yield
|
|
312
|
+
|
|
313
|
+
@values = T.let(nil, T.nilable(T::Array[T.experimental_attached_class]))
|
|
314
|
+
@mapping = T.let(nil, T.nilable(T::Hash[SerializedVal, T.experimental_attached_class]))
|
|
315
|
+
|
|
316
|
+
# Freeze the Enum class and bind the constant names into each of the instances.
|
|
317
|
+
@mapping = {}
|
|
318
|
+
self.constants(false).each do |const_name|
|
|
319
|
+
instance = self.const_get(const_name, false)
|
|
320
|
+
if !instance.is_a?(self)
|
|
321
|
+
raise "Invalid constant #{self}::#{const_name} on enum. " \
|
|
322
|
+
"All constants defined for an enum must be instances itself (e.g. `Foo = new`)."
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
instance._bind_name(const_name)
|
|
326
|
+
serialized = instance.serialize
|
|
327
|
+
if @mapping.include?(serialized)
|
|
328
|
+
raise "Enum values must have unique serializations. Value '#{serialized}' is repeated on #{self}."
|
|
329
|
+
end
|
|
330
|
+
@mapping[serialized] = instance
|
|
331
|
+
end
|
|
332
|
+
@values = @mapping.values.sort.freeze
|
|
333
|
+
@mapping.freeze
|
|
334
|
+
@fully_initialized = true
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
sig {params(child_class: Module).void}
|
|
338
|
+
def self.inherited(child_class)
|
|
339
|
+
super
|
|
340
|
+
|
|
341
|
+
raise "Inheriting from children of T::Enum is prohibited" if self != T::Enum
|
|
342
|
+
end
|
|
343
|
+
end
|
|
@@ -58,11 +58,7 @@ module T::Private::Methods::SignatureValidation
|
|
|
58
58
|
def self.validate_override_mode(signature, super_signature)
|
|
59
59
|
case signature.mode
|
|
60
60
|
when *Modes::OVERRIDE_MODES
|
|
61
|
-
|
|
62
|
-
raise "You declared `#{signature.method_name}` as #{pretty_mode(signature)}, but the method it overrides is not declared as `overridable` or `abstract`.\n" \
|
|
63
|
-
" Parent definition: #{method_loc_str(super_signature.method)}\n" \
|
|
64
|
-
" Child definition: #{method_loc_str(signature.method)}\n"
|
|
65
|
-
end
|
|
61
|
+
# Peaceful
|
|
66
62
|
when *Modes::NON_OVERRIDE_MODES
|
|
67
63
|
if super_signature.mode == Modes.standard
|
|
68
64
|
# Peaceful
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# typed: true
|
|
3
|
+
|
|
4
|
+
module T::Private::Types
|
|
5
|
+
# Wraps a proc for a type alias to defer its evaluation.
|
|
6
|
+
class TypeAlias < T::Types::Base
|
|
7
|
+
|
|
8
|
+
def initialize(callable)
|
|
9
|
+
@callable = callable
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def aliased_type
|
|
13
|
+
@aliased_type ||= T::Utils.coerce(@callable.call)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @override Base
|
|
17
|
+
def name
|
|
18
|
+
aliased_type.name
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @override Base
|
|
22
|
+
def valid?(obj)
|
|
23
|
+
aliased_type.valid?(obj)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
class T::Props::Decorator
|
|
11
11
|
extend T::Sig
|
|
12
12
|
|
|
13
|
-
Rules = T.type_alias
|
|
14
|
-
DecoratedClass = T.type_alias
|
|
15
|
-
DecoratedInstance = T.type_alias
|
|
16
|
-
PropType = T.type_alias
|
|
17
|
-
PropTypeOrClass = T.type_alias
|
|
13
|
+
Rules = T.type_alias {T::Hash[Symbol, T.untyped]}
|
|
14
|
+
DecoratedClass = T.type_alias {T.untyped} # T.class_of(T::Props), but that produces circular reference errors in some circumstances
|
|
15
|
+
DecoratedInstance = T.type_alias {T.untyped} # Would be T::Props, but that produces circular reference errors in some circumstances
|
|
16
|
+
PropType = T.type_alias {T.any(T::Types::Base, T::Props::CustomType)}
|
|
17
|
+
PropTypeOrClass = T.type_alias {T.any(PropType, Module)}
|
|
18
18
|
|
|
19
19
|
class NoRulesError < StandardError; end
|
|
20
20
|
|
|
@@ -156,10 +156,27 @@ class T::Props::Decorator
|
|
|
156
156
|
else
|
|
157
157
|
type_object.valid?(val)
|
|
158
158
|
end
|
|
159
|
+
|
|
159
160
|
if !valid
|
|
160
161
|
raise T::Props::InvalidValueError.new("Can't set #{@class.name}.#{prop} to #{val.inspect} " \
|
|
161
162
|
"(instance of #{val.class}) - need a #{type_object}")
|
|
162
163
|
end
|
|
164
|
+
rescue T::Props::InvalidValueError => err
|
|
165
|
+
caller_loc = T.must(caller_locations(8, 1))[0]
|
|
166
|
+
|
|
167
|
+
pretty_message = "Parameter '#{prop}': #{err.message}\n" \
|
|
168
|
+
"Caller: #{caller_loc.path}:#{caller_loc.lineno}\n"
|
|
169
|
+
|
|
170
|
+
T::Configuration.call_validation_error_handler(
|
|
171
|
+
nil,
|
|
172
|
+
message: err.message,
|
|
173
|
+
pretty_message: pretty_message,
|
|
174
|
+
kind: 'Parameter',
|
|
175
|
+
name: prop,
|
|
176
|
+
type: type,
|
|
177
|
+
value: val,
|
|
178
|
+
location: caller_loc,
|
|
179
|
+
)
|
|
163
180
|
end
|
|
164
181
|
|
|
165
182
|
# For performance, don't use named params here.
|
|
@@ -330,6 +347,7 @@ class T::Props::Decorator
|
|
|
330
347
|
.void
|
|
331
348
|
end
|
|
332
349
|
def prop_defined(name, cls, rules={})
|
|
350
|
+
cls = T::Utils.resolve_alias(cls)
|
|
333
351
|
if rules[:optional] == true
|
|
334
352
|
T::Configuration.hard_assert_handler(
|
|
335
353
|
'Use of `optional: true` is deprecated, please use `T.nilable(...)` instead.',
|
|
@@ -534,7 +552,7 @@ class T::Props::Decorator
|
|
|
534
552
|
nil
|
|
535
553
|
end
|
|
536
554
|
|
|
537
|
-
# returns the type of the hash key, or nil. Any CustomType could be a key, but we only expect
|
|
555
|
+
# returns the type of the hash key, or nil. Any CustomType could be a key, but we only expect T::Enum right now.
|
|
538
556
|
sig do
|
|
539
557
|
params(type: PropType)
|
|
540
558
|
.returns(T.nilable(Module))
|
|
@@ -553,9 +571,6 @@ class T::Props::Decorator
|
|
|
553
571
|
|
|
554
572
|
# From T::Props::Utils.deep_clone_object, plus String
|
|
555
573
|
TYPES_NOT_NEEDING_CLONE = [TrueClass, FalseClass, NilClass, Symbol, String, Numeric]
|
|
556
|
-
if defined?(Opus) && defined?(Opus::Enum)
|
|
557
|
-
TYPES_NOT_NEEDING_CLONE << Opus::Enum
|
|
558
|
-
end
|
|
559
574
|
|
|
560
575
|
sig {params(type: PropType).returns(T::Boolean)}
|
|
561
576
|
private def shallow_clone_ok(type)
|
|
@@ -64,6 +64,8 @@ module T::Props::TypeValidation
|
|
|
64
64
|
type.types.map {|subtype| find_invalid_subtype(subtype)}.compact.first
|
|
65
65
|
when T::Types::Enum, T::Types::ClassOf
|
|
66
66
|
nil
|
|
67
|
+
when T::Private::Types::TypeAlias
|
|
68
|
+
find_invalid_subtype(type.aliased_type)
|
|
67
69
|
when T::Types::Simple
|
|
68
70
|
# TODO Could we manage to define a whitelist, consisting of something
|
|
69
71
|
# like primitives, subdocs, DataInterfaces, and collections/enums/unions
|
data/lib/types/props/utils.rb
CHANGED
|
@@ -23,14 +23,10 @@ module T::Props::Utils
|
|
|
23
23
|
h
|
|
24
24
|
when Regexp
|
|
25
25
|
what.dup
|
|
26
|
+
when T::Enum
|
|
27
|
+
what
|
|
26
28
|
else
|
|
27
|
-
|
|
28
|
-
# being defined.
|
|
29
|
-
if defined?(Opus) && defined?(Opus::Enum) && what.class == Opus::Enum
|
|
30
|
-
what
|
|
31
|
-
else
|
|
32
|
-
what.clone
|
|
33
|
-
end
|
|
29
|
+
what.clone
|
|
34
30
|
end
|
|
35
31
|
freeze ? result.freeze : result
|
|
36
32
|
end
|
data/lib/types/sig.rb
CHANGED
|
@@ -7,15 +7,15 @@ module T::Sig
|
|
|
7
7
|
module WithoutRuntime
|
|
8
8
|
# At runtime, does nothing, but statically it is treated exactly the same
|
|
9
9
|
# as T::Sig#sig. Only use it in cases where you can't use T::Sig#sig.
|
|
10
|
-
def self.sig(
|
|
10
|
+
def self.sig(arg0=nil, &blk); end # rubocop:disable PrisonGuard/BanBuiltinMethodOverride
|
|
11
11
|
|
|
12
12
|
original_verbose = $VERBOSE
|
|
13
13
|
$VERBOSE = false
|
|
14
14
|
|
|
15
15
|
# At runtime, does nothing, but statically it is treated exactly the same
|
|
16
16
|
# as T::Sig#sig. Only use it in cases where you can't use T::Sig#sig.
|
|
17
|
-
T::Sig::WithoutRuntime.sig {params(
|
|
18
|
-
def self.sig(
|
|
17
|
+
T::Sig::WithoutRuntime.sig {params(arg0: T.nilable(Symbol), blk: T.proc.bind(T::Private::Methods::DeclBuilder).void).void}
|
|
18
|
+
def self.sig(arg0=nil, &blk); end # rubocop:disable PrisonGuard/BanBuiltinMethodOverride, Lint/DuplicateMethods
|
|
19
19
|
|
|
20
20
|
$VERBOSE = original_verbose
|
|
21
21
|
end
|
|
@@ -23,8 +23,8 @@ module T::Sig
|
|
|
23
23
|
# Declares a method with type signatures and/or
|
|
24
24
|
# abstract/override/... helpers. See the documentation URL on
|
|
25
25
|
# {T::Helpers}
|
|
26
|
-
T::Sig::WithoutRuntime.sig {params(
|
|
27
|
-
def sig(
|
|
28
|
-
T::Private::Methods.declare_sig(self,
|
|
26
|
+
T::Sig::WithoutRuntime.sig {params(arg0: T.nilable(Symbol), blk: T.proc.bind(T::Private::Methods::DeclBuilder).void).void}
|
|
27
|
+
def sig(arg0=nil, &blk) # rubocop:disable PrisonGuard/BanBuiltinMethodOverride
|
|
28
|
+
T::Private::Methods.declare_sig(self, arg0, &blk)
|
|
29
29
|
end
|
|
30
30
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# typed: true
|
|
3
|
+
|
|
4
|
+
module T::Types
|
|
5
|
+
# Modeling AttachedClass properly at runtime would require additional
|
|
6
|
+
# tracking, so at runtime we permit all values and rely on the static checker.
|
|
7
|
+
# As AttachedClass is modeled statically as a type member on every singleton
|
|
8
|
+
# class, this is consistent with the runtime behavior for all type members.
|
|
9
|
+
class AttachedClassType < Base
|
|
10
|
+
|
|
11
|
+
def initialize(); end
|
|
12
|
+
|
|
13
|
+
# @override Base
|
|
14
|
+
def name
|
|
15
|
+
"AttachedClass"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @override Base
|
|
19
|
+
def valid?(obj)
|
|
20
|
+
true
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @override Base
|
|
24
|
+
private def subtype_of_single?(other)
|
|
25
|
+
case other
|
|
26
|
+
when AttachedClassType
|
|
27
|
+
true
|
|
28
|
+
else
|
|
29
|
+
false
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/types/types/base.rb
CHANGED
|
@@ -41,6 +41,14 @@ module T::Types
|
|
|
41
41
|
def subtype_of?(t2)
|
|
42
42
|
t1 = self
|
|
43
43
|
|
|
44
|
+
if t2.is_a?(T::Private::Types::TypeAlias)
|
|
45
|
+
t2 = t2.aliased_type
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
if t1.is_a?(T::Private::Types::TypeAlias)
|
|
49
|
+
return t1.aliased_type.subtype_of?(t2)
|
|
50
|
+
end
|
|
51
|
+
|
|
44
52
|
# pairs to cover: 1 (_, _)
|
|
45
53
|
# 2 (_, And)
|
|
46
54
|
# 3 (_, Or)
|
|
@@ -134,7 +142,8 @@ module T::Types
|
|
|
134
142
|
end
|
|
135
143
|
|
|
136
144
|
def ==(other)
|
|
137
|
-
other.class == self.class &&
|
|
145
|
+
(T::Utils.resolve_alias(other).class == T::Utils.resolve_alias(self).class) &&
|
|
146
|
+
other.name == self.name
|
|
138
147
|
end
|
|
139
148
|
|
|
140
149
|
alias_method :eql?, :==
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
# typed: true
|
|
3
3
|
|
|
4
4
|
module T::Types
|
|
5
|
-
# Validates that an object is equal to another
|
|
6
|
-
class
|
|
5
|
+
# Validates that an object is equal to another T::Enum singleton value.
|
|
6
|
+
class TEnum < Base
|
|
7
7
|
attr_reader :val
|
|
8
8
|
|
|
9
9
|
def initialize(val)
|
|
@@ -23,7 +23,7 @@ module T::Types
|
|
|
23
23
|
# @override Base
|
|
24
24
|
private def subtype_of_single?(other)
|
|
25
25
|
case other
|
|
26
|
-
when
|
|
26
|
+
when TEnum
|
|
27
27
|
@val == other.val
|
|
28
28
|
else
|
|
29
29
|
false
|
|
@@ -46,13 +46,8 @@ module T::Types
|
|
|
46
46
|
return false if !key_type.valid?(key) || !value_type.valid?(val)
|
|
47
47
|
end
|
|
48
48
|
return true
|
|
49
|
-
when Enumerator::Lazy
|
|
50
|
-
# Users don't want these walked
|
|
51
|
-
return true
|
|
52
49
|
when Enumerator
|
|
53
|
-
|
|
54
|
-
return false unless @type.valid?(elem)
|
|
55
|
-
end
|
|
50
|
+
# Enumerators can be unbounded: see `[:foo, :bar].cycle`
|
|
56
51
|
return true
|
|
57
52
|
when Range
|
|
58
53
|
@type.valid?(obj.first) && @type.valid?(obj.last)
|
data/lib/types/types/union.rb
CHANGED
data/lib/types/utils.rb
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
module T::Utils
|
|
5
5
|
# Used to convert from a type specification to a `T::Types::Base`.
|
|
6
6
|
def self.coerce(val)
|
|
7
|
-
if val.is_a?(T::Types::
|
|
7
|
+
if val.is_a?(T::Private::Types::TypeAlias)
|
|
8
|
+
val.aliased_type
|
|
9
|
+
elsif val.is_a?(T::Types::Base)
|
|
8
10
|
val
|
|
9
11
|
elsif val == ::Array
|
|
10
12
|
T::Array[T.untyped]
|
|
@@ -26,8 +28,11 @@ module T::Utils
|
|
|
26
28
|
T::Types::FixedHash.new(val) # rubocop:disable PrisonGuard/UseOpusTypesShortcut
|
|
27
29
|
elsif val.is_a?(T::Private::Methods::DeclBuilder)
|
|
28
30
|
T::Private::Methods.finalize_proc(val.decl)
|
|
29
|
-
elsif
|
|
30
|
-
T::Types::
|
|
31
|
+
elsif val.is_a?(::T::Enum)
|
|
32
|
+
T::Types::TEnum.new(val) # rubocop:disable PrisonGuard/UseOpusTypesShortcut
|
|
33
|
+
elsif val.is_a?(::String)
|
|
34
|
+
raise "Invalid String literal for type constraint. Must be an #{T::Types::Base}, a " \
|
|
35
|
+
"class/module, or an array. Got a String with value `#{val}`."
|
|
31
36
|
else
|
|
32
37
|
raise "Invalid value for type constraint. Must be an #{T::Types::Base}, a " \
|
|
33
38
|
"class/module, or an array. Got a `#{val.class}`."
|
|
@@ -76,6 +81,16 @@ module T::Utils
|
|
|
76
81
|
T::Private::Methods.run_all_sig_blocks
|
|
77
82
|
end
|
|
78
83
|
|
|
84
|
+
# Return the underlying type for a type alias. Otherwise returns type.
|
|
85
|
+
def self.resolve_alias(type)
|
|
86
|
+
case type
|
|
87
|
+
when T::Private::Types::TypeAlias
|
|
88
|
+
type.aliased_type
|
|
89
|
+
else
|
|
90
|
+
type
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
79
94
|
# Give a type which is a subclass of T::Types::Base, determines if the type is a simple nilable type (union of NilClass and something else).
|
|
80
95
|
# If so, returns the T::Types::Base of the something else. Otherwise, returns nil.
|
|
81
96
|
def self.unwrap_nilable(type)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sorbet-runtime
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.5059
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stripe
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2019-
|
|
11
|
+
date: 2019-11-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|
|
@@ -78,6 +78,7 @@ files:
|
|
|
78
78
|
- lib/types/boolean.rb
|
|
79
79
|
- lib/types/compatibility_patches.rb
|
|
80
80
|
- lib/types/configuration.rb
|
|
81
|
+
- lib/types/enum.rb
|
|
81
82
|
- lib/types/generic.rb
|
|
82
83
|
- lib/types/helpers.rb
|
|
83
84
|
- lib/types/interface_wrapper.rb
|
|
@@ -88,7 +89,6 @@ files:
|
|
|
88
89
|
- lib/types/private/casts.rb
|
|
89
90
|
- lib/types/private/class_utils.rb
|
|
90
91
|
- lib/types/private/decl_state.rb
|
|
91
|
-
- lib/types/private/error_handler.rb
|
|
92
92
|
- lib/types/private/final.rb
|
|
93
93
|
- lib/types/private/methods/_methods.rb
|
|
94
94
|
- lib/types/private/methods/call_validation.rb
|
|
@@ -101,6 +101,7 @@ files:
|
|
|
101
101
|
- lib/types/private/sealed.rb
|
|
102
102
|
- lib/types/private/types/not_typed.rb
|
|
103
103
|
- lib/types/private/types/string_holder.rb
|
|
104
|
+
- lib/types/private/types/type_alias.rb
|
|
104
105
|
- lib/types/private/types/void.rb
|
|
105
106
|
- lib/types/profile.rb
|
|
106
107
|
- lib/types/props/_props.rb
|
|
@@ -118,6 +119,7 @@ files:
|
|
|
118
119
|
- lib/types/runtime_profiled.rb
|
|
119
120
|
- lib/types/sig.rb
|
|
120
121
|
- lib/types/struct.rb
|
|
122
|
+
- lib/types/types/attached_class.rb
|
|
121
123
|
- lib/types/types/base.rb
|
|
122
124
|
- lib/types/types/class_of.rb
|
|
123
125
|
- lib/types/types/enum.rb
|
|
@@ -125,10 +127,10 @@ files:
|
|
|
125
127
|
- lib/types/types/fixed_hash.rb
|
|
126
128
|
- lib/types/types/intersection.rb
|
|
127
129
|
- lib/types/types/noreturn.rb
|
|
128
|
-
- lib/types/types/opus_enum.rb
|
|
129
130
|
- lib/types/types/proc.rb
|
|
130
131
|
- lib/types/types/self_type.rb
|
|
131
132
|
- lib/types/types/simple.rb
|
|
133
|
+
- lib/types/types/t_enum.rb
|
|
132
134
|
- lib/types/types/type_member.rb
|
|
133
135
|
- lib/types/types/type_parameter.rb
|
|
134
136
|
- lib/types/types/type_template.rb
|
|
@@ -145,7 +147,8 @@ files:
|
|
|
145
147
|
homepage: https://sorbet.run
|
|
146
148
|
licenses:
|
|
147
149
|
- Apache-2.0
|
|
148
|
-
metadata:
|
|
150
|
+
metadata:
|
|
151
|
+
source_code_uri: https://github.com/sorbet/sorbet
|
|
149
152
|
post_install_message:
|
|
150
153
|
rdoc_options: []
|
|
151
154
|
require_paths:
|
|
@@ -155,9 +158,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
155
158
|
- - ">="
|
|
156
159
|
- !ruby/object:Gem::Version
|
|
157
160
|
version: 2.3.0
|
|
158
|
-
- - "<"
|
|
159
|
-
- !ruby/object:Gem::Version
|
|
160
|
-
version: 2.7.0.preview1
|
|
161
161
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
162
162
|
requirements:
|
|
163
163
|
- - ">="
|
|
File without changes
|