module Hashie::Extensions::Coercion::ClassMethods

def build_coercion(type)

def build_coercion(type)
  if type.is_a? Enumerable
    if type.class == ::Hash
      type, key_type, value_type = type.class, *type.first
      build_hash_coercion(type, key_type, value_type)
    else
      value_type = type.first
      type = type.class
      build_container_coercion(type, value_type)
    end
  elsif CORE_TYPES.key? type
    build_core_type_coercion(type)
  elsif type.respond_to? :coerce
    lambda do |value|
      return value if value.is_a? type
      type.coerce(value)
    end
  elsif type.respond_to? :new
    lambda do |value|
      return value if value.is_a? type
      type.new(value)
    end
  else
    raise TypeError, "#{type} is not a coercable type"
  end
end

def build_container_coercion(type, value_type)

def build_container_coercion(type, value_type)
  value_coerce = fetch_coercion(value_type)
  lambda do |value|
    type.new(value.map { |v| value_coerce.call(v) })
  end
end

def build_core_type_coercion(type)

def build_core_type_coercion(type)
  name = CORE_TYPES[type]
  lambda do |value|
    return value if value.is_a? type
    return value.send(name)
  end
end

def build_hash_coercion(type, key_type, value_type)

def build_hash_coercion(type, key_type, value_type)
  key_coerce = fetch_coercion(key_type)
  value_coerce = fetch_coercion(value_type)
  lambda do |value|
    type[value.map { |k, v| [key_coerce.call(k), value_coerce.call(v)] }]
  end
end

def coerce_key(*attrs)

Other tags:
    Example: Coerce a "user" subhash into a User object -

Parameters:
  • into (Class) -- the class into which you want the key(s) coerced.
  • key (Object) -- the key or array of keys you would like to be coerced.
def coerce_key(*attrs)
  into = attrs.pop
  attrs.each { |key| key_coercions[key] = into }
end

def coerce_value(from, into, options = {})

Other tags:
    Example: Coerce all hashes into this special type of hash -

Options Hash: (**options)
  • :strict (Boolean) -- whether use exact source class

Parameters:
  • into (Class) -- the class into which you would like the value coerced.
  • from (Class) -- the type you would like coerced.
def coerce_value(from, into, options = {})
  options = { strict: true }.merge(options)
  if ABSTRACT_CORE_TYPES.key? from
    ABSTRACT_CORE_TYPES[from].each do |type|
      coerce_value type, into, options
    end
  end
  if options[:strict]
    strict_value_coercions[from] = into
  else
    while from.superclass && from.superclass != Object
      lenient_value_coercions[from] = into
      from = from.superclass
    end
  end
end

def coercion_cache

def coercion_cache
  @coercion_cache ||= ::Hash.new do |hash, type|
    hash[type] = build_coercion(type)
  end
end

def fetch_coercion(type)

def fetch_coercion(type)
  return type if type.is_a? Proc
  coercion_cache[type]
end

def inherited(klass)

def inherited(klass)
  super
  klass.key_coercions = key_coercions.dup
end

def key_coercion(key)

if one exists.
Returns the specific key coercion for the specified key,
def key_coercion(key)
  key_coercions[key.to_sym]
end

def key_coercions

Returns a hash of any existing key coercions.
def key_coercions
  @key_coercions ||= {}
end

def lenient_value_coercions

Return all value coercions that have the :strict rule as false.
def lenient_value_coercions
  @lenient_value_coercions ||= {}
end

def strict_value_coercions

Return all value coercions that have the :strict rule as true.
def strict_value_coercions
  @strict_value_coercions ||= {}
end

def value_coercion(value)

Fetch the value coercion, if any, for the specified object.
def value_coercion(value)
  from = value.class
  strict_value_coercions[from] || lenient_value_coercions[from]
end