sorbet-runtime 0.6.12449 → 0.6.12872
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 +1 -1
- data/lib/types/_types.rb +12 -0
- data/lib/types/configuration.rb +2 -19
- data/lib/types/enum.rb +1 -1
- data/lib/types/private/abstract/data.rb +1 -1
- data/lib/types/private/methods/_methods.rb +36 -51
- data/lib/types/private/methods/call_validation.rb +10 -14
- data/lib/types/private/methods/signature_validation.rb +9 -3
- data/lib/types/private/sealed.rb +1 -1
- data/lib/types/props/_props.rb +5 -8
- data/lib/types/props/custom_type.rb +1 -1
- data/lib/types/props/decorator.rb +27 -48
- data/lib/types/props/has_lazily_specialized_methods.rb +1 -1
- data/lib/types/props/pretty_printable.rb +5 -5
- data/lib/types/props/private/apply_default.rb +4 -4
- data/lib/types/props/private/deserializer_generator.rb +10 -6
- data/lib/types/props/private/serde_transform.rb +4 -4
- data/lib/types/props/private/serializer_generator.rb +9 -5
- data/lib/types/props/private/setter_factory.rb +9 -9
- data/lib/types/props/serializable.rb +4 -9
- data/lib/types/props/type_validation.rb +2 -2
- data/lib/types/types/class_of.rb +1 -1
- data/lib/types/types/simple.rb +4 -4
- data/lib/types/types/t_enum.rb +2 -0
- data/lib/types/types/typed_array.rb +2 -2
- data/lib/types/types/typed_class.rb +1 -1
- data/lib/types/types/typed_enumerable.rb +6 -12
- data/lib/types/types/typed_enumerator.rb +2 -2
- data/lib/types/types/typed_enumerator_chain.rb +2 -2
- data/lib/types/types/typed_enumerator_lazy.rb +2 -2
- data/lib/types/types/typed_hash.rb +2 -2
- data/lib/types/types/typed_module.rb +102 -0
- data/lib/types/types/typed_range.rb +2 -2
- data/lib/types/types/typed_set.rb +2 -5
- metadata +5 -6
- data/lib/types/non_forcing_constants.rb +0 -55
- data/lib/types/private/methods/call_validation_2_6.rb +0 -1729
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f1df82030d7eef7b4581bd982da33dafd6667515045b5e32e36d95d2cd96e876
|
|
4
|
+
data.tar.gz: c6b5c03495c971851b599f2465ce86a983a23b7455b9766755b77da9916b2d38
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1491c37794b1e008c76728181aa3fdeb4fa7ac16c995d9c9d8477d7b5a6bd557c921781097d07f060b378de14648050cd773b35735ad46129fe074b888495fe4
|
|
7
|
+
data.tar.gz: 84d80bada939f468b9580708a11a63f3b08ab61c411b79d202afe294beab896f886213aa044d718170fcabced529be555ee08083be70b6f85f66ea61421ac6c2
|
data/lib/sorbet-runtime.rb
CHANGED
|
@@ -85,6 +85,7 @@ require_relative 'types/boolean'
|
|
|
85
85
|
|
|
86
86
|
# Depends on types/utils
|
|
87
87
|
require_relative 'types/types/typed_array'
|
|
88
|
+
require_relative 'types/types/typed_module'
|
|
88
89
|
require_relative 'types/types/typed_class'
|
|
89
90
|
|
|
90
91
|
# Props dependencies
|
|
@@ -114,6 +115,5 @@ require_relative 'types/props/private/parser'
|
|
|
114
115
|
require_relative 'types/props/generated_code_validation'
|
|
115
116
|
|
|
116
117
|
require_relative 'types/struct'
|
|
117
|
-
require_relative 'types/non_forcing_constants'
|
|
118
118
|
|
|
119
119
|
require_relative 'types/compatibility_patches'
|
data/lib/types/_types.rb
CHANGED
|
@@ -367,4 +367,16 @@ module T
|
|
|
367
367
|
end
|
|
368
368
|
end
|
|
369
369
|
end
|
|
370
|
+
|
|
371
|
+
module Module
|
|
372
|
+
def self.[](type)
|
|
373
|
+
if type.is_a?(T::Types::Untyped)
|
|
374
|
+
T::Types::TypedModule::Untyped::Private::INSTANCE
|
|
375
|
+
elsif type.is_a?(T::Types::Anything)
|
|
376
|
+
T::Types::TypedModule::Anything::Private::INSTANCE
|
|
377
|
+
else
|
|
378
|
+
T::Types::TypedModule::Private::Pool.type_for_module(type)
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
end
|
|
370
382
|
end
|
data/lib/types/configuration.rb
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
module T::Configuration
|
|
5
|
-
# Cache this comparisonn to avoid two allocations all over the place.
|
|
6
|
-
AT_LEAST_RUBY_2_7 = Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7')
|
|
7
|
-
|
|
8
5
|
# Announces to Sorbet that we are currently in a test environment, so it
|
|
9
6
|
# should treat any sigs which are marked `.checked(:tests)` as if they were
|
|
10
7
|
# just a normal sig.
|
|
@@ -448,11 +445,7 @@ module T::Configuration
|
|
|
448
445
|
MODULE_NAME = Module.instance_method(:name)
|
|
449
446
|
private_constant :MODULE_NAME
|
|
450
447
|
|
|
451
|
-
@default_module_name_mangler =
|
|
452
|
-
->(type) { MODULE_NAME.bind_call(type) }
|
|
453
|
-
else
|
|
454
|
-
->(type) { MODULE_NAME.bind(type).call } # rubocop:disable Performance/BindCall
|
|
455
|
-
end
|
|
448
|
+
@default_module_name_mangler = ->(type) { MODULE_NAME.bind_call(type) }
|
|
456
449
|
|
|
457
450
|
@module_name_mangler = nil
|
|
458
451
|
|
|
@@ -462,7 +455,7 @@ module T::Configuration
|
|
|
462
455
|
|
|
463
456
|
# Set to override the default behavior for converting types
|
|
464
457
|
# to names in generated code. Used by the runtime implementation
|
|
465
|
-
# associated with `--
|
|
458
|
+
# associated with `--sorbet-packages` mode.
|
|
466
459
|
#
|
|
467
460
|
# @param [Lambda, Proc, nil] handler Proc that converts a type (Class/Module)
|
|
468
461
|
# to a String (pass nil to reset to default behavior)
|
|
@@ -546,16 +539,6 @@ module T::Configuration
|
|
|
546
539
|
@legacy_t_enum_migration_mode || false
|
|
547
540
|
end
|
|
548
541
|
|
|
549
|
-
@prop_freeze_handler = ->(instance, prop_name) {}
|
|
550
|
-
|
|
551
|
-
def self.prop_freeze_handler=(handler)
|
|
552
|
-
@prop_freeze_handler = handler
|
|
553
|
-
end
|
|
554
|
-
|
|
555
|
-
def self.prop_freeze_handler
|
|
556
|
-
@prop_freeze_handler
|
|
557
|
-
end
|
|
558
|
-
|
|
559
542
|
@sealed_violation_whitelist = nil
|
|
560
543
|
# @param [Array] sealed_violation_whitelist An array of Regexp to validate
|
|
561
544
|
# whether inheriting /including a sealed module outside the defining module
|
data/lib/types/enum.rb
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# modules that override the `hash` method with something completely broken.
|
|
13
13
|
module T::Private::Abstract::Data
|
|
14
14
|
def self.get(mod, key)
|
|
15
|
-
mod.instance_variable_get("@opus_abstract__#{key}")
|
|
15
|
+
mod.instance_variable_get("@opus_abstract__#{key}")
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def self.set(mod, key, value)
|
|
@@ -104,24 +104,6 @@ module T::Private::Methods
|
|
|
104
104
|
T::Types::Proc.new(decl.params, decl.returns)
|
|
105
105
|
end
|
|
106
106
|
|
|
107
|
-
# Returns the signature for a method whose definition was preceded by `sig`.
|
|
108
|
-
#
|
|
109
|
-
# @param method [UnboundMethod]
|
|
110
|
-
# @return [T::Private::Methods::Signature]
|
|
111
|
-
def self.signature_for_method(method)
|
|
112
|
-
signature_for_key(method_to_key(method))
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
private_class_method def self.signature_for_key(key)
|
|
116
|
-
maybe_run_sig_block_for_key(key)
|
|
117
|
-
|
|
118
|
-
# If a subclass Sub inherits a method `foo` from Base, then
|
|
119
|
-
# Sub.instance_method(:foo) != Base.instance_method(:foo) even though they resolve to the
|
|
120
|
-
# same method. Similarly, Foo.method(:bar) != Foo.singleton_class.instance_method(:bar).
|
|
121
|
-
# So, we always do the look up by the method on the owner (Base in this example).
|
|
122
|
-
@signatures_by_method[key]
|
|
123
|
-
end
|
|
124
|
-
|
|
125
107
|
# Fetch the directory name of the file that defines the `T::Private` constant and
|
|
126
108
|
# add a trailing slash to allow us to match it as a directory prefix.
|
|
127
109
|
SORBET_RUNTIME_LIB_PATH = File.dirname(T.const_source_location(:Private).first) + File::SEPARATOR
|
|
@@ -275,10 +257,8 @@ module T::Private::Methods
|
|
|
275
257
|
# make sure to keep changes in sync.
|
|
276
258
|
elsif method_sig.check_level == :always || (method_sig.check_level == :tests && T::Private::RuntimeLevels.check_tests?)
|
|
277
259
|
CallValidation.validate_call(self, original_method, method_sig, args, blk)
|
|
278
|
-
elsif T::Configuration::AT_LEAST_RUBY_2_7
|
|
279
|
-
original_method.bind_call(self, *args, &blk)
|
|
280
260
|
else
|
|
281
|
-
original_method.
|
|
261
|
+
original_method.bind_call(self, *args, &blk)
|
|
282
262
|
end
|
|
283
263
|
end
|
|
284
264
|
end
|
|
@@ -407,6 +387,19 @@ module T::Private::Methods
|
|
|
407
387
|
end
|
|
408
388
|
end
|
|
409
389
|
|
|
390
|
+
# Returns the signature for a method whose definition was preceded by `sig`.
|
|
391
|
+
#
|
|
392
|
+
# @param method [UnboundMethod]
|
|
393
|
+
# @return [T::Private::Methods::Signature]
|
|
394
|
+
def self.signature_for_method(method)
|
|
395
|
+
signature_for_key(method_to_key(method))
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
private_class_method def self.signature_for_key(key)
|
|
399
|
+
maybe_run_sig_block_for_key(key)
|
|
400
|
+
@signatures_by_method[key]
|
|
401
|
+
end
|
|
402
|
+
|
|
410
403
|
def self.unwrap_method(mod, signature, original_method)
|
|
411
404
|
maybe_wrapped_method = CallValidation.wrap_method_if_needed(mod, signature, original_method)
|
|
412
405
|
@signatures_by_method[method_to_key(maybe_wrapped_method)] = signature
|
|
@@ -433,6 +426,25 @@ module T::Private::Methods
|
|
|
433
426
|
run_sig_block_for_key(method_to_key(method))
|
|
434
427
|
end
|
|
435
428
|
|
|
429
|
+
# use this directly if you don't want/need to box up the method into an object to pass to method_to_key.
|
|
430
|
+
private_class_method def self.method_owner_and_name_to_key(owner, name)
|
|
431
|
+
"#{owner.object_id}##{name}"
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
private_class_method def self.method_to_key(method)
|
|
435
|
+
# If a subclass Sub inherits a method `foo` from Base, then
|
|
436
|
+
# Sub.instance_method(:foo) != Base.instance_method(:foo) even though they resolve to the
|
|
437
|
+
# same method. Similarly, Foo.method(:bar) != Foo.singleton_class.instance_method(:bar).
|
|
438
|
+
# So, we always do the look up by the method on the owner (Base in this example).
|
|
439
|
+
method_owner_and_name_to_key(method.owner, method.name)
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
private_class_method def self.key_to_method(key)
|
|
443
|
+
id, name = key.split("#")
|
|
444
|
+
obj = ObjectSpace._id2ref(id.to_i)
|
|
445
|
+
obj.instance_method(name)
|
|
446
|
+
end
|
|
447
|
+
|
|
436
448
|
private_class_method def self.run_sig_block_for_key(key, force_type_init: false)
|
|
437
449
|
blk = @sig_wrappers[key]
|
|
438
450
|
if !blk
|
|
@@ -516,27 +528,15 @@ module T::Private::Methods
|
|
|
516
528
|
@old_hooks = nil
|
|
517
529
|
else
|
|
518
530
|
old_included = T::Private::ClassUtils.replace_method(Module, :included, true) do |arg|
|
|
519
|
-
|
|
520
|
-
old_included.bind_call(self, arg)
|
|
521
|
-
else
|
|
522
|
-
old_included.bind(self).call(arg) # rubocop:disable Performance/BindCall
|
|
523
|
-
end
|
|
531
|
+
old_included.bind_call(self, arg)
|
|
524
532
|
::T::Private::Methods._hook_impl(arg, false, self)
|
|
525
533
|
end
|
|
526
534
|
old_extended = T::Private::ClassUtils.replace_method(Module, :extended, true) do |arg|
|
|
527
|
-
|
|
528
|
-
old_extended.bind_call(self, arg)
|
|
529
|
-
else
|
|
530
|
-
old_extended.bind(self).call(arg) # rubocop:disable Performance/BindCall
|
|
531
|
-
end
|
|
535
|
+
old_extended.bind_call(self, arg)
|
|
532
536
|
::T::Private::Methods._hook_impl(arg, true, self)
|
|
533
537
|
end
|
|
534
538
|
old_inherited = T::Private::ClassUtils.replace_method(Class, :inherited, true) do |arg|
|
|
535
|
-
|
|
536
|
-
old_inherited.bind_call(self, arg)
|
|
537
|
-
else
|
|
538
|
-
old_inherited.bind(self).call(arg) # rubocop:disable Performance/BindCall
|
|
539
|
-
end
|
|
539
|
+
old_inherited.bind_call(self, arg)
|
|
540
540
|
::T::Private::Methods._hook_impl(arg, false, self)
|
|
541
541
|
end
|
|
542
542
|
@old_hooks = [old_included, old_extended, old_inherited]
|
|
@@ -604,21 +604,6 @@ module T::Private::Methods
|
|
|
604
604
|
mod.method(name)
|
|
605
605
|
end
|
|
606
606
|
end
|
|
607
|
-
|
|
608
|
-
# use this directly if you don't want/need to box up the method into an object to pass to method_to_key.
|
|
609
|
-
private_class_method def self.method_owner_and_name_to_key(owner, name)
|
|
610
|
-
"#{owner.object_id}##{name}"
|
|
611
|
-
end
|
|
612
|
-
|
|
613
|
-
private_class_method def self.method_to_key(method)
|
|
614
|
-
method_owner_and_name_to_key(method.owner, method.name)
|
|
615
|
-
end
|
|
616
|
-
|
|
617
|
-
private_class_method def self.key_to_method(key)
|
|
618
|
-
id, name = key.split("#")
|
|
619
|
-
obj = ObjectSpace._id2ref(id.to_i)
|
|
620
|
-
obj.instance_method(name)
|
|
621
|
-
end
|
|
622
607
|
end
|
|
623
608
|
|
|
624
609
|
# This has to be here, and can't be nested inside `T::Private::Methods`,
|
|
@@ -79,13 +79,13 @@ module T::Private::Methods::CallValidation
|
|
|
79
79
|
|
|
80
80
|
# All the types for which valid? unconditionally returns `true`
|
|
81
81
|
return_is_ignorable =
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
method_sig.return_type.equal?(T::Types::Untyped::Private::INSTANCE) ||
|
|
83
|
+
method_sig.return_type.equal?(T::Types::Anything::Private::INSTANCE) ||
|
|
84
|
+
method_sig.return_type.equal?(T::Types::AttachedClassType::Private::INSTANCE) ||
|
|
85
|
+
method_sig.return_type.equal?(T::Types::SelfType::Private::INSTANCE) ||
|
|
86
|
+
method_sig.return_type.is_a?(T::Types::TypeParameter) ||
|
|
87
|
+
method_sig.return_type.is_a?(T::Types::TypeVariable) ||
|
|
88
|
+
(method_sig.return_type.is_a?(T::Types::Simple) && method_sig.return_type.raw_type.equal?(BasicObject))
|
|
89
89
|
|
|
90
90
|
returns_anything_method = all_args_are_simple && return_is_ignorable
|
|
91
91
|
|
|
@@ -176,7 +176,7 @@ module T::Private::Methods::CallValidation
|
|
|
176
176
|
# this code is sig validation code.
|
|
177
177
|
# Please issue `finish` to step out of it
|
|
178
178
|
|
|
179
|
-
return_value =
|
|
179
|
+
return_value = original_method.bind_call(instance, *args, &blk)
|
|
180
180
|
|
|
181
181
|
# The only type that is allowed to change the return value is `.void`.
|
|
182
182
|
# It ignores what you returned and changes it to be a private singleton.
|
|
@@ -279,7 +279,7 @@ module T::Private::Methods::CallValidation
|
|
|
279
279
|
# this code is sig validation code.
|
|
280
280
|
# Please issue `finish` to step out of it
|
|
281
281
|
|
|
282
|
-
return_value =
|
|
282
|
+
return_value = original_method.bind_call(instance, *args, &blk)
|
|
283
283
|
|
|
284
284
|
# The only type that is allowed to change the return value is `.void`.
|
|
285
285
|
# It ignores what you returned and changes it to be a private singleton.
|
|
@@ -332,8 +332,4 @@ module T::Private::Methods::CallValidation
|
|
|
332
332
|
end
|
|
333
333
|
end
|
|
334
334
|
|
|
335
|
-
|
|
336
|
-
require_relative './call_validation_2_7'
|
|
337
|
-
else
|
|
338
|
-
require_relative './call_validation_2_6'
|
|
339
|
-
end
|
|
335
|
+
require_relative './call_validation_2_7'
|
|
@@ -277,6 +277,9 @@ module T::Private::Methods::SignatureValidation
|
|
|
277
277
|
end
|
|
278
278
|
end
|
|
279
279
|
|
|
280
|
+
ALLOW_INCOMPATIBLE_VISIBILITY = [:visibility, true].freeze
|
|
281
|
+
private_constant :ALLOW_INCOMPATIBLE_VISIBILITY
|
|
282
|
+
|
|
280
283
|
def self.validate_override_visibility(signature, super_signature)
|
|
281
284
|
return if super_signature.mode == Modes.untyped
|
|
282
285
|
# This departs from the behavior of other `validate_override_whatever` functions in that it
|
|
@@ -284,8 +287,8 @@ module T::Private::Methods::SignatureValidation
|
|
|
284
287
|
# done because the primary method for silencing these errors (`allow_incompatible: :visibility`)
|
|
285
288
|
# requires an `override` node to attach to. Once we have static override checking for implicitly
|
|
286
289
|
# overridden methods, we can remove this.
|
|
287
|
-
return unless
|
|
288
|
-
return if
|
|
290
|
+
return unless Modes::OVERRIDE_MODES.include?(signature.mode)
|
|
291
|
+
return if ALLOW_INCOMPATIBLE_VISIBILITY.include?(signature.override_allow_incompatible)
|
|
289
292
|
method = signature.method
|
|
290
293
|
super_method = super_signature.method
|
|
291
294
|
mode_noun = super_signature.mode == Modes.abstract ? 'implementation' : 'override'
|
|
@@ -305,8 +308,11 @@ module T::Private::Methods::SignatureValidation
|
|
|
305
308
|
end
|
|
306
309
|
|
|
307
310
|
# Higher = more restrictive.
|
|
311
|
+
METHOD_VISIBILITIES = %i[public protected private].freeze
|
|
312
|
+
private_constant :METHOD_VISIBILITIES
|
|
313
|
+
|
|
308
314
|
private_class_method def self.visibility_strength(vis)
|
|
309
|
-
|
|
315
|
+
METHOD_VISIBILITIES.find_index(vis)
|
|
310
316
|
end
|
|
311
317
|
|
|
312
318
|
private_class_method def self.base_override_loc_str(signature, super_signature)
|
data/lib/types/private/sealed.rb
CHANGED
|
@@ -70,7 +70,7 @@ module T::Private::Sealed
|
|
|
70
70
|
|
|
71
71
|
def self.validate_inheritance(caller_loc, parent, child, verb)
|
|
72
72
|
this_file = caller_loc&.path
|
|
73
|
-
decl_file = parent.instance_variable_get(:@sorbet_sealed_module_decl_file)
|
|
73
|
+
decl_file = parent.instance_variable_get(:@sorbet_sealed_module_decl_file)
|
|
74
74
|
|
|
75
75
|
if !this_file
|
|
76
76
|
raise "Could not use backtrace to determine file for #{verb} child #{child}"
|
data/lib/types/props/_props.rb
CHANGED
|
@@ -132,17 +132,14 @@ module T::Props
|
|
|
132
132
|
end
|
|
133
133
|
|
|
134
134
|
# Shorthand helper to define a `prop` with `immutable => true`
|
|
135
|
-
sig { params(name: Symbol,
|
|
136
|
-
def const(name,
|
|
137
|
-
if
|
|
135
|
+
sig { params(name: Symbol, cls: T.untyped, rules: T.untyped).void }
|
|
136
|
+
def const(name, cls, **rules)
|
|
137
|
+
if rules.key?(:immutable)
|
|
138
138
|
Kernel.raise ArgumentError.new("Cannot pass 'immutable' argument when using 'const' keyword to define a prop")
|
|
139
139
|
end
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
else
|
|
144
|
-
self.prop(name, cls_or_args, **args.merge(immutable: true))
|
|
145
|
-
end
|
|
141
|
+
rules[:immutable] = true
|
|
142
|
+
self.prop(name, cls, **rules)
|
|
146
143
|
end
|
|
147
144
|
|
|
148
145
|
def included(child)
|
|
@@ -50,7 +50,7 @@ module T::Props
|
|
|
50
50
|
sig { abstract.params(scalar: T.untyped).returns(T.untyped).checked(:never) }
|
|
51
51
|
def deserialize(scalar); end
|
|
52
52
|
|
|
53
|
-
sig { override.params(_base: Module).void }
|
|
53
|
+
sig { override.params(_base: T::Module[T.anything]).void }
|
|
54
54
|
def self.included(_base)
|
|
55
55
|
super
|
|
56
56
|
|
|
@@ -13,8 +13,10 @@ class T::Props::Decorator
|
|
|
13
13
|
Rules = T.type_alias { T::Hash[Symbol, T.untyped] }
|
|
14
14
|
DecoratedInstance = T.type_alias { Object } # Would be T::Props, but that produces circular reference errors in some circumstances
|
|
15
15
|
PropType = T.type_alias { T::Types::Base }
|
|
16
|
-
PropTypeOrClass = T.type_alias { T.any(PropType, Module) }
|
|
16
|
+
PropTypeOrClass = T.type_alias { T.any(PropType, T::Module[T.anything]) }
|
|
17
17
|
OverrideRules = T.type_alias { T::Hash[Symbol, {allow_incompatible: T::Boolean}] }
|
|
18
|
+
DecoratedClassType = T.type_alias { T.all(T::Module[T.anything], T::Props::ClassMethods) }
|
|
19
|
+
private_constant :DecoratedClassType
|
|
18
20
|
|
|
19
21
|
class NoRulesError < StandardError; end
|
|
20
22
|
|
|
@@ -38,7 +40,7 @@ class T::Props::Decorator
|
|
|
38
40
|
|
|
39
41
|
sig { params(klass: T.untyped).void.checked(:never) }
|
|
40
42
|
def initialize(klass)
|
|
41
|
-
@class = T.let(klass,
|
|
43
|
+
@class = T.let(klass, DecoratedClassType)
|
|
42
44
|
@class.plugins.each do |mod|
|
|
43
45
|
T::Props::Plugin::Private.apply_decorator_methods(mod, self)
|
|
44
46
|
end
|
|
@@ -102,7 +104,7 @@ class T::Props::Decorator
|
|
|
102
104
|
end
|
|
103
105
|
|
|
104
106
|
# checked(:never) - O(prop accesses)
|
|
105
|
-
sig { returns(
|
|
107
|
+
sig { returns(DecoratedClassType).checked(:never) }
|
|
106
108
|
def decorated_class
|
|
107
109
|
@class
|
|
108
110
|
end
|
|
@@ -174,7 +176,9 @@ class T::Props::Decorator
|
|
|
174
176
|
.checked(:never)
|
|
175
177
|
end
|
|
176
178
|
def prop_get(instance, prop, rules=prop_rules(prop))
|
|
177
|
-
|
|
179
|
+
# `instance_variable_get` will return nil if the variable doesn't exist
|
|
180
|
+
# which is what we want to have happen for the logic below.
|
|
181
|
+
val = instance.instance_variable_get(rules[:accessor_key])
|
|
178
182
|
if !val.nil?
|
|
179
183
|
val
|
|
180
184
|
elsif (d = rules[:ifunset])
|
|
@@ -194,7 +198,9 @@ class T::Props::Decorator
|
|
|
194
198
|
.checked(:never)
|
|
195
199
|
end
|
|
196
200
|
def prop_get_if_set(instance, prop, rules=prop_rules(prop))
|
|
197
|
-
|
|
201
|
+
# `instance_variable_get` will return nil if the variable doesn't exist
|
|
202
|
+
# which is what we want to have happen for the return value here.
|
|
203
|
+
instance.instance_variable_get(rules[:accessor_key])
|
|
198
204
|
end
|
|
199
205
|
alias_method :get, :prop_get_if_set # Alias for backwards compatibility
|
|
200
206
|
|
|
@@ -203,7 +209,7 @@ class T::Props::Decorator
|
|
|
203
209
|
params(
|
|
204
210
|
instance: DecoratedInstance,
|
|
205
211
|
prop: Symbol,
|
|
206
|
-
foreign_class: Module,
|
|
212
|
+
foreign_class: T::Module[T.anything],
|
|
207
213
|
rules: Rules,
|
|
208
214
|
opts: T::Hash[Symbol, T.untyped],
|
|
209
215
|
)
|
|
@@ -222,7 +228,7 @@ class T::Props::Decorator
|
|
|
222
228
|
sig do
|
|
223
229
|
params(
|
|
224
230
|
name: Symbol,
|
|
225
|
-
cls: Module,
|
|
231
|
+
cls: T::Module[T.anything],
|
|
226
232
|
rules: Rules,
|
|
227
233
|
type: PropTypeOrClass
|
|
228
234
|
)
|
|
@@ -238,7 +244,9 @@ class T::Props::Decorator
|
|
|
238
244
|
end
|
|
239
245
|
|
|
240
246
|
if rules.keys.any? { |k| !valid_rule_key?(k) }
|
|
241
|
-
|
|
247
|
+
invalid_keys = rules.keys.reject { |k| valid_rule_key?(k) }
|
|
248
|
+
suffix = invalid_keys.size == 1 ? "" : "s"
|
|
249
|
+
raise ArgumentError.new("Invalid prop arg#{suffix} supplied in #{self}: #{invalid_keys.inspect}")
|
|
242
250
|
end
|
|
243
251
|
|
|
244
252
|
if !rules[:clobber_existing_method!] && !rules[:without_accessors] && BANNED_METHOD_NAMES.include?(name.to_sym)
|
|
@@ -258,7 +266,9 @@ class T::Props::Decorator
|
|
|
258
266
|
nil
|
|
259
267
|
end
|
|
260
268
|
|
|
261
|
-
SAFE_NAME = T.let(/\A[A-Za-z_][A-Za-z0-9_-]*\z
|
|
269
|
+
SAFE_NAME = T.let(/\A[A-Za-z_][A-Za-z0-9_-]*\z/, Regexp, checked: false)
|
|
270
|
+
# Should be exactly the same as `SAFE_NAME`, but with a leading `@`.
|
|
271
|
+
SAFE_ACCESSOR_KEY_NAME = T.let(/\A@[A-Za-z_][A-Za-z0-9_-]*\z/, Regexp, checked: false)
|
|
262
272
|
|
|
263
273
|
# Used to validate both prop names and serialized forms
|
|
264
274
|
sig { params(name: T.any(Symbol, String)).void.checked(:never) }
|
|
@@ -269,7 +279,7 @@ class T::Props::Decorator
|
|
|
269
279
|
end
|
|
270
280
|
|
|
271
281
|
# This converts the type from a T::Type to a regular old ruby class.
|
|
272
|
-
sig { params(type: T::Types::Base).returns(Module).checked(:never) }
|
|
282
|
+
sig { params(type: T::Types::Base).returns(T::Module[T.anything]).checked(:never) }
|
|
273
283
|
private def convert_type_to_class(type)
|
|
274
284
|
case type
|
|
275
285
|
when T::Types::TypedArray, T::Types::FixedArray
|
|
@@ -321,7 +331,7 @@ class T::Props::Decorator
|
|
|
321
331
|
(@class.method_defined?(name) || @class.private_method_defined?(name)) &&
|
|
322
332
|
# Unfortunately, older versions of ruby don't allow the second parameter on
|
|
323
333
|
# `private_method_defined?`.
|
|
324
|
-
|
|
334
|
+
!@class.method_defined?(name, false) && !@class.private_method_defined?(name, false)
|
|
325
335
|
end
|
|
326
336
|
|
|
327
337
|
sig(:final) { params(name: Symbol, rules: Rules).void.checked(:never) }
|
|
@@ -402,8 +412,6 @@ class T::Props::Decorator
|
|
|
402
412
|
|
|
403
413
|
# extra arbitrary metadata attached by the code defining this property
|
|
404
414
|
|
|
405
|
-
validate_not_missing_sensitivity(name, rules)
|
|
406
|
-
|
|
407
415
|
# for backcompat (the `:array` key is deprecated but because the name is
|
|
408
416
|
# so generic it's really hard to be sure it's not being relied on anymore)
|
|
409
417
|
if type.is_a?(T::Types::TypedArray)
|
|
@@ -479,35 +487,6 @@ class T::Props::Decorator
|
|
|
479
487
|
end
|
|
480
488
|
end
|
|
481
489
|
|
|
482
|
-
# checked(:never) - Rules hash is expensive to check
|
|
483
|
-
sig { params(prop_name: Symbol, rules: Rules).void.checked(:never) }
|
|
484
|
-
private def validate_not_missing_sensitivity(prop_name, rules)
|
|
485
|
-
if rules[:sensitivity].nil?
|
|
486
|
-
if rules[:redaction]
|
|
487
|
-
T::Configuration.hard_assert_handler(
|
|
488
|
-
"#{@class}##{prop_name} has a 'redaction:' annotation but no " \
|
|
489
|
-
"'sensitivity:' annotation. This is probably wrong, because if a " \
|
|
490
|
-
"prop needs redaction then it is probably sensitive. Add a " \
|
|
491
|
-
"sensitivity annotation like 'sensitivity: Opus::Sensitivity::PII." \
|
|
492
|
-
"whatever', or explicitly override this check with 'sensitivity: []'."
|
|
493
|
-
)
|
|
494
|
-
end
|
|
495
|
-
# TODO(PRIVACYENG-982) Ideally we'd also check for 'password' and possibly
|
|
496
|
-
# other terms, but this interacts badly with ProtoDefinedDocument because
|
|
497
|
-
# the proto syntax currently can't declare "sensitivity: []"
|
|
498
|
-
if /\bsecret\b/.match?(prop_name)
|
|
499
|
-
T::Configuration.hard_assert_handler(
|
|
500
|
-
"#{@class}##{prop_name} has the word 'secret' in its name, but no " \
|
|
501
|
-
"'sensitivity:' annotation. This is probably wrong, because if a " \
|
|
502
|
-
"prop is named 'secret' then it is probably sensitive. Add a " \
|
|
503
|
-
"sensitivity annotation like 'sensitivity: Opus::Sensitivity::NonPII." \
|
|
504
|
-
"security_token', or explicitly override this check with " \
|
|
505
|
-
"'sensitivity: []'."
|
|
506
|
-
)
|
|
507
|
-
end
|
|
508
|
-
end
|
|
509
|
-
end
|
|
510
|
-
|
|
511
490
|
# Create `#{prop_name}_redacted` method
|
|
512
491
|
sig do
|
|
513
492
|
params(
|
|
@@ -609,7 +588,7 @@ class T::Props::Decorator
|
|
|
609
588
|
sig do
|
|
610
589
|
params(
|
|
611
590
|
prop_name: Symbol,
|
|
612
|
-
prop_cls: Module,
|
|
591
|
+
prop_cls: T::Module[T.anything],
|
|
613
592
|
rules: Rules,
|
|
614
593
|
foreign: T.untyped,
|
|
615
594
|
)
|
|
@@ -652,10 +631,10 @@ class T::Props::Decorator
|
|
|
652
631
|
#
|
|
653
632
|
# This gets called when a module or class that extends T::Props gets included, extended,
|
|
654
633
|
# prepended, or inherited.
|
|
655
|
-
sig { params(child: Module).void.checked(:never) }
|
|
634
|
+
sig { params(child: T::Module[T.anything]).void.checked(:never) }
|
|
656
635
|
def model_inherited(child)
|
|
657
636
|
child.extend(T::Props::ClassMethods)
|
|
658
|
-
child = T.cast(child,
|
|
637
|
+
child = T.cast(child, DecoratedClassType)
|
|
659
638
|
|
|
660
639
|
child.plugins.concat(decorated_class.plugins)
|
|
661
640
|
decorated_class.plugins.each do |mod|
|
|
@@ -742,19 +721,19 @@ class T::Props::Decorator
|
|
|
742
721
|
result
|
|
743
722
|
end
|
|
744
723
|
|
|
745
|
-
sig { params(child:
|
|
724
|
+
sig { params(child: DecoratedClassType, prop: Symbol).returns(T::Boolean).checked(:never) }
|
|
746
725
|
private def clobber_getter?(child, prop)
|
|
747
726
|
!!(child.decorator.method(:prop_get).owner != method(:prop_get).owner &&
|
|
748
727
|
child.instance_method(prop).source_location&.first == __FILE__)
|
|
749
728
|
end
|
|
750
729
|
|
|
751
|
-
sig { params(child:
|
|
730
|
+
sig { params(child: DecoratedClassType, prop: Symbol).returns(T::Boolean).checked(:never) }
|
|
752
731
|
private def clobber_setter?(child, prop)
|
|
753
732
|
!!(child.decorator.method(:prop_set).owner != method(:prop_set).owner &&
|
|
754
733
|
child.instance_method("#{prop}=").source_location&.first == __FILE__)
|
|
755
734
|
end
|
|
756
735
|
|
|
757
|
-
sig { params(mod: Module).void.checked(:never) }
|
|
736
|
+
sig { params(mod: T::Module[T.anything]).void.checked(:never) }
|
|
758
737
|
def plugin(mod)
|
|
759
738
|
decorated_class.plugins << mod
|
|
760
739
|
T::Props::Plugin::Private.apply_class_methods(mod, decorated_class)
|
|
@@ -12,8 +12,8 @@ module T::Props::PrettyPrintable
|
|
|
12
12
|
pp.group(1, "<#{klass.inspect_class_with_decoration(self)}", ">") do
|
|
13
13
|
klass.all_props.sort.each do |prop|
|
|
14
14
|
pp.breakable
|
|
15
|
-
val = klass.get(self, prop)
|
|
16
15
|
rules = klass.prop_rules(prop)
|
|
16
|
+
val = klass.get(self, prop, rules)
|
|
17
17
|
pp.text("#{prop}=")
|
|
18
18
|
if (custom_inspect = rules[:inspect])
|
|
19
19
|
inspected = if T::Utils.arity(custom_inspect) == 1
|
|
@@ -22,8 +22,8 @@ module T::Props::PrettyPrintable
|
|
|
22
22
|
custom_inspect.call(val, {multiline: multiline})
|
|
23
23
|
end
|
|
24
24
|
pp.text(inspected.nil? ? "nil" : inspected)
|
|
25
|
-
elsif rules[:sensitivity] && !
|
|
26
|
-
pp.text("<REDACTED #{
|
|
25
|
+
elsif (sensitivity = rules[:sensitivity]) && !sensitivity.empty? && !val.nil?
|
|
26
|
+
pp.text("<REDACTED #{sensitivity.join(', ')}>")
|
|
27
27
|
else
|
|
28
28
|
val.pretty_print(pp)
|
|
29
29
|
end
|
|
@@ -56,14 +56,14 @@ module T::Props::PrettyPrintable
|
|
|
56
56
|
|
|
57
57
|
# Overridable method to specify how the first part of a `pretty_print`d object's class should look like
|
|
58
58
|
# NOTE: This is just to support Stripe's `PrettyPrintableModel` case, and not recommended to be overridden
|
|
59
|
-
sig { params(instance: T::Props::PrettyPrintable).returns(String) }
|
|
59
|
+
sig { params(instance: T::Props::PrettyPrintable).returns(String).checked(:never) }
|
|
60
60
|
def inspect_class_with_decoration(instance)
|
|
61
61
|
T.unsafe(instance).class.to_s
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
# Overridable method to add anything that is not a prop
|
|
65
65
|
# NOTE: This is to support cases like Serializable's `@_extra_props`, and Stripe's `PrettyPrintableModel#@_deleted`
|
|
66
|
-
sig { params(instance: T::Props::PrettyPrintable, pp: T.any(PrettyPrint, PP::SingleLine)).void }
|
|
66
|
+
sig { params(instance: T::Props::PrettyPrintable, pp: T.any(PrettyPrint, PP::SingleLine)).void.checked(:never) }
|
|
67
67
|
def pretty_print_extra(instance, pp); end
|
|
68
68
|
end
|
|
69
69
|
end
|
|
@@ -27,10 +27,10 @@ module T::Props
|
|
|
27
27
|
sig { abstract.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never) }
|
|
28
28
|
def set_default(instance); end
|
|
29
29
|
|
|
30
|
-
NO_CLONE_TYPES = T.let([TrueClass, FalseClass, NilClass, Symbol, Numeric, T::Enum].freeze, T::Array[Module])
|
|
30
|
+
NO_CLONE_TYPES = T.let([TrueClass, FalseClass, NilClass, Symbol, Numeric, T::Enum].freeze, T::Array[T::Module[T.anything]])
|
|
31
31
|
|
|
32
32
|
# checked(:never) - Rules hash is expensive to check
|
|
33
|
-
sig { params(cls: Module, rules: T::Hash[Symbol, T.untyped]).returns(T.nilable(ApplyDefault)).checked(:never) }
|
|
33
|
+
sig { params(cls: T::Module[T.anything], rules: T::Hash[Symbol, T.untyped]).returns(T.nilable(ApplyDefault)).checked(:never) }
|
|
34
34
|
def self.for(cls, rules)
|
|
35
35
|
accessor_key = rules.fetch(:accessor_key)
|
|
36
36
|
setter = rules.fetch(:setter_proc)
|
|
@@ -138,7 +138,7 @@ module T::Props
|
|
|
138
138
|
# checked(:never) - We do this with `T.let` instead
|
|
139
139
|
sig do
|
|
140
140
|
params(
|
|
141
|
-
cls: Module,
|
|
141
|
+
cls: T::Module[T.anything],
|
|
142
142
|
factory: T.any(Proc, Method),
|
|
143
143
|
accessor_key: Symbol,
|
|
144
144
|
setter_proc: SetterFactory::SetterProc,
|
|
@@ -147,7 +147,7 @@ module T::Props
|
|
|
147
147
|
.checked(:never)
|
|
148
148
|
end
|
|
149
149
|
def initialize(cls, factory, accessor_key, setter_proc)
|
|
150
|
-
@class = T.let(cls, Module)
|
|
150
|
+
@class = T.let(cls, T::Module[T.anything])
|
|
151
151
|
@factory = T.let(factory, T.any(Proc, Method))
|
|
152
152
|
super(accessor_key, setter_proc)
|
|
153
153
|
end
|