require 'rgen/instantiator/reference_resolver' module RGen module Instantiator # This is a resolver resolving element identifiers which are qualified names. class QualifiedNameResolver attr_reader :nameAttribute attr_reader :separator attr_reader :leadingSeparator def initialize(rootElements, options={}) @rootElements = rootElements @nameAttribute = options[:nameAttribute] || "name" @separator = options[:separator] || "/" @leadingSeparator = options.has_key?(:leadingSeparator) ? options[:leadingSeparator] : true @elementByQName = {} @visitedQName = {} @childReferences = {} @resolverDelegate = ReferenceResolver.new(:identifier_resolver => method(:resolveIdentifier)) end def resolveIdentifier(qualifiedName) return @elementByQName[qualifiedName] if @elementByQName.has_key?(qualifiedName) path = qualifiedName.split(separator).reject{|s| s == ""} if path.size > 1 parentQName = (leadingSeparator ? separator : "") + path[0..-2].join(separator) parents = resolveIdentifier(parentQName) parents = [parents].compact unless parents.is_a?(Array) children = parents.collect{|p| allNamedChildren(p)}.flatten elsif path.size == 1 parentQName = "" children = allRootNamedChildren else return @elementByQName[qualifiedName] = nil end # if the parent was already visited all matching elements are the hash if !@visitedQName[parentQName] children.each do |c| name = c.send(nameAttribute) if name qname = parentQName + ((parentQName != "" || leadingSeparator) ? separator : "") + name existing = @elementByQName[qname] if existing @elementByQName[qname] = [existing] unless existing.is_a?(Array) @elementByQName[qname] << c else @elementByQName[qname] = c end end end # all named children of praent have been checked and hashed @visitedQName[parentQName] = true end @elementByQName[qualifiedName] ||= nil end def resolveReferences(unresolvedReferences, problems=[]) @resolverDelegate.resolve(unresolvedReferences, :problems => problems) end private def allNamedChildren(element) childReferences(element.class).collect do |r| element.getGenericAsArray(r.name).collect do |c| if c.respond_to?(nameAttribute) c else allNamedChildren(c) end end end.flatten end def allRootNamedChildren @rootElements.collect do |e| if e.respond_to?(nameAttribute) e else allNamedChildren(e) end end.flatten end def childReferences(clazz) @childReferences[clazz] ||= clazz.ecore.eAllReferences.select{|r| r.containment} end end end end