Module: Diffbot::CoercibleHash
- Included in:
- Frontpage, Item, Items::Product, Product
- Defined in:
- lib/diffbot/coercible_hash.rb
Overview
Public: Extend a hash with this mixin to make keys coercible to certain classes. These keys, when assigned to the hash, will be transformed into the specified classes.
The object you pass as coercion types should implement either a ‘coerce` or a `new` method.
You can define rules to coerce properties into classes or collections of classes. In the latter case, CoercibleHash will just map over whatever value is passed and attempt to coerce each item individually to the given class.
Examples
class Address < Struct.new(:street, :zipcode, :state)
def self.coerce(address)
new(address[:street], address[:zipcode], address[:state])
end
end
class Person < Hash
extend Diffbot::CoercibleHash
coerce_property :address, Address
coerce_property :children, collection: Person
def name
self["name"]
end
end
person = Person.new(address: {
street: "123 Example St.", zipcode: "12345", state: "XX"
})
person.address.street #=> "123 Example St."
# etc.
father = Person.new(name: "John", children: [
{ name: "Tim" }, { name: "Sarah" }
])
father.name #=> "John"
father.children.first.name #=> "Tim"
father.children.last.name #=> "Sarah"
Instance Attribute Summary collapse
-
#coercions ⇒ Object
readonly
The coercion rules defined for this hash.
Class Method Summary collapse
-
.extended(base) ⇒ Object
Adds a #[]= that checks for coercion on the property and delegates to super.
Instance Method Summary collapse
-
#coerce_property(property, options) ⇒ Object
Public: Coerce a property of this hash into a given type.
Instance Attribute Details
#coercions ⇒ Object (readonly)
The coercion rules defined for this hash.
48 49 50 |
# File 'lib/diffbot/coercible_hash.rb', line 48 def coercions @coercions end |
Class Method Details
.extended(base) ⇒ Object
Adds a #[]= that checks for coercion on the property and delegates to super.
51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/diffbot/coercible_hash.rb', line 51 def self.extended(base) base.instance_variable_set("@coercions", {}) base.class_eval do def []=(property, value) if self.class.coercions.key?(property.to_s) super property, self.class.coercions[property.to_s].(value) else super end end end end |
Instance Method Details
#coerce_property(property, options) ⇒ Object
Public: Coerce a property of this hash into a given type. We will try to call .coerce on the object you pass as the class, and if that fails, we will call .new.
property - The name of the property to coerce. class_or_options - Either a class to which coerce, or a hash with options:
* class: The class to which coerce
* collection: Coerce the key into an array of members of
this class.
Examples
class Person < Hash
extend Diffbot::CoercibleHash
coerce_property :address, Address
coerce_property :children, collection: Person
coerce_property :dob, class: Date
end
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/diffbot/coercible_hash.rb', line 85 def coerce_property(property, ) unless .is_a?(Hash) = { class: } end coercion_method = ->(obj) do if obj.respond_to?(:coerce) obj.method(:coerce) elsif obj.respond_to?(:new) obj.method(:new) else raise ArgumentError, "#{obj.inspect} does not implement neither .coerce nor .new" end end if .has_key?(:collection) klass = [:collection] coercion = ->(value) { value.map { |el| coercion_method[klass][el] } } elsif .has_key?(:class) klass = [:class] coercion = ->(value) { coercion_method[klass][value] } else raise ArgumentError, "You need to specify either :class or :collection" end coercions[property.to_s] = coercion end |