Class: RGen::ModelBuilder::BuilderContext

Inherits:
Object
  • Object
show all
Defined in:
lib/rgen/model_builder/builder_context.rb

Defined Under Namespace

Classes: CommandResolver, ConstPathElement, ExtensionContainerFactory, PackageNotFoundException, PackageResolver

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(package, extensionsModule, resolver, env = nil) ⇒ BuilderContext

Returns a new instance of BuilderContext.



11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/rgen/model_builder/builder_context.rb', line 11

def initialize(package, extensionsModule, resolver, env=nil)
  package = package.ecore unless package.is_a?(RGen::ECore::EPackage)
  raise "First argument must be a metamodel package" \
    unless package.is_a?(RGen::ECore::EPackage)
  @rootPackage, @env = package, env
  @commandResolver = CommandResolver.new(package, extensionsModule, self)
  @package = @rootPackage
  @resolver = resolver
  @contextStack = []
  @toplevelElements = []
  @helperNames = {}
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *args, &block) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/rgen/model_builder/builder_context.rb', line 52

def method_missing(m, *args, &block)
  package, classOrContainer = @commandResolver.resolveCommand(m, @package)
  return super if package.nil?
  return classOrContainer.send(m, *args, &block) if classOrContainer.is_a?(ExtensionContainerFactory::ExtensionContainer)
  eClass = classOrContainer
  nameArg, argHash = self.class.processArguments(args)
  internalName = nameArg || argHash[:name]
  argHash[:name] ||= nameArg if nameArg && self.class.hasNameAttribute(eClass)
  resolverJobs, asRole, helperName = self.class.filterArgHash(argHash, eClass)
  element = eClass.instanceClass.new(argHash)
  @resolver.setElementName(element, internalName)
  @env << element if @env
  contextElement = @contextStack.last
  if contextElement
    self.class.associateWithContextElement(element, contextElement, asRole)
  else
    @toplevelElements << element
  end
  resolverJobs.each do |job|
    job.receiver = element
    job.namespace = contextElement
    @resolver.addJob(job)
  end
  # process block
  if block
    @contextStack.push(element)
    @package, oldPackage = package, @package
    instance_eval(&block)
    @package = oldPackage
    @contextStack.pop
  end
  element
end

Instance Attribute Details

#toplevelElementsObject (readonly)

Returns the value of attribute toplevelElements.



9
10
11
# File 'lib/rgen/model_builder/builder_context.rb', line 9

def toplevelElements
  @toplevelElements
end

Class Method Details

.associateWithContextElement(element, contextElement, asRole) ⇒ Object



287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/rgen/model_builder/builder_context.rb', line 287

def associateWithContextElement(element, contextElement, asRole)
  return unless contextElement
  contextClass = contextElement.class.ecore
  if asRole
    asRoleRef = eAllReferences(contextClass).find{|r| r.name == asRole.to_s}
    raise "Context class #{contextClass.name} has no reference named #{asRole}" unless asRoleRef
    ref = asRoleRef
  else
    possibleContainmentRefs = containmentRefs(contextClass, element.class.ecore)
    if possibleContainmentRefs.size == 1
      ref = possibleContainmentRefs.first
    elsif possibleContainmentRefs.size == 0
      raise "Context class #{contextClass.name} can not contain a #{element.class.ecore.name}"
    else
      raise "Context class #{contextClass.name} has several containment references to a #{element.class.ecore.name}." +
        " Clearify using \":as => <role>\""
    end
  end
  if ref.many
    contextElement.addGeneric(ref.name, element)
  else
    contextElement.setGeneric(ref.name, element)
  end
end

.containmentRefs(contextClass, eClass) ⇒ Object



279
280
281
282
283
284
285
# File 'lib/rgen/model_builder/builder_context.rb', line 279

def containmentRefs(contextClass, eClass)
  @containmentRefs ||= {}
  @containmentRefs[[contextClass, eClass]] ||=
    eAllReferences(contextClass).select do |r| 
      r.containment && (eClass.eAllSuperTypes << eClass).include?(r.eType)
    end
end

.eAllReferences(eClass) ⇒ Object



274
275
276
277
# File 'lib/rgen/model_builder/builder_context.rb', line 274

def eAllReferences(eClass)
  @eAllReferences ||= {}
  @eAllReferences[eClass] ||= eClass.eAllReferences
end

.filterArgHash(argHash, eClass) ⇒ Object



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/rgen/model_builder/builder_context.rb', line 238

def filterArgHash(argHash, eClass)
  resolverJobs = []
  asRole, helperName = nil, nil
  refByName = {}
  eAllReferences(eClass).each {|r| refByName[r.name] = r}
  argHash.each_pair do |k,v|
    if k == :as
      asRole = v
      argHash.delete(k)
    elsif k == :name && !hasNameAttribute(eClass)
      helperName = v          
      argHash.delete(k)
    elsif v.is_a?(String)
      ref = refByName[k.to_s]#eAllReferences(eClass).find{|r| r.name == k.to_s}
      if ref
        argHash.delete(k)
        resolverJobs << ReferenceResolver::ResolverJob.new(nil, ref, nil,  v)
      end
    elsif v.is_a?(Array)
      ref = refByName[k.to_s] #eAllReferences(eClass).find{|r| r.name == k.to_s}
      ref && v.dup.each do |e|
        if e.is_a?(String)
          v.delete(e)
          resolverJobs << ReferenceResolver::ResolverJob.new(nil, ref, nil, e)
        end
      end
    end
  end
  [ resolverJobs, asRole, helperName ]
end

.hasNameAttribute(eClass) ⇒ Object



269
270
271
272
# File 'lib/rgen/model_builder/builder_context.rb', line 269

def hasNameAttribute(eClass)
  @hasNameAttribute ||= {}
  @hasNameAttribute[eClass] ||= eClass.eAllAttributes.any?{|a| a.name == "name"}
end

.processArguments(args) ⇒ Object



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/rgen/model_builder/builder_context.rb', line 221

def processArguments(args)
  unless (args.size == 2 && args.first.is_a?(String) && args.last.is_a?(Hash)) ||
    (args.size == 1 && (args.first.is_a?(String) || args.first.is_a?(Hash))) ||
    args.size == 0
    raise "Provide a Hash to set feature values, " +
      "optionally the first argument may be a String specifying " + 
      "the value of the \"name\" attribute."
  end
  if args.last.is_a?(Hash)
    argHash = args.last
  else
    argHash = {}
  end
  nameArg = args.first if args.first.is_a?(String)
  [nameArg, argHash]
end

.resolvePackage(contextPackage, rootPackage, path) ⇒ Object



198
199
200
201
202
203
204
205
206
207
208
# File 'lib/rgen/model_builder/builder_context.rb', line 198

def resolvePackage(contextPackage, rootPackage, path)
  begin
    return resolvePackageDownwards(contextPackage, path)
  rescue PackageNotFoundException
    if contextPackage.eSuperPackage && contextPackage != rootPackage
      return resolvePackage(contextPackage.eSuperPackage, rootPackage, path)
    else
      raise
    end
  end
end

.resolvePackageDownwards(contextPackage, path) ⇒ Object



210
211
212
213
214
215
216
217
218
219
# File 'lib/rgen/model_builder/builder_context.rb', line 210

def resolvePackageDownwards(contextPackage, path)
  first, *rest = path
  package = contextPackage.eSubpackages.find{|p| p.name == first}
  raise PackageNotFoundException.new("Could not resolve package: #{first} is not a subpackage of #{contextPackage.name}") unless package
  if rest.empty?
    package 
  else
    resolvePackageDownwards(package, rest)
  end
end

Instance Method Details

#_context(depth = 1) ⇒ Object



93
94
95
# File 'lib/rgen/model_builder/builder_context.rb', line 93

def _context(depth=1)
  @contextStack[-depth]
end

#_using(constPathElement, &block) ⇒ Object



86
87
88
89
90
91
# File 'lib/rgen/model_builder/builder_context.rb', line 86

def _using(constPathElement, &block)
  @package, oldPackage = 
    self.class.resolvePackage(@package, @rootPackage, constPathElement.constPath), @package
  instance_eval(&block)
  @package = oldPackage
end

#const_missing_delegated(delegator, const) ⇒ Object



24
25
26
# File 'lib/rgen/model_builder/builder_context.rb', line 24

def const_missing_delegated(delegator, const)
  ConstPathElement.new(const, self)
end