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)
- 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 = {})
- 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)
Returns the specific key coercion for the specified key,
def key_coercion(key) key_coercions[key.to_sym] end
def key_coercions
def key_coercions @key_coercions ||= {} end
def lenient_value_coercions
def lenient_value_coercions @lenient_value_coercions ||= {} end
def strict_value_coercions
def strict_value_coercions @strict_value_coercions ||= {} end
def value_coercion(value)
def value_coercion(value) from = value.class strict_value_coercions[from] || lenient_value_coercions[from] end