sorbet-runtime 0.5.12225 → 0.5.12349
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/types/props/decorator.rb +91 -8
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed0be05b2dc1a36d22edcee3cf009bf56a33694e889ba41793966f6128853738
|
4
|
+
data.tar.gz: 906069610c18e58a01945eb7c605fe1dcc6089d8a6a20955557c8dd6cf491528
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8d6655a0e3502befabc74bb1e4ee6d55a8d8b5d7a1eccc6593ba3070cd2d45e14958239f5dba645451fed4f1bb73300e2868f90da983a8223f14f84bfad382f
|
7
|
+
data.tar.gz: 1f815a6904f8ee420f72a400cdd895df9d5b456cbaaf0f919318e84fd0b50e3ce37618fbf0b9b3aa6e069757e7fc3e8db04c17e538fb164e1abfbb4be503f3ab
|
@@ -14,12 +14,28 @@ class T::Props::Decorator
|
|
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
16
|
PropTypeOrClass = T.type_alias { T.any(PropType, Module) }
|
17
|
+
OverrideRules = T.type_alias { T::Hash[Symbol, {allow_incompatible: T::Boolean}] }
|
17
18
|
|
18
19
|
class NoRulesError < StandardError; end
|
19
20
|
|
20
21
|
EMPTY_PROPS = T.let({}.freeze, T::Hash[Symbol, Rules], checked: false)
|
21
22
|
private_constant :EMPTY_PROPS
|
22
23
|
|
24
|
+
OVERRIDE_TRUE = T.let({
|
25
|
+
reader: {allow_incompatible: false}.freeze,
|
26
|
+
writer: {allow_incompatible: false}.freeze,
|
27
|
+
}.freeze, OverrideRules)
|
28
|
+
|
29
|
+
OVERRIDE_READER = T.let({
|
30
|
+
reader: {allow_incompatible: false}.freeze,
|
31
|
+
}.freeze, OverrideRules)
|
32
|
+
|
33
|
+
OVERRIDE_WRITER = T.let({
|
34
|
+
writer: {allow_incompatible: false}.freeze,
|
35
|
+
}.freeze, OverrideRules)
|
36
|
+
|
37
|
+
OVERRIDE_EMPTY = T.let({}.freeze, OverrideRules)
|
38
|
+
|
23
39
|
sig { params(klass: T.untyped).void.checked(:never) }
|
24
40
|
def initialize(klass)
|
25
41
|
@class = T.let(klass, T.all(Module, T::Props::ClassMethods))
|
@@ -45,17 +61,15 @@ class T::Props::Decorator
|
|
45
61
|
end
|
46
62
|
|
47
63
|
# checked(:never) - Rules hash is expensive to check
|
48
|
-
sig { params(
|
49
|
-
def add_prop_definition(
|
64
|
+
sig { params(name: Symbol, rules: Rules).void.checked(:never) }
|
65
|
+
def add_prop_definition(name, rules)
|
50
66
|
override = rules.delete(:override)
|
51
67
|
|
52
|
-
if props.include?(
|
53
|
-
raise ArgumentError.new("Attempted to redefine prop #{
|
54
|
-
elsif !props.include?(prop) && override
|
55
|
-
raise ArgumentError.new("Attempted to override a prop #{prop.inspect} on class #{@class} that doesn't already exist")
|
68
|
+
if props.include?(name) && !override
|
69
|
+
raise ArgumentError.new("Attempted to redefine prop #{name.inspect} on class #{@class} that's already defined without specifying :override => true: #{prop_rules(name)}")
|
56
70
|
end
|
57
71
|
|
58
|
-
@props = @props.merge(
|
72
|
+
@props = @props.merge(name => rules.freeze).freeze
|
59
73
|
end
|
60
74
|
|
61
75
|
# Heads up!
|
@@ -302,6 +316,27 @@ class T::Props::Decorator
|
|
302
316
|
T::Utils::Nilable.is_union_with_nilclass(cls) || ((cls == T.untyped || cls == NilClass) && rules.key?(:default) && rules[:default].nil?)
|
303
317
|
end
|
304
318
|
|
319
|
+
sig(:final) { params(name: Symbol).returns(T::Boolean).checked(:never) }
|
320
|
+
private def method_defined_on_ancestor?(name)
|
321
|
+
@class.method_defined?(name) && !@class.method_defined?(name, false)
|
322
|
+
end
|
323
|
+
|
324
|
+
sig(:final) { params(name: Symbol, rules: Rules).void.checked(:never) }
|
325
|
+
private def validate_overrides(name, rules)
|
326
|
+
override = elaborate_override(name, rules[:override])
|
327
|
+
|
328
|
+
return if rules[:without_accessors]
|
329
|
+
|
330
|
+
if override[:reader] && !method_defined_on_ancestor?(name) && !props.include?(name)
|
331
|
+
raise ArgumentError.new("You marked the getter for prop #{name.inspect} as `override`, but the method `#{name}` doesn't exist to be overridden.")
|
332
|
+
end
|
333
|
+
|
334
|
+
# Properly, we should also check whether `props[name]` is immutable, but the old code didn't either.
|
335
|
+
if !rules[:immutable] && override[:writer] && !method_defined_on_ancestor?("#{name}=".to_sym) && !props.include?(name)
|
336
|
+
raise ArgumentError.new("You marked the setter for prop #{name.inspect} as `override`, but the method `#{name}=` doesn't exist to be overridden.")
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
305
340
|
# checked(:never) - Rules hash is expensive to check
|
306
341
|
sig do
|
307
342
|
params(
|
@@ -381,6 +416,7 @@ class T::Props::Decorator
|
|
381
416
|
rules[:setter_proc] = setter_proc
|
382
417
|
rules[:value_validate_proc] = value_validate_proc
|
383
418
|
|
419
|
+
validate_overrides(name, rules)
|
384
420
|
add_prop_definition(name, rules)
|
385
421
|
|
386
422
|
# NB: using `without_accessors` doesn't make much sense unless you also define some other way to
|
@@ -405,6 +441,7 @@ class T::Props::Decorator
|
|
405
441
|
# Fast path (~4x faster as of Ruby 2.6)
|
406
442
|
@class.send(:define_method, "#{name}=", &rules.fetch(:setter_proc))
|
407
443
|
end
|
444
|
+
|
408
445
|
end
|
409
446
|
|
410
447
|
if method(:prop_get).owner != T::Props::Decorator || rules.key?(:ifunset)
|
@@ -627,7 +664,7 @@ class T::Props::Decorator
|
|
627
664
|
|
628
665
|
props.each do |name, rules|
|
629
666
|
copied_rules = rules.dup
|
630
|
-
# NB: Calling `child.decorator` here is a
|
667
|
+
# NB: Calling `child.decorator` here is a time bomb that's going to give someone a really bad
|
631
668
|
# time. Any class that defines props and also overrides the `decorator_class` method is going
|
632
669
|
# to reach this line before its override take effect, turning it into a no-op.
|
633
670
|
child.decorator.add_prop_definition(name, copied_rules)
|
@@ -656,6 +693,52 @@ class T::Props::Decorator
|
|
656
693
|
end
|
657
694
|
end
|
658
695
|
|
696
|
+
sig(:final) do
|
697
|
+
params(key: Symbol, d: T.untyped, out: T::Hash[Symbol, {allow_incompatible: T::Boolean}])
|
698
|
+
.void
|
699
|
+
.checked(:never)
|
700
|
+
end
|
701
|
+
private def elaborate_override_entry(key, d, out)
|
702
|
+
# It's written this way so that `{reader: false}` will omit the entry for `reader` in the
|
703
|
+
# result entirely
|
704
|
+
case d[key]
|
705
|
+
when TrueClass
|
706
|
+
out[key] = {allow_incompatible: false}
|
707
|
+
when Hash
|
708
|
+
out[key] = {allow_incompatible: !!d[key][:allow_incompatible]}
|
709
|
+
end
|
710
|
+
end
|
711
|
+
|
712
|
+
sig(:final) do
|
713
|
+
params(name: Symbol, d: T.untyped)
|
714
|
+
.returns(T::Hash[Symbol, {allow_incompatible: T::Boolean}])
|
715
|
+
.checked(:never)
|
716
|
+
end
|
717
|
+
private def elaborate_override(name, d)
|
718
|
+
return OVERRIDE_TRUE if d == true
|
719
|
+
return OVERRIDE_READER if d == :reader
|
720
|
+
return OVERRIDE_WRITER if d == :writer
|
721
|
+
return OVERRIDE_EMPTY if d == false || d.nil?
|
722
|
+
unless d.is_a?(Hash)
|
723
|
+
raise ArgumentError.new("`override` only accepts `true`, `:reader`, `:writer`, or a Hash in prop #{@class.name}.#{name} (got #{d.class})")
|
724
|
+
end
|
725
|
+
|
726
|
+
# cwong: should we check for bad keys? `sig { override(not_real: true) }` on a normal function
|
727
|
+
# errors statically but not at runtime.
|
728
|
+
|
729
|
+
# XX cwong: this means {reader: false, allow_incompatible: true} will become {allow_incompatible: true},
|
730
|
+
# is that fine?
|
731
|
+
unless (allow_incompatible = d[:allow_incompatible]).nil?
|
732
|
+
return {reader: {allow_incompatible: !!allow_incompatible},
|
733
|
+
writer: {allow_incompatible: !!allow_incompatible}}.to_h
|
734
|
+
end
|
735
|
+
|
736
|
+
result = {}
|
737
|
+
elaborate_override_entry(:reader, d, result)
|
738
|
+
elaborate_override_entry(:writer, d, result)
|
739
|
+
result
|
740
|
+
end
|
741
|
+
|
659
742
|
sig { params(child: T.all(Module, T::Props::ClassMethods), prop: Symbol).returns(T::Boolean).checked(:never) }
|
660
743
|
private def clobber_getter?(child, prop)
|
661
744
|
!!(child.decorator.method(:prop_get).owner != method(:prop_get).owner &&
|
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.5.
|
4
|
+
version: 0.5.12349
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stripe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-07-
|
11
|
+
date: 2025-07-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|