lib/virtus/attribute/hash.rb in virtus-0.5.2 vs lib/virtus/attribute/hash.rb in virtus-0.5.3

- old
+ new

@@ -13,9 +13,93 @@ # Post.new(:meta => { :tags => %w(foo bar) }) # class Hash < Object primitive ::Hash coercion_method :to_hash + default primitive.new + + # The type to which keys of this hash will be coerced + # + # @example + # + # class Request + # include Virtus + # + # attribute :headers, Hash[Symbol => String] + # end + # + # Post.attributes[:headers].key_type # => Virtus::Attribute::Symbol + # + # @return [Virtus::Attribute] + # + # @api public + attr_reader :key_type + + # The type to which values of this hash will be coerced + # + # @example + # + # class Request + # include Virtus + # + # attribute :headers, Hash[Symbol => String] + # end + # + # Post.attributes[:headers].value_type # => Virtus::Attribute::String + # + # @return [Virtus::Attribute] + # + # @api public + attr_reader :value_type + + # Handles hashes with [key_type => value_type] syntax. + # + # @param [Class] + # + # @param [Hash] + # + # @return [Hash] + # + # @api private + def self.merge_options(type, options) + if !type.respond_to?(:size) + options + elsif type.size > 1 + raise ArgumentError, "more than one [key => value] pair in `#{type.inspect}`" + else + options.merge(:key_type => type.keys.first, :value_type => type.values.first) + end + end + + # Initializes an instance of {Virtus::Attribute::Hash} + # + # @api private + def initialize(*) + super + if @options.has_key?(:key_type) && @options.has_key?(:value_type) + @key_type = @options[:key_type] + @value_type = @options[:value_type] + @key_type_instance = Attribute.build(@name, @key_type) + @value_type_instance = Attribute.build(@name, @value_type) + end + end + + # Coerce a hash with keys and values + # + # @param [Object] + # + # @return [Object] + # + # @api private + def coerce(value) + coerced = super + return coerced unless coerced.respond_to?(:each_with_object) + coerced.each_with_object({}) do |key_and_value, hash| + key = @key_type_instance.coerce(key_and_value[0]) + value = @value_type_instance.coerce(key_and_value[1]) + hash[key] = value + end + end end # class Hash end # class Attribute end # module Virtus