def self.copy(from, to=nil)
raise StandardError.new("Specify target class either directly as second parameter or using :to => <class>") \
unless to.nil? || to.is_a?(Class) || (to.is_a?(Hash) && to[:to].is_a?(Class))
to = to[:to] if to.is_a?(Hash)
transform(from, :to => to || from) do
copy_features
end
end
def self.copy_all(from, hash={})
to = hash[:to] || from
except = hash[:except]
fromDepth = from.ecore.qualifiedName.split("::").size
from.ecore.eAllClasses.each do |c|
path = c.qualifiedName.split("::")[fromDepth..-1]
next if except && except.include?(path.join("::"))
copy c.instanceClass, :to => path.inject(to){|m,c| m.const_get(c)}
end
end
def self.method(name, &block)
_methods[name.to_s] = block
end
def initialize(env_in=nil, env_out=nil, elementMap=nil)
@env_in = env_in
@env_out = env_out
@transformer_results = elementMap || {}
@transformer_jobs = []
end
def trans(obj)
if obj.is_a?(Hash)
raise StandardError.new("No input environment available to find model element.") unless @env_in
obj = @env_in.find(obj)
end
return nil if obj.nil?
return obj if obj.is_a?(TrueClass) or obj.is_a?(FalseClass) or obj.is_a?(Numeric) or obj.is_a?(Symbol)
return @transformer_results[obj] if @transformer_results[obj]
return @transformer_results[obj] = obj.dup if obj.is_a?(String)
return obj.collect{|o| trans(o)}.compact if obj.is_a? Array
raise StandardError.new("No transformer for class #{obj.class.name}") unless _transformerBlock(obj.class)
block_desc = _evaluateCondition(obj)
return nil unless block_desc
@transformer_results[obj] = _instantiateTargetClass(obj, block_desc.target)
@transformer_jobs << TransformerJob.new(self, obj, block_desc)
return @transformer_results[obj] if @transformer_jobs.size > 1
while @transformer_jobs.size > 0
@transformer_jobs.first.execute
@transformer_jobs.shift
end
@transformer_results[obj]
end
def copy_features(options={})
hash = {}
@current_object.class.ecore.eAllStructuralFeatures.each do |f|
next if f.derived
next if options[:except] && options[:except].include?(f.name.to_sym)
hash[f.name.to_sym] = trans(@current_object.send(f.name))
end
hash.merge!(yield) if block_given?
hash
end
def _transformProperties(obj, block_desc)
old_object, @current_object = @current_object, obj
block_result = instance_eval(&block_desc.block)
raise StandardError.new("Transformer must return a hash") unless block_result.is_a? Hash
@current_object = old_object
_attributesFromHash(@transformer_results[obj], block_result)
end
class TransformerJob
def initialize(transformer, obj, block_desc)
@transformer, @obj, @block_desc = transformer, obj, block_desc
end
def execute
@transformer._transformProperties(@obj, @block_desc)
end
end
def method_missing(m, *args)
if @current_object.respond_to?(m)
@current_object.send(m, *args)
else
_invokeMethod(m, *args)
end
end
private
def _transformerBlock(clazz)
block = self.class._transformer_blocks[clazz]
block = _transformerBlock(clazz.superclass) if block.nil? && clazz != Object
block
end
def _evaluateCondition(obj, clazz=obj.class)
tb = self.class._transformer_blocks[clazz]
block_description = nil
if tb.is_a?(TransformationDescription)
block_description = tb
elsif tb
old_object, @current_object = @current_object, obj
tb.each_pair {|condition, block|
if condition.is_a?(Proc)
result = instance_eval(&condition)
elsif condition.is_a?(Symbol)
result = _invokeMethod(condition)
else
result = condition
end
if result
block_description = block
break
end
}
@current_object = old_object
end
block_description = _evaluateCondition(obj, clazz.superclass) if block_description.nil? && clazz != Object
block_description
end
def _instantiateTargetClass(obj, target_desc)
old_object, @current_object = @current_object, obj
if target_desc.is_a?(Proc)
target_class = instance_eval(&target_desc)
elsif target_desc.is_a?(Symbol)
target_class = _invokeMethod(target_desc)
else
target_class = target_desc
end
@current_object = old_object
result = target_class.new
@env_out << result if @env_out
result
end
def _invokeMethod(m)
raise StandardError.new("Method not found: #{m}") unless self.class._methods[m.to_s]
instance_eval(&self.class._methods[m.to_s])
end
def _attributesFromHash(obj, hash)
hash.delete(:class)
hash.each_pair{|k,v|
obj.send("#{k}=", v)
}
obj
end
end