module Hashie::Extensions::Coercion::InstanceMethods

def coerce_or_init(type)

def coerce_or_init(type)
  return type if type.is_a? Proc
  if CORE_TYPES.key?(type)
    lambda do |v|
      return v if v.is_a? type
      return v.send(CORE_TYPES[type])
    end
  elsif type.respond_to?(:coerce)
    lambda do |v|
      return v if v.is_a? type
      type.coerce(v)
    end
  elsif type.respond_to?(:new)
    lambda do |v|
      return v if v.is_a? type
      type.new(v)
    end
  else
    fail TypeError, "#{type} is not a coercable type"
  end
end

def custom_writer(key, value, _convert = true)

def custom_writer(key, value, _convert = true)
  self[key] = value
end

def replace(other_hash)

def replace(other_hash)
  (keys - other_hash.keys).each { |key| delete(key) }
  other_hash.each { |key, value| self[key] = value }
  self
end

def set_value_with_coercion(key, value)

def set_value_with_coercion(key, value)
  into = self.class.key_coercion(key) || self.class.value_coercion(value)
  return set_value_without_coercion(key, value) if value.nil? || into.nil?
  begin
    return set_value_without_coercion(key, coerce_or_init(into).call(value)) unless into.is_a?(Enumerable)
    if into.class <= ::Hash
      key_coerce = coerce_or_init(into.flatten[0])
      value_coerce = coerce_or_init(into.flatten[-1])
      value = into.class[value.map { |k, v| [key_coerce.call(k), value_coerce.call(v)] }]
    else # Enumerable but not Hash: Array, Set
      value_coerce = coerce_or_init(into.first)
      value = into.class.new(value.map { |v| value_coerce.call(v) })
    end
  rescue NoMethodError, TypeError => e
    raise CoercionError, "Cannot coerce property #{key.inspect} from #{value.class} to #{into}: #{e.message}"
  end
  set_value_without_coercion(key, value)
end