class RGen::ModelBuilder::ReferenceResolver

Constants

ResolverJob

Public Class Methods

new() click to toggle source
# File lib/rgen/model_builder/reference_resolver.rb, line 23
def initialize
  @jobs = []
  @elementName = {}
end

Public Instance Methods

addJob(job) click to toggle source
# File lib/rgen/model_builder/reference_resolver.rb, line 28
def addJob(job)
  @jobs << job
end
resolve(ns=[]) click to toggle source
# File lib/rgen/model_builder/reference_resolver.rb, line 36
def resolve(ns=[])
  @toplevelNamespace = ToplevelNamespace.new(ns)
  (@jobs || []).each_with_index do |job, i|
    target = resolveReference(job.namespace || @toplevelNamespace, job.string.split("."))
    raise ResolverException.new("Can not resolve reference #{job.string}") unless target
    if job.reference.many
      job.receiver.addGeneric(job.reference.name, target)
    else
      job.receiver.setGeneric(job.reference.name, target)
    end
  end
end
setElementName(element, name) click to toggle source
# File lib/rgen/model_builder/reference_resolver.rb, line 32
def setElementName(element, name)
  @elementName[element] = name
end

Private Instance Methods

containmentRefs(element) click to toggle source
# File lib/rgen/model_builder/reference_resolver.rb, line 138
def containmentRefs(element)
  @containmentRefs ||= {}
  @containmentRefs[element.class] ||= eAllReferences(element).select{|r| r.containment}
end
eAllReferences(element) click to toggle source
# File lib/rgen/model_builder/reference_resolver.rb, line 148
def eAllReferences(element)
  @eAllReferences ||= {}
  @eAllReferences[element.class] ||= element.class.ecore.eAllReferences
end
elementChildren(element) click to toggle source
# File lib/rgen/model_builder/reference_resolver.rb, line 120
def elementChildren(element)
  @elementChildren ||= {}
  return @elementChildren[element] if @elementChildren[element]
  children = containmentRefs(element).collect do |r|
    element.getGeneric(r.name)
  end.flatten.compact
  @elementChildren[element] = children
end
elementName(element) click to toggle source
# File lib/rgen/model_builder/reference_resolver.rb, line 116
def elementName(element)
  @elementName[element]
end
elementParents(element) click to toggle source
# File lib/rgen/model_builder/reference_resolver.rb, line 129
def elementParents(element)
  @elementParents ||= {}
  return @elementParents[element] if @elementParents[element]
  parents = parentRefs(element).collect do |r|
    element.getGeneric(r.name)
  end.flatten.compact
  @elementParents[element] = parents
end
namespaceElementByName(namespace, name) click to toggle source
# File lib/rgen/model_builder/reference_resolver.rb, line 73
def namespaceElementByName(namespace, name)
  @namespaceElementsByName ||= {}
  return @namespaceElementsByName[namespace][name] if @namespaceElementsByName[namespace]
  hash = {}
  namespaceElements(namespace).each do |e|
    raise ResolverException.new("Multiple elements named #{elementName(e)} found in #{nsToS(namespace)}") if hash[elementName(e)]
    hash[elementName(e)] = e if elementName(e)
  end
  @namespaceElementsByName[namespace] = hash
  hash[name]
end
namespaceElements(namespace) click to toggle source
# File lib/rgen/model_builder/reference_resolver.rb, line 96
def namespaceElements(namespace)
  if namespace.is_a?(ToplevelNamespace)
    namespace.elements
  elsif namespace.class.respond_to?(:ecore)
    elementChildren(namespace)
  else
    raise ResolverException.new("Element #{nsToS(namespace)} can not be used as a namespace")
  end
end
nsToS(namespace) click to toggle source
# File lib/rgen/model_builder/reference_resolver.rb, line 106
def nsToS(namespace)
  if namespace.is_a?(ToplevelNamespace)
    "toplevel namespace"
  else
    result = namespace.class.name    
    result += ":\"#{elementName(namespace)}\"" if elementName(namespace)
    result
  end
end
parentNamespace(namespace) click to toggle source
# File lib/rgen/model_builder/reference_resolver.rb, line 85
def parentNamespace(namespace)
  if namespace.class.respond_to?(:ecore)
    parents = elementParents(namespace)
    raise ResolverException.new("Element #{nsToS(namespace)} has multiple parents") \
      if parents.size > 1
    parents.first || @toplevelNamespace
  else
    nil
  end
end
parentRefs(element) click to toggle source
# File lib/rgen/model_builder/reference_resolver.rb, line 143
def parentRefs(element)
  @parentRefs ||= {}
  @parentRefs[element.class] ||= eAllReferences(element).select{|r| r.eOpposite && r.eOpposite.containment}
end
resolveReference(namespace, nameParts) click to toggle source

TODO: if a reference can not be fully resolved, but a prefix can be found, the exception reported is that its first path element can not be found on toplevel

# File lib/rgen/model_builder/reference_resolver.rb, line 54
def resolveReference(namespace, nameParts)
  element = resolveReferenceDownwards(namespace, nameParts)
  if element.nil? && parentNamespace(namespace)
    element = resolveReference(parentNamespace(namespace), nameParts)
  end
  element
end
resolveReferenceDownwards(namespace, nameParts) click to toggle source
# File lib/rgen/model_builder/reference_resolver.rb, line 62
def resolveReferenceDownwards(namespace, nameParts)
  firstPart, *restParts = nameParts
  element = namespaceElementByName(namespace, firstPart)
  return nil unless element
  if restParts.size > 0
    resolveReferenceDownwards(element, restParts)
  else
    element
  end
end