1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
module RGen
module Instantiator
class AbstractInstantiator
ResolverDescription = Struct.new(:from, :attribute, :block) # :nodoc:
class << self
attr_accessor :resolver_descs
end
def initialize(env)
@env = env
end
# Specifies that +attribute+ should be resolved. If +:class+ is specified,
# resolve +attribute+ only for objects of type class.
# The block must return the value to which the attribute should be assigned.
# The object for which the attribute is to be resolved will be accessible
# in the current context within the block.
#
def self.resolve(attribute, desc=nil, &block)
from = (desc.is_a?(Hash) && desc[:class])
self.resolver_descs ||= []
self.resolver_descs << ResolverDescription.new(from, attribute, block)
end
# Resolves +attribute+ to a model element which has attribute +:id+ set to the
# value currently in attribute +:src+
#
def self.resolve_by_id(attribute, desc)
id_attr = (desc.is_a?(Hash) && desc[:id])
src_attr = (desc.is_a?(Hash) && desc[:src])
raise StandardError.new("No id attribute given.") unless id_attr
resolve(attribute) do
@env.find(id_attr => @current_object.send(src_attr)).first
end
end
private
def method_missing(m, *args) #:nodoc:
if @current_object
@current_object.send(m)
else
super
end
end
def resolve
self.class.resolver_descs ||= []
self.class.resolver_descs.each { |desc|
@env.find(:class => desc.from).each { |e|
old_object, @current_object = @current_object, e
e.send("#{desc.attribute}=", instance_eval(&desc.block)) if e.respond_to?("#{desc.attribute}=")
@current_object = old_object
}
}
end
end
end
end
|