require 'dm-core'
# An item is identified by a name, for example, Bread
class Item
include DataMapper::Resource
property :name, String, :key => true, :length => 100
has n, :stacks
# recipes which produce this item
has n, :producing_recipes, :model => 'Recipe',
:child_key => [:product_name]
# recipes which use this item as an ingredient
def consuming_recipes
Recipe.all.select do |recipe|
recipe.ingredients.any? do |ingredient|
ingredient == self
end
end
end
# items which are products of consuming_recipes
def derivatives
consuming_recipes.map(&:product)
end
# items which are ingredients in producing_recipes
def materials
producing_recipes.inject do |items, recipe|
items + recipe.ingredients
end
end
end
# A stack contains a number of the same item
class Stack
include DataMapper::Resource
property :id, Serial
property :quantity, Integer
belongs_to :item
belongs_to :bag
end
# A bag contains a number of stacks
class Bag
include DataMapper::Resource
property :id, Serial
property :type, Discriminator
has n, :stacks
has n, :items, :through => :stacks
# retrieve the quantity of the given item in the bag, when 0 returns default
def [](item, default=0)
if stack = stacks.first('item.name' => item.name)
stack.quantity
else
default
end
end
# set the quantity of the given item in the bag
def []=(item, quantity)
if stack = stacks.first('item.name' => item.name)
stack.quantity = quantity
else
stacks << Stack.new(:item_name => item.name, :quantity => quantity)
end
end
# return a hash of item => quantity
def quantities
ret = {}
stacks.each {|stack| ret[stack.item] = stack.quantity}
end
end
# A recipe has one product item, and a few ingredient items each with a
# quantity, for example, Bread = 2 Flour + 1 Yeast + 1 Water
class Recipe < Bag
# include DataMapper::Resource
belongs_to :product, :model => 'Item',
:child_key => [:product_name]
alias_method :ingredients, :items
end
# An identity is identified by an url, and has an inventory
class Identity
include DataMapper::Resource
property :url, String, :key => true, :length => 100
has 1, :inventory
has n, :items, :through => :inventory
end
# An inventory has a number of different items, and belongs to an identity
class Inventory < Bag
# include DataMapper::Resource
belongs_to :identity
end