-
-
Notifications
You must be signed in to change notification settings - Fork 9.3k
/
weak_constructor.rb
67 lines (60 loc) 路 2.36 KB
/
weak_constructor.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# frozen_string_literal: true
# typed: false
module T::Props::WeakConstructor
include T::Props::Optional
extend T::Sig
# checked(:never) - O(runtime object construction)
sig {params(hash: T::Hash[Symbol, T.untyped]).void.checked(:never)}
def initialize(hash={})
decorator = self.class.decorator
hash_keys_matching_props = decorator.construct_props_with_defaults(self, hash) +
decorator.construct_props_without_defaults(self, hash)
if hash_keys_matching_props < hash.size
raise ArgumentError.new("#{self.class}: Unrecognized properties: #{(hash.keys - decorator.props.keys).join(', ')}")
end
end
end
module T::Props::WeakConstructor::DecoratorMethods
extend T::Sig
# Set values for all props that have no defaults. Ignore any not present.
#
# @return [Integer] A count of props that we successfully initialized (which
# we'll use to check for any unrecognized input.)
#
# checked(:never) - O(runtime object construction)
sig {params(instance: T::Props::WeakConstructor, hash: T::Hash[Symbol, T.untyped]).returns(Integer).checked(:never)}
def construct_props_without_defaults(instance, hash)
# Use `each_pair` rather than `count` because, as of Ruby 2.6, the latter delegates to Enumerator
# and therefore allocates for each entry.
result = 0
props_without_defaults&.each_pair do |p, setter_proc|
if hash.key?(p)
instance.instance_exec(hash[p], &setter_proc)
result += 1
end
end
result
end
# Set values for all props that have defaults. Use the default if and only if
# the prop key isn't in the input.
#
# @return [Integer] A count of props that we successfully initialized (which
# we'll use to check for any unrecognized input.)
#
# checked(:never) - O(runtime object construction)
sig {params(instance: T::Props::WeakConstructor, hash: T::Hash[Symbol, T.untyped]).returns(Integer).checked(:never)}
def construct_props_with_defaults(instance, hash)
# Use `each_pair` rather than `count` because, as of Ruby 2.6, the latter delegates to Enumerator
# and therefore allocates for each entry.
result = 0
props_with_defaults&.each_pair do |p, default_struct|
if hash.key?(p)
instance.instance_exec(hash[p], &default_struct.setter_proc)
result += 1
else
default_struct.set_default(instance)
end
end
result
end
end