sorbet-runtime 0.5.5267 → 0.5.5278
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/types/private/methods/signature.rb +7 -1
- data/lib/types/props/decorator.rb +42 -58
- data/lib/types/props/plugin.rb +23 -1
- 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: 351ff337a29d85d7adcd563eb352cc9516be5d80ac8d4c7eda271e51ed295d52
|
4
|
+
data.tar.gz: 2d1f3e87d3b84650f4bcf3ca1eae08385999e1c9e9cbe930cb42db7289c9497d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ece19477f2ce3df3d12a314a90eeed696b4168ddae9fd78e052d3f60a21c6bb618aeda3db95fd30e5947369f6bf04be07f8856b4781259d9693d157128f219eb
|
7
|
+
data.tar.gz: fa6c021527b7d372c4f648103245117c6b2998ffd7bb63ada0dc6216d3ae6dfd077c53a4659132c6d38aec6b3b3415eabfd49f81055f6dd06dce821b9da15f91
|
@@ -51,8 +51,14 @@ class T::Private::Methods::Signature
|
|
51
51
|
@on_failure = on_failure
|
52
52
|
@override_allow_incompatible = override_allow_incompatible
|
53
53
|
|
54
|
-
param_names = parameters.map {|_, name| name}
|
55
54
|
declared_param_names = raw_arg_types.keys
|
55
|
+
# If sig params are declared but there is a single parameter with a missing name
|
56
|
+
# **and** the method ends with a "=", assume it is a writer method generated
|
57
|
+
# by attr_writer or attr_accessor
|
58
|
+
writer_method = declared_param_names != [nil] && parameters == [[:req]] && method_name[-1] == "="
|
59
|
+
# For writer methods, map the single parameter to the method name without the "=" at the end
|
60
|
+
parameters = [[:req, method_name[0...-1].to_sym]] if writer_method
|
61
|
+
param_names = parameters.map {|_, name| name}
|
56
62
|
missing_names = param_names - declared_param_names
|
57
63
|
extra_names = declared_param_names - param_names
|
58
64
|
if !missing_names.empty?
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# typed:
|
2
|
+
# typed: strict
|
3
3
|
|
4
4
|
# NB: This is not actually a decorator. It's just named that way for consistency
|
5
5
|
# with DocumentDecorator and ModelDecorator (which both seem to have been written
|
@@ -11,26 +11,27 @@ class T::Props::Decorator
|
|
11
11
|
extend T::Sig
|
12
12
|
|
13
13
|
Rules = T.type_alias {T::Hash[Symbol, T.untyped]}
|
14
|
-
|
15
|
-
DecoratedInstance = T.type_alias {T.untyped} # Would be T::Props, but that produces circular reference errors in some circumstances
|
14
|
+
DecoratedInstance = T.type_alias {Object} # Would be T::Props, but that produces circular reference errors in some circumstances
|
16
15
|
PropType = T.type_alias {T.any(T::Types::Base, T::Props::CustomType)}
|
17
16
|
PropTypeOrClass = T.type_alias {T.any(PropType, Module)}
|
18
17
|
|
19
18
|
class NoRulesError < StandardError; end
|
20
19
|
|
21
|
-
|
20
|
+
EMPTY_PROPS = T.let({}.freeze, T::Hash[Symbol, Rules])
|
21
|
+
private_constant :EMPTY_PROPS
|
22
|
+
|
23
|
+
sig {params(klass: T.untyped).void}
|
22
24
|
def initialize(klass)
|
23
|
-
@class = klass
|
24
|
-
|
25
|
-
Private.apply_decorator_methods(mod, self)
|
25
|
+
@class = T.let(klass, T.all(Module, T::Props::ClassMethods))
|
26
|
+
@class.plugins.each do |mod|
|
27
|
+
T::Props::Plugin::Private.apply_decorator_methods(mod, self)
|
26
28
|
end
|
29
|
+
@props = T.let(EMPTY_PROPS, T::Hash[Symbol, Rules])
|
27
30
|
end
|
28
31
|
|
29
32
|
# checked(:never) - O(prop accesses)
|
30
33
|
sig {returns(T::Hash[Symbol, Rules]).checked(:never)}
|
31
|
-
|
32
|
-
@props ||= {}.freeze
|
33
|
-
end
|
34
|
+
attr_reader :props
|
34
35
|
|
35
36
|
# Try to avoid using this; post-definition mutation of prop rules is
|
36
37
|
# surprising and hard to reason about.
|
@@ -62,7 +63,7 @@ class T::Props::Decorator
|
|
62
63
|
@props = @props.merge(prop => rules.freeze).freeze
|
63
64
|
end
|
64
65
|
|
65
|
-
VALID_RULE_KEYS = %i{
|
66
|
+
VALID_RULE_KEYS = T.let(%i{
|
66
67
|
enum
|
67
68
|
foreign
|
68
69
|
foreign_hint_only
|
@@ -76,16 +77,16 @@ class T::Props::Decorator
|
|
76
77
|
extra
|
77
78
|
optional
|
78
79
|
_tnilable
|
79
|
-
}.map {|k| [k, true]}.to_h.freeze
|
80
|
+
}.map {|k| [k, true]}.to_h.freeze, T::Hash[Symbol, T::Boolean])
|
80
81
|
private_constant :VALID_RULE_KEYS
|
81
82
|
|
82
83
|
sig {params(key: Symbol).returns(T::Boolean).checked(:never)}
|
83
84
|
def valid_rule_key?(key)
|
84
|
-
VALID_RULE_KEYS[key]
|
85
|
+
!!VALID_RULE_KEYS[key]
|
85
86
|
end
|
86
87
|
|
87
88
|
# checked(:never) - O(prop accesses)
|
88
|
-
sig {returns(
|
89
|
+
sig {returns(T.all(Module, T::Props::ClassMethods)).checked(:never)}
|
89
90
|
def decorated_class; @class; end
|
90
91
|
|
91
92
|
# Accessors
|
@@ -135,13 +136,13 @@ class T::Props::Decorator
|
|
135
136
|
instance: DecoratedInstance,
|
136
137
|
prop: Symbol,
|
137
138
|
val: T.untyped,
|
138
|
-
rules:
|
139
|
+
rules: Rules
|
139
140
|
)
|
140
141
|
.void
|
141
142
|
.checked(:never)
|
142
143
|
end
|
143
144
|
def prop_set(instance, prop, val, rules=prop_rules(prop))
|
144
|
-
instance.instance_exec(val, &rules
|
145
|
+
instance.instance_exec(val, &rules.fetch(:setter_proc))
|
145
146
|
end
|
146
147
|
alias_method :set, :prop_set
|
147
148
|
|
@@ -184,18 +185,18 @@ class T::Props::Decorator
|
|
184
185
|
prop: Symbol,
|
185
186
|
foreign_class: Module,
|
186
187
|
rules: Rules,
|
187
|
-
opts: Hash
|
188
|
+
opts: T::Hash[Symbol, T.untyped],
|
188
189
|
)
|
189
190
|
.returns(T.untyped)
|
190
191
|
.checked(:never)
|
191
192
|
end
|
192
193
|
def foreign_prop_get(instance, prop, foreign_class, rules=props[prop.to_sym], opts={})
|
193
194
|
return if !(value = prop_get(instance, prop, rules))
|
194
|
-
foreign_class.load(value, {}, opts)
|
195
|
+
T.unsafe(foreign_class).load(value, {}, opts)
|
195
196
|
end
|
196
197
|
|
197
198
|
# TODO: we should really be checking all the methods on `cls`, not just Object
|
198
|
-
BANNED_METHOD_NAMES = Object.instance_methods.to_set.freeze
|
199
|
+
BANNED_METHOD_NAMES = T.let(Object.instance_methods.to_set.freeze, T::Set[Symbol])
|
199
200
|
|
200
201
|
# checked(:never) - Rules hash is expensive to check
|
201
202
|
sig do
|
@@ -245,6 +246,7 @@ class T::Props::Decorator
|
|
245
246
|
nil
|
246
247
|
end
|
247
248
|
|
249
|
+
sig {params(name: Symbol).void}
|
248
250
|
private def validate_prop_name(name)
|
249
251
|
if name !~ /\A[A-Za-z_][A-Za-z0-9_-]*\z/
|
250
252
|
raise ArgumentError.new("Invalid prop name in #{@class.name}: #{name}")
|
@@ -371,7 +373,7 @@ class T::Props::Decorator
|
|
371
373
|
# are ultimately included does.
|
372
374
|
#
|
373
375
|
if defined?(Opus) && defined?(Opus::Sensitivity) && defined?(Opus::Sensitivity::PIIable)
|
374
|
-
if sensitivity_and_pii[:pii] && @class.is_a?(Class) &&
|
376
|
+
if sensitivity_and_pii[:pii] && @class.is_a?(Class) && !T.unsafe(@class).contains_pii?
|
375
377
|
raise ArgumentError.new(
|
376
378
|
'Cannot include a pii prop in a class that declares `contains_no_pii`'
|
377
379
|
)
|
@@ -454,21 +456,21 @@ class T::Props::Decorator
|
|
454
456
|
if !rules[:immutable]
|
455
457
|
if method(:prop_set).owner != T::Props::Decorator
|
456
458
|
@class.send(:define_method, "#{name}=") do |val|
|
457
|
-
self.class.decorator.prop_set(self, name, val, rules)
|
459
|
+
T.unsafe(self.class).decorator.prop_set(self, name, val, rules)
|
458
460
|
end
|
459
461
|
else
|
460
462
|
# Fast path (~4x faster as of Ruby 2.6)
|
461
|
-
@class.send(:define_method, "#{name}=", &rules
|
463
|
+
@class.send(:define_method, "#{name}=", &rules.fetch(:setter_proc))
|
462
464
|
end
|
463
465
|
end
|
464
466
|
|
465
467
|
if method(:prop_get).owner != T::Props::Decorator || rules.key?(:ifunset)
|
466
468
|
@class.send(:define_method, name) do
|
467
|
-
self.class.decorator.prop_get(self, name, rules)
|
469
|
+
T.unsafe(self.class).decorator.prop_get(self, name, rules)
|
468
470
|
end
|
469
471
|
else
|
470
472
|
# Fast path (~30x faster as of Ruby 2.6)
|
471
|
-
@class.attr_reader
|
473
|
+
@class.send(:attr_reader, name) # send is used because `attr_reader` is private in 2.4
|
472
474
|
end
|
473
475
|
end
|
474
476
|
end
|
@@ -536,10 +538,10 @@ class T::Props::Decorator
|
|
536
538
|
end
|
537
539
|
|
538
540
|
# From T::Props::Utils.deep_clone_object, plus String
|
539
|
-
TYPES_NOT_NEEDING_CLONE = [TrueClass, FalseClass, NilClass, Symbol, String, Numeric]
|
541
|
+
TYPES_NOT_NEEDING_CLONE = T.let([TrueClass, FalseClass, NilClass, Symbol, String, Numeric], T::Array[Module])
|
540
542
|
|
541
543
|
# checked(:never) - Typechecks internally
|
542
|
-
sig {params(type: PropType).returns(T::Boolean).checked(:never)}
|
544
|
+
sig {params(type: PropType).returns(T.nilable(T::Boolean)).checked(:never)}
|
543
545
|
private def shallow_clone_ok(type)
|
544
546
|
inner_type =
|
545
547
|
if type.is_a?(T::Types::TypedArray)
|
@@ -581,7 +583,7 @@ class T::Props::Decorator
|
|
581
583
|
end
|
582
584
|
|
583
585
|
# checked(:never) - Rules hash is expensive to check
|
584
|
-
sig {params(prop_name: Symbol, rules:
|
586
|
+
sig {params(prop_name: Symbol, rules: Rules).void.checked(:never)}
|
585
587
|
private def validate_not_missing_sensitivity(prop_name, rules)
|
586
588
|
if rules[:sensitivity].nil?
|
587
589
|
if rules[:redaction]
|
@@ -686,6 +688,7 @@ class T::Props::Decorator
|
|
686
688
|
# *haven't* allowed additional options in the past and want to
|
687
689
|
# default to keeping this interface narrow.
|
688
690
|
@class.send(:define_method, fk_method) do |allow_direct_mutation: nil|
|
691
|
+
foreign = T.let(foreign, T.untyped)
|
689
692
|
if foreign.is_a?(Proc)
|
690
693
|
resolved_foreign = foreign.call
|
691
694
|
if !resolved_foreign.respond_to?(:load)
|
@@ -704,7 +707,7 @@ class T::Props::Decorator
|
|
704
707
|
opts = {allow_direct_mutation: allow_direct_mutation}
|
705
708
|
end
|
706
709
|
|
707
|
-
self.class.decorator.foreign_prop_get(self, prop_name, foreign, rules, opts)
|
710
|
+
T.unsafe(self.class).decorator.foreign_prop_get(self, prop_name, foreign, rules, opts)
|
708
711
|
end
|
709
712
|
|
710
713
|
force_fk_method = "#{fk_method}!"
|
@@ -716,7 +719,7 @@ class T::Props::Decorator
|
|
716
719
|
storytime: {method: force_fk_method, class: self.class}
|
717
720
|
)
|
718
721
|
end
|
719
|
-
|
722
|
+
loaded_foreign
|
720
723
|
end
|
721
724
|
|
722
725
|
@class.send(:define_method, "#{prop_name}_record") do |allow_direct_mutation: nil|
|
@@ -765,16 +768,17 @@ class T::Props::Decorator
|
|
765
768
|
#
|
766
769
|
# This gets called when a module or class that extends T::Props gets included, extended,
|
767
770
|
# prepended, or inherited.
|
768
|
-
sig {params(child:
|
771
|
+
sig {params(child: Module).void.checked(:never)}
|
769
772
|
def model_inherited(child)
|
770
773
|
child.extend(T::Props::ClassMethods)
|
771
|
-
child.
|
774
|
+
child = T.cast(child, T.all(Module, T::Props::ClassMethods))
|
772
775
|
|
776
|
+
child.plugins.concat(decorated_class.plugins)
|
773
777
|
decorated_class.plugins.each do |mod|
|
774
778
|
# NB: apply_class_methods must not be an instance method on the decorator itself,
|
775
779
|
# otherwise we'd have to call child.decorator here, which would create the decorator
|
776
780
|
# before any `decorator_class` override has a chance to take effect (see the comment below).
|
777
|
-
Private.apply_class_methods(mod, child)
|
781
|
+
T::Props::Plugin::Private.apply_class_methods(mod, child)
|
778
782
|
end
|
779
783
|
|
780
784
|
props.each do |name, rules|
|
@@ -794,17 +798,17 @@ class T::Props::Decorator
|
|
794
798
|
#
|
795
799
|
unless rules[:without_accessors]
|
796
800
|
if child.decorator.method(:prop_get).owner != method(:prop_get).owner &&
|
797
|
-
child.instance_method(name).source_location
|
801
|
+
child.instance_method(name).source_location&.first == __FILE__
|
798
802
|
child.send(:define_method, name) do
|
799
|
-
self.class.decorator.prop_get(self, name, rules)
|
803
|
+
T.unsafe(self.class).decorator.prop_get(self, name, rules)
|
800
804
|
end
|
801
805
|
end
|
802
806
|
|
803
807
|
unless rules[:immutable]
|
804
808
|
if child.decorator.method(:prop_set).owner != method(:prop_set).owner &&
|
805
|
-
child.instance_method("#{name}=").source_location
|
809
|
+
child.instance_method("#{name}=").source_location&.first == __FILE__
|
806
810
|
child.send(:define_method, "#{name}=") do |val|
|
807
|
-
self.class.decorator.prop_set(self, name, val, rules)
|
811
|
+
T.unsafe(self.class).decorator.prop_set(self, name, val, rules)
|
808
812
|
end
|
809
813
|
end
|
810
814
|
end
|
@@ -815,27 +819,7 @@ class T::Props::Decorator
|
|
815
819
|
sig {params(mod: Module).void.checked(:never)}
|
816
820
|
def plugin(mod)
|
817
821
|
decorated_class.plugins << mod
|
818
|
-
Private.apply_class_methods(mod, decorated_class)
|
819
|
-
Private.apply_decorator_methods(mod, self)
|
820
|
-
end
|
821
|
-
|
822
|
-
module Private
|
823
|
-
# These need to be non-instance methods so we can use them without prematurely creating the
|
824
|
-
# child decorator in `model_inherited` (see comments there for details).
|
825
|
-
def self.apply_class_methods(plugin, target)
|
826
|
-
if plugin.const_defined?('ClassMethods')
|
827
|
-
# FIXME: This will break preloading, selective test execution, etc if `mod::ClassMethods`
|
828
|
-
# is ever defined in a separate file from `mod`.
|
829
|
-
target.extend(plugin::ClassMethods) # rubocop:disable PrisonGuard/NoDynamicConstAccess
|
830
|
-
end
|
831
|
-
end
|
832
|
-
|
833
|
-
def self.apply_decorator_methods(plugin, target)
|
834
|
-
if plugin.const_defined?('DecoratorMethods')
|
835
|
-
# FIXME: This will break preloading, selective test execution, etc if `mod::DecoratorMethods`
|
836
|
-
# is ever defined in a separate file from `mod`.
|
837
|
-
target.extend(plugin::DecoratorMethods) # rubocop:disable PrisonGuard/NoDynamicConstAccess
|
838
|
-
end
|
839
|
-
end
|
822
|
+
T::Props::Plugin::Private.apply_class_methods(mod, decorated_class)
|
823
|
+
T::Props::Plugin::Private.apply_decorator_methods(mod, self)
|
840
824
|
end
|
841
825
|
end
|
data/lib/types/props/plugin.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# typed:
|
2
|
+
# typed: false
|
3
3
|
|
4
4
|
module T::Props::Plugin
|
5
5
|
include T::Props
|
@@ -12,4 +12,26 @@ module T::Props::Plugin
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
mixes_in_class_methods(ClassMethods)
|
15
|
+
|
16
|
+
module Private
|
17
|
+
# These need to be non-instance methods so we can use them without prematurely creating the
|
18
|
+
# child decorator in `model_inherited` (see comments there for details).
|
19
|
+
#
|
20
|
+
# The dynamic constant access below forces this file to be `typed: false`
|
21
|
+
def self.apply_class_methods(plugin, target)
|
22
|
+
if plugin.const_defined?('ClassMethods')
|
23
|
+
# FIXME: This will break preloading, selective test execution, etc if `mod::ClassMethods`
|
24
|
+
# is ever defined in a separate file from `mod`.
|
25
|
+
target.extend(plugin::ClassMethods) # rubocop:disable PrisonGuard/NoDynamicConstAccess
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.apply_decorator_methods(plugin, target)
|
30
|
+
if plugin.const_defined?('DecoratorMethods')
|
31
|
+
# FIXME: This will break preloading, selective test execution, etc if `mod::DecoratorMethods`
|
32
|
+
# is ever defined in a separate file from `mod`.
|
33
|
+
target.extend(plugin::DecoratorMethods) # rubocop:disable PrisonGuard/NoDynamicConstAccess
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
15
37
|
end
|
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.5278
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stripe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-01-
|
11
|
+
date: 2020-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|