Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Easing the use of EmbeddedDocument pattern in Ruby
require 'json'
require 'date'
# Embedders
def scalar
lambda { |x| x }
end
def date
lambda { |x| Date.parse(x) }
end
# Embedder combinators
def sequence_of(e)
lambda { |array|
array.map {|x| e.call(x)}
}
end
def defaulted(e, default)
lambda { |value|
value.nil? ? default : e.call(value)
}
end
# A super-class for embedded document classes. As can be seen, its class is itself an embedder.
class EmbeddedDocument < Struct.new(:data)
def self.key(name, embedder, accessor_name = nil)
name = name.to_s
accessor_name ||= name
define_method(accessor_name) do
embedder.call(self.data[name])
end
end
def self.call(value)
self.new(value)
end
def method_missing(sym)
self.data[sym.to_s]
end
end
# Use:
class Item < EmbeddedDocument
end
class Delivery < EmbeddedDocument
key :shipDate, date, :ship_date
key :items, sequence_of(Item)
end
class Order < EmbeddedDocument
key :deliveries, sequence_of(Delivery)
key :items, sequence_of(Item)
def quantity_for(a_product)
item = items.detect{|i| a_product == i.product}
item ? item.quantity : 0
end
end
order_hash = JSON.parse(
'{ "id": 1234,
"customer": "martin",
"items": [
{"product": "talisker", "quantity": 500},
{"product": "macallan", "quantity": 800},
{"product": "ledaig", "quantity": 1100}
],
"deliveries": [
{ "id": 7722,
"shipDate": "2013-04-19",
"items": [
{"product": "talisker", "quantity": 300},
{"product": "ledaig", "quantity": 500}
]
},
{ "id": 6533,
"shipDate": "2013-04-18",
"items": [
{"product": "talisker", "quantity": 200},
{"product": "ledaig", "quantity": 300},
{"product": "macallan", "quantity": 300}
]
}
]
}'
)
order = Order.new(order_hash)
p order.deliveries
p order.quantity_for('talisker')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.