lib/types/props/weak_constructor.rb
# 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