sorbet-runtime 0.5.5841
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/sorbet-runtime.rb +116 -0
- data/lib/types/_types.rb +285 -0
- data/lib/types/abstract_utils.rb +50 -0
- data/lib/types/boolean.rb +8 -0
- data/lib/types/compatibility_patches.rb +95 -0
- data/lib/types/configuration.rb +428 -0
- data/lib/types/enum.rb +349 -0
- data/lib/types/generic.rb +23 -0
- data/lib/types/helpers.rb +39 -0
- data/lib/types/interface_wrapper.rb +158 -0
- data/lib/types/non_forcing_constants.rb +51 -0
- data/lib/types/private/abstract/data.rb +36 -0
- data/lib/types/private/abstract/declare.rb +48 -0
- data/lib/types/private/abstract/hooks.rb +43 -0
- data/lib/types/private/abstract/validate.rb +128 -0
- data/lib/types/private/casts.rb +22 -0
- data/lib/types/private/class_utils.rb +111 -0
- data/lib/types/private/decl_state.rb +30 -0
- data/lib/types/private/final.rb +51 -0
- data/lib/types/private/methods/_methods.rb +460 -0
- data/lib/types/private/methods/call_validation.rb +1149 -0
- data/lib/types/private/methods/decl_builder.rb +228 -0
- data/lib/types/private/methods/modes.rb +16 -0
- data/lib/types/private/methods/signature.rb +196 -0
- data/lib/types/private/methods/signature_validation.rb +229 -0
- data/lib/types/private/mixins/mixins.rb +27 -0
- data/lib/types/private/retry.rb +10 -0
- data/lib/types/private/runtime_levels.rb +56 -0
- data/lib/types/private/sealed.rb +65 -0
- data/lib/types/private/types/not_typed.rb +23 -0
- data/lib/types/private/types/string_holder.rb +26 -0
- data/lib/types/private/types/type_alias.rb +26 -0
- data/lib/types/private/types/void.rb +34 -0
- data/lib/types/profile.rb +31 -0
- data/lib/types/props/_props.rb +161 -0
- data/lib/types/props/constructor.rb +40 -0
- data/lib/types/props/custom_type.rb +108 -0
- data/lib/types/props/decorator.rb +672 -0
- data/lib/types/props/errors.rb +8 -0
- data/lib/types/props/generated_code_validation.rb +268 -0
- data/lib/types/props/has_lazily_specialized_methods.rb +92 -0
- data/lib/types/props/optional.rb +81 -0
- data/lib/types/props/plugin.rb +37 -0
- data/lib/types/props/pretty_printable.rb +107 -0
- data/lib/types/props/private/apply_default.rb +170 -0
- data/lib/types/props/private/deserializer_generator.rb +165 -0
- data/lib/types/props/private/parser.rb +32 -0
- data/lib/types/props/private/serde_transform.rb +192 -0
- data/lib/types/props/private/serializer_generator.rb +77 -0
- data/lib/types/props/private/setter_factory.rb +134 -0
- data/lib/types/props/serializable.rb +330 -0
- data/lib/types/props/type_validation.rb +111 -0
- data/lib/types/props/utils.rb +59 -0
- data/lib/types/props/weak_constructor.rb +67 -0
- data/lib/types/runtime_profiled.rb +24 -0
- data/lib/types/sig.rb +30 -0
- data/lib/types/struct.rb +18 -0
- data/lib/types/types/attached_class.rb +37 -0
- data/lib/types/types/base.rb +151 -0
- data/lib/types/types/class_of.rb +38 -0
- data/lib/types/types/enum.rb +42 -0
- data/lib/types/types/fixed_array.rb +60 -0
- data/lib/types/types/fixed_hash.rb +59 -0
- data/lib/types/types/intersection.rb +37 -0
- data/lib/types/types/noreturn.rb +29 -0
- data/lib/types/types/proc.rb +51 -0
- data/lib/types/types/self_type.rb +35 -0
- data/lib/types/types/simple.rb +33 -0
- data/lib/types/types/t_enum.rb +38 -0
- data/lib/types/types/type_member.rb +7 -0
- data/lib/types/types/type_parameter.rb +23 -0
- data/lib/types/types/type_template.rb +7 -0
- data/lib/types/types/type_variable.rb +31 -0
- data/lib/types/types/typed_array.rb +34 -0
- data/lib/types/types/typed_enumerable.rb +161 -0
- data/lib/types/types/typed_enumerator.rb +36 -0
- data/lib/types/types/typed_hash.rb +43 -0
- data/lib/types/types/typed_range.rb +26 -0
- data/lib/types/types/typed_set.rb +36 -0
- data/lib/types/types/union.rb +56 -0
- data/lib/types/types/untyped.rb +29 -0
- data/lib/types/utils.rb +217 -0
- metadata +223 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 02df0e4234d0887f7584ed03f2efd4ceabe7cd2aad902a198617207b02d92a6a
|
4
|
+
data.tar.gz: 3cef81d70c297f03d9b6307c32c7c6b079e120ac5a92681ff371bb3d010205b8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6e0cb83492e866202da027d8f8a5800a52fb7f0e3e4353952ec0250b28122704ad1bc5317ebd30b388df247d0a353afa239393aeafe3421d100d81a5f5456c81
|
7
|
+
data.tar.gz: 6a8b52a3830af73aec07c37bd6afba1081fbd47fbe0d37601803a1ccd73fa1edd08d9fbb233bb9c0556d81baff8571f791e723e7c84f117622c5fcf42ec91e40
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
# This file is hand-crafted to encode the dependencies. They load the whole type
|
5
|
+
# system since there is such a high chance of it being used, using an autoloader
|
6
|
+
# wouldn't buy us any startup time saving.
|
7
|
+
|
8
|
+
# Namespaces without any implementation
|
9
|
+
module T; end
|
10
|
+
module T::Helpers; end
|
11
|
+
module T::Private; end
|
12
|
+
module T::Private::Abstract; end
|
13
|
+
module T::Private::Types; end
|
14
|
+
|
15
|
+
require 'set'
|
16
|
+
|
17
|
+
# Each section is a group that I believe need a fixed ordering. There is also
|
18
|
+
# an ordering between groups.
|
19
|
+
|
20
|
+
# These are pre-reqs for almost everything in here.
|
21
|
+
require_relative 'types/configuration'
|
22
|
+
require_relative 'types/profile'
|
23
|
+
require_relative 'types/_types'
|
24
|
+
require_relative 'types/private/decl_state'
|
25
|
+
require_relative 'types/runtime_profiled'
|
26
|
+
require_relative 'types/private/class_utils'
|
27
|
+
require_relative 'types/private/runtime_levels'
|
28
|
+
require_relative 'types/private/methods/_methods'
|
29
|
+
require_relative 'types/sig'
|
30
|
+
require_relative 'types/helpers'
|
31
|
+
require_relative 'types/private/final'
|
32
|
+
require_relative 'types/private/sealed'
|
33
|
+
|
34
|
+
# The types themselves. First base classes
|
35
|
+
require_relative 'types/types/base'
|
36
|
+
require_relative 'types/types/typed_enumerable'
|
37
|
+
# Everything else
|
38
|
+
require_relative 'types/types/class_of'
|
39
|
+
require_relative 'types/types/enum'
|
40
|
+
require_relative 'types/types/fixed_array'
|
41
|
+
require_relative 'types/types/fixed_hash'
|
42
|
+
require_relative 'types/types/intersection'
|
43
|
+
require_relative 'types/types/noreturn'
|
44
|
+
require_relative 'types/types/proc'
|
45
|
+
require_relative 'types/types/attached_class'
|
46
|
+
require_relative 'types/types/self_type'
|
47
|
+
require_relative 'types/types/simple'
|
48
|
+
require_relative 'types/types/t_enum'
|
49
|
+
require_relative 'types/types/type_parameter'
|
50
|
+
require_relative 'types/types/typed_array'
|
51
|
+
require_relative 'types/types/typed_enumerator'
|
52
|
+
require_relative 'types/types/typed_hash'
|
53
|
+
require_relative 'types/types/typed_range'
|
54
|
+
require_relative 'types/types/typed_set'
|
55
|
+
require_relative 'types/types/union'
|
56
|
+
require_relative 'types/types/untyped'
|
57
|
+
require_relative 'types/private/types/not_typed'
|
58
|
+
require_relative 'types/private/types/void'
|
59
|
+
require_relative 'types/private/types/string_holder'
|
60
|
+
require_relative 'types/private/types/type_alias'
|
61
|
+
|
62
|
+
require_relative 'types/types/type_variable'
|
63
|
+
require_relative 'types/types/type_member'
|
64
|
+
require_relative 'types/types/type_template'
|
65
|
+
|
66
|
+
# Call validation
|
67
|
+
require_relative 'types/private/methods/modes'
|
68
|
+
require_relative 'types/private/methods/call_validation'
|
69
|
+
|
70
|
+
# Signature validation
|
71
|
+
require_relative 'types/private/methods/signature_validation'
|
72
|
+
require_relative 'types/abstract_utils'
|
73
|
+
require_relative 'types/private/abstract/validate'
|
74
|
+
|
75
|
+
# Catch all. Sort of built by `cd extn; find types -type f | grep -v test | sort`
|
76
|
+
require_relative 'types/generic'
|
77
|
+
require_relative 'types/interface_wrapper'
|
78
|
+
require_relative 'types/private/abstract/declare'
|
79
|
+
require_relative 'types/private/abstract/hooks'
|
80
|
+
require_relative 'types/private/casts'
|
81
|
+
require_relative 'types/private/methods/decl_builder'
|
82
|
+
require_relative 'types/private/methods/signature'
|
83
|
+
require_relative 'types/private/retry'
|
84
|
+
require_relative 'types/utils'
|
85
|
+
require_relative 'types/boolean'
|
86
|
+
|
87
|
+
# Props dependencies
|
88
|
+
require_relative 'types/private/abstract/data'
|
89
|
+
require_relative 'types/private/mixins/mixins'
|
90
|
+
require_relative 'types/props/_props'
|
91
|
+
require_relative 'types/props/custom_type'
|
92
|
+
require_relative 'types/props/decorator'
|
93
|
+
require_relative 'types/props/errors'
|
94
|
+
require_relative 'types/props/plugin'
|
95
|
+
require_relative 'types/props/utils'
|
96
|
+
require_relative 'types/enum'
|
97
|
+
# Props that run sigs statically so have to be after all the others :(
|
98
|
+
require_relative 'types/props/private/setter_factory'
|
99
|
+
require_relative 'types/props/private/apply_default'
|
100
|
+
require_relative 'types/props/has_lazily_specialized_methods'
|
101
|
+
require_relative 'types/props/optional'
|
102
|
+
require_relative 'types/props/weak_constructor'
|
103
|
+
require_relative 'types/props/constructor'
|
104
|
+
require_relative 'types/props/pretty_printable'
|
105
|
+
require_relative 'types/props/private/serde_transform'
|
106
|
+
require_relative 'types/props/private/deserializer_generator'
|
107
|
+
require_relative 'types/props/private/serializer_generator'
|
108
|
+
require_relative 'types/props/serializable'
|
109
|
+
require_relative 'types/props/type_validation'
|
110
|
+
require_relative 'types/props/private/parser'
|
111
|
+
require_relative 'types/props/generated_code_validation'
|
112
|
+
|
113
|
+
require_relative 'types/struct'
|
114
|
+
require_relative 'types/non_forcing_constants'
|
115
|
+
|
116
|
+
require_relative 'types/compatibility_patches'
|
data/lib/types/_types.rb
ADDED
@@ -0,0 +1,285 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
# This is where we define the shortcuts, so we can't use them here
|
4
|
+
# rubocop:disable PrisonGuard/UseOpusTypesShortcut
|
5
|
+
|
6
|
+
# _____
|
7
|
+
# |_ _| _ _ __ ___ ___
|
8
|
+
# | || | | | '_ \ / _ \/ __|
|
9
|
+
# | || |_| | |_) | __/\__ \
|
10
|
+
# |_| \__, | .__/ \___||___/
|
11
|
+
# |___/|_|
|
12
|
+
#
|
13
|
+
# Docs at https://sorbet.org/docs/sigs
|
14
|
+
#
|
15
|
+
# Types that you can pass to `sig`:
|
16
|
+
#
|
17
|
+
# - a Ruby class
|
18
|
+
#
|
19
|
+
# - [<Type>, <Type>, ...] -- to specify a "tuple"; a fixed-size array with known types for each member
|
20
|
+
#
|
21
|
+
# - {key: <Type>, key2: <Type>, ...} -- to speicfy a "shape"; a fixed-size hash
|
22
|
+
# with known keys and type values
|
23
|
+
#
|
24
|
+
# - Any of the `T.foo` methods below
|
25
|
+
|
26
|
+
module T
|
27
|
+
# T.any(<Type>, <Type>, ...) -- matches any of the types listed
|
28
|
+
def self.any(type_a, type_b, *types)
|
29
|
+
T::Types::Union.new([type_a, type_b] + types)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Shorthand for T.any(type, NilClass)
|
33
|
+
def self.nilable(type)
|
34
|
+
T::Types::Union.new([type, NilClass])
|
35
|
+
end
|
36
|
+
|
37
|
+
# Matches any object. In the static checker, T.untyped allows any
|
38
|
+
# method calls or operations.
|
39
|
+
def self.untyped
|
40
|
+
T::Types::Untyped::Private::INSTANCE
|
41
|
+
end
|
42
|
+
|
43
|
+
# Indicates a function never returns (e.g. "Kernel#raise")
|
44
|
+
def self.noreturn
|
45
|
+
T::Types::NoReturn::Private::INSTANCE
|
46
|
+
end
|
47
|
+
|
48
|
+
# T.all(<Type>, <Type>, ...) -- matches an object that has all of the types listed
|
49
|
+
def self.all(type_a, type_b, *types)
|
50
|
+
T::Types::Intersection.new([type_a, type_b] + types)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Matches any of the listed values
|
54
|
+
def self.enum(values)
|
55
|
+
T::Types::Enum.new(values)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Creates a proc type
|
59
|
+
def self.proc
|
60
|
+
T::Private::Methods.start_proc
|
61
|
+
end
|
62
|
+
|
63
|
+
# Matches `self`:
|
64
|
+
def self.self_type
|
65
|
+
T::Types::SelfType::Private::INSTANCE
|
66
|
+
end
|
67
|
+
|
68
|
+
# Matches the instance type in a singleton-class context
|
69
|
+
def self.attached_class
|
70
|
+
T::Types::AttachedClassType::Private::INSTANCE
|
71
|
+
end
|
72
|
+
|
73
|
+
# Matches any class that subclasses or includes the provided class
|
74
|
+
# or module
|
75
|
+
def self.class_of(klass)
|
76
|
+
T::Types::ClassOf.new(klass)
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
## END OF THE METHODS TO PASS TO `sig`.
|
81
|
+
|
82
|
+
|
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:
|
86
|
+
#
|
87
|
+
# NilableString = T.type_alias {T.nilable(String)}
|
88
|
+
#
|
89
|
+
# sig {params(arg: NilableString, default: String).returns(String)}
|
90
|
+
# def or_else(arg, default)
|
91
|
+
# arg || default
|
92
|
+
# end
|
93
|
+
#
|
94
|
+
# The name of the type alias is not preserved; Error messages will
|
95
|
+
# be printed with reference to the underlying type.
|
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
|
104
|
+
end
|
105
|
+
|
106
|
+
# References a type parameter which was previously defined with
|
107
|
+
# `type_parameters`.
|
108
|
+
#
|
109
|
+
# This is used for generic methods. Example usage:
|
110
|
+
#
|
111
|
+
# sig
|
112
|
+
# .type_parameters(:U)
|
113
|
+
# .params(
|
114
|
+
# blk: T.proc.params(arg0: Elem).returns(T.type_parameter(:U)),
|
115
|
+
# )
|
116
|
+
# .returns(T::Array[T.type_parameter(:U)])
|
117
|
+
# def map(&blk); end
|
118
|
+
def self.type_parameter(name)
|
119
|
+
T::Types::TypeParameter.new(name)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Tells the typechecker that `value` is of type `type`. Use this to get additional checking after
|
123
|
+
# an expression that the typechecker is unable to analyze. If `checked` is true, raises an
|
124
|
+
# exception at runtime if the value doesn't match the type.
|
125
|
+
#
|
126
|
+
# Compared to `T.let`, `T.cast` is _trusted_ by static system.
|
127
|
+
def self.cast(value, type, checked: true)
|
128
|
+
return value unless checked
|
129
|
+
|
130
|
+
Private::Casts.cast(value, type, cast_method: "T.cast")
|
131
|
+
end
|
132
|
+
|
133
|
+
# Tells the typechecker to declare a variable of type `type`. Use
|
134
|
+
# like:
|
135
|
+
#
|
136
|
+
# seconds = T.let(0.0, Float)
|
137
|
+
#
|
138
|
+
# Compared to `T.cast`, `T.let` is _checked_ by static system.
|
139
|
+
#
|
140
|
+
# If `checked` is true, raises an exception at runtime if the value
|
141
|
+
# doesn't match the type.
|
142
|
+
def self.let(value, type, checked: true)
|
143
|
+
return value unless checked
|
144
|
+
|
145
|
+
Private::Casts.cast(value, type, cast_method: "T.let")
|
146
|
+
end
|
147
|
+
|
148
|
+
# Tells the typechecker to ensure that `value` is of type `type` (if not, the typechecker will
|
149
|
+
# fail). Use this for debugging typechecking errors, or to ensure that type information is
|
150
|
+
# statically known and being checked appropriately. If `checked` is true, raises an exception at
|
151
|
+
# runtime if the value doesn't match the type.
|
152
|
+
def self.assert_type!(value, type, checked: true)
|
153
|
+
return value unless checked
|
154
|
+
|
155
|
+
Private::Casts.cast(value, type, cast_method: "T.assert_type!")
|
156
|
+
end
|
157
|
+
|
158
|
+
# For the static type checker, strips all type information from a value
|
159
|
+
# and returns the same value, but statically-typed as `T.untyped`.
|
160
|
+
# Can be used to tell the static checker to "trust you" by discarding type information
|
161
|
+
# you know to be incorrect. Use with care!
|
162
|
+
# (This has no effect at runtime.)
|
163
|
+
#
|
164
|
+
# We can't actually write this sig because we ourselves are inside
|
165
|
+
# the `T::` module and doing this would create a bootstrapping
|
166
|
+
# cycle. However, we also don't actually need to do so; An untyped
|
167
|
+
# identity method works just as well here.
|
168
|
+
#
|
169
|
+
# sig {params(value: T.untyped).returns(T.untyped)}
|
170
|
+
def self.unsafe(value)
|
171
|
+
value
|
172
|
+
end
|
173
|
+
|
174
|
+
# A convenience method to `raise` when the argument is `nil` and return it
|
175
|
+
# otherwise.
|
176
|
+
#
|
177
|
+
# Intended to be used as:
|
178
|
+
#
|
179
|
+
# needs_foo(T.must(maybe_gives_foo))
|
180
|
+
#
|
181
|
+
# Equivalent to:
|
182
|
+
#
|
183
|
+
# foo = maybe_gives_foo
|
184
|
+
# raise "nil" if foo.nil?
|
185
|
+
# needs_foo(foo)
|
186
|
+
#
|
187
|
+
# Intended to be used to promise sorbet that a given nilable value happens
|
188
|
+
# to contain a non-nil value at this point.
|
189
|
+
#
|
190
|
+
# sig {params(arg: T.nilable(A)).returns(A)}
|
191
|
+
def self.must(arg)
|
192
|
+
return arg if arg
|
193
|
+
return arg if arg == false
|
194
|
+
|
195
|
+
begin
|
196
|
+
raise TypeError.new("Passed `nil` into T.must")
|
197
|
+
rescue TypeError => e # raise into rescue to ensure e.backtrace is populated
|
198
|
+
T::Configuration.inline_type_error_handler(e)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# A way to ask Sorbet to show what type it thinks an expression has.
|
203
|
+
# This can be useful for debugging and checking assumptions.
|
204
|
+
# In the runtime, merely returns the value passed in.
|
205
|
+
def self.reveal_type(value)
|
206
|
+
value
|
207
|
+
end
|
208
|
+
|
209
|
+
# A way to ask Sorbet to prove that a certain branch of control flow never
|
210
|
+
# happens. Commonly used to assert that a case or if statement exhausts all
|
211
|
+
# possible cases.
|
212
|
+
def self.absurd(value)
|
213
|
+
msg = "Control flow reached T.absurd."
|
214
|
+
|
215
|
+
case value
|
216
|
+
when Kernel
|
217
|
+
msg += " Got value: #{value}"
|
218
|
+
end
|
219
|
+
|
220
|
+
begin
|
221
|
+
raise TypeError.new(msg)
|
222
|
+
rescue TypeError => e # raise into rescue to ensure e.backtrace is populated
|
223
|
+
T::Configuration.inline_type_error_handler(e)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
### Generic classes ###
|
228
|
+
|
229
|
+
module Array
|
230
|
+
def self.[](type)
|
231
|
+
if type.is_a?(T::Types::Untyped)
|
232
|
+
T::Types::TypedArray::Untyped.new
|
233
|
+
else
|
234
|
+
T::Types::TypedArray.new(type)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
module Hash
|
240
|
+
def self.[](keys, values)
|
241
|
+
if keys.is_a?(T::Types::Untyped) && values.is_a?(T::Types::Untyped)
|
242
|
+
T::Types::TypedHash::Untyped.new
|
243
|
+
else
|
244
|
+
T::Types::TypedHash.new(keys: keys, values: values)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
module Enumerable
|
250
|
+
def self.[](type)
|
251
|
+
if type.is_a?(T::Types::Untyped)
|
252
|
+
T::Types::TypedEnumerable::Untyped.new
|
253
|
+
else
|
254
|
+
T::Types::TypedEnumerable.new(type)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
module Enumerator
|
260
|
+
def self.[](type)
|
261
|
+
if type.is_a?(T::Types::Untyped)
|
262
|
+
T::Types::TypedEnumerator::Untyped.new
|
263
|
+
else
|
264
|
+
T::Types::TypedEnumerator.new(type)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
module Range
|
270
|
+
def self.[](type)
|
271
|
+
T::Types::TypedRange.new(type)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
module Set
|
276
|
+
def self.[](type)
|
277
|
+
if type.is_a?(T::Types::Untyped)
|
278
|
+
T::Types::TypedSet::Untyped.new
|
279
|
+
else
|
280
|
+
T::Types::TypedSet.new(type)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
# rubocop:enable PrisonGuard/UseOpusTypesShortcut
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module T::AbstractUtils
|
5
|
+
Methods = T::Private::Methods
|
6
|
+
|
7
|
+
# Returns whether a module is declared as abstract. After the module is finished being declared,
|
8
|
+
# this is equivalent to whether it has any abstract methods that haven't been implemented
|
9
|
+
# (because we validate that and raise an error otherwise).
|
10
|
+
#
|
11
|
+
# Note that checking `mod.is_a?(Abstract::Hooks)` is not a safe substitute for this method; when
|
12
|
+
# a class extends `Abstract::Hooks`, all of its subclasses, including the eventual concrete
|
13
|
+
# ones, will still have `Abstract::Hooks` as an ancestor.
|
14
|
+
def self.abstract_module?(mod)
|
15
|
+
!T::Private::Abstract::Data.get(mod, :abstract_type).nil?
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.abstract_method?(method)
|
19
|
+
signature = Methods.signature_for_method(method)
|
20
|
+
signature&.mode == Methods::Modes.abstract
|
21
|
+
end
|
22
|
+
|
23
|
+
# Given a module, returns the set of methods declared as abstract (in itself or ancestors)
|
24
|
+
# that have not been implemented.
|
25
|
+
def self.abstract_methods_for(mod)
|
26
|
+
declared_methods = declared_abstract_methods_for(mod)
|
27
|
+
declared_methods.select do |declared_method|
|
28
|
+
actual_method = mod.instance_method(declared_method.name)
|
29
|
+
# Note that in the case where an abstract method is overridden by another abstract method,
|
30
|
+
# this method will return them both. This is intentional to ensure we validate the final
|
31
|
+
# implementation against all declarations of an abstract method (they might not all have the
|
32
|
+
# same signature).
|
33
|
+
abstract_method?(actual_method)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Given a module, returns the set of methods declared as abstract (in itself or ancestors)
|
38
|
+
# regardless of whether they have been implemented.
|
39
|
+
def self.declared_abstract_methods_for(mod)
|
40
|
+
methods = []
|
41
|
+
mod.ancestors.each do |ancestor|
|
42
|
+
ancestor_methods = ancestor.private_instance_methods(false) + ancestor.instance_methods(false)
|
43
|
+
ancestor_methods.each do |method_name|
|
44
|
+
method = ancestor.instance_method(method_name)
|
45
|
+
methods << method if abstract_method?(method)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
methods
|
49
|
+
end
|
50
|
+
end
|