rgen 0.4.6 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/CHANGELOG +95 -83
  2. data/Rakefile +4 -3
  3. data/lib/ea_support/ea_support.rb +54 -0
  4. data/lib/ea_support/id_store.rb +32 -0
  5. data/lib/ea_support/uml13_ea_metamodel.rb +562 -0
  6. data/lib/ea_support/uml13_ea_metamodel_ext.rb +45 -0
  7. data/lib/ea_support/uml13_ea_metamodel_generator.rb +43 -0
  8. data/lib/ea_support/uml13_ea_to_uml13.rb +72 -0
  9. data/lib/ea_support/uml13_to_uml13_ea.rb +82 -0
  10. data/lib/rgen/ecore/ecore.rb +16 -2
  11. data/lib/rgen/ecore/ecore_builder_methods.rb +81 -0
  12. data/lib/rgen/ecore/ecore_instantiator.rb +5 -1
  13. data/lib/rgen/metamodel_builder/builder_extensions.rb +11 -3
  14. data/lib/rgen/metamodel_builder/module_extension2.rb +205 -0
  15. data/lib/rgen/method_delegation.rb +99 -0
  16. data/lib/rgen/model_builder.rb +27 -0
  17. data/lib/rgen/model_builder/builder_context.rb +318 -0
  18. data/lib/rgen/model_builder/model_serializer.rb +201 -0
  19. data/lib/rgen/model_builder/reference_resolver.rb +156 -0
  20. data/lib/rgen/template_language/directory_template_container.rb +6 -2
  21. data/lib/rgen/template_language/output_handler.rb +2 -4
  22. data/lib/rgen/template_language/template_container.rb +212 -195
  23. data/lib/rgen/transformer.rb +95 -4
  24. data/lib/transformers/ecore_to_uml13.rb +66 -0
  25. data/lib/transformers/uml13_to_ecore.rb +16 -7
  26. data/test/ea_instantiator_test.rb +8 -14
  27. data/test/ea_serializer_test.rb +3 -9
  28. data/test/ea_serializer_test/ea_testmodel_regenerated.xml +2 -2
  29. data/test/ea_serializer_test/ea_testmodel_regenerated_import.log +3 -0
  30. data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +19 -19
  31. data/test/metamodel_roundtrip_test/houseMetamodel_Regenerated.ecore +44 -44
  32. data/test/method_delegation_test.rb +178 -0
  33. data/test/model_builder/builder_context_test.rb +59 -0
  34. data/test/model_builder/builder_test.rb +284 -0
  35. data/test/model_builder/ecore_internal.rb +103 -0
  36. data/test/model_builder/ecore_original.rb +163 -0
  37. data/test/model_builder/ecore_original_regenerated.rb +163 -0
  38. data/test/model_builder/reference_resolver_test.rb +156 -0
  39. data/test/model_builder/serializer_test.rb +63 -0
  40. data/test/model_builder_test.rb +4 -0
  41. data/test/rgen_test.rb +2 -0
  42. data/test/template_language_test.rb +41 -1
  43. data/test/template_language_test/expected_result1.txt +1 -3
  44. data/test/template_language_test/templates/define_local_test/local.tpl +8 -0
  45. data/test/template_language_test/templates/define_local_test/test.tpl +8 -0
  46. data/test/template_language_test/templates/evaluate_test/test.tpl +7 -0
  47. data/test/template_language_test/templates/no_indent_test/no_indent.tpl +3 -0
  48. data/test/template_language_test/templates/no_indent_test/sub1/no_indent.tpl +3 -0
  49. data/test/template_language_test/templates/no_indent_test/test.tpl +24 -0
  50. data/test/template_language_test/templates/no_indent_test/test2.tpl +13 -0
  51. data/test/template_language_test/templates/no_indent_test/test3.tpl +10 -0
  52. data/test/template_language_test/templates/template_resolution_test/sub1.tpl +9 -0
  53. data/test/template_language_test/templates/template_resolution_test/sub1/sub1.tpl +3 -0
  54. data/test/template_language_test/templates/template_resolution_test/test.tpl +4 -0
  55. data/test/template_language_test/testout.txt +1 -3
  56. data/test/testmodel/ea_testmodel_import.log +1 -0
  57. data/test/testmodel/ea_testmodel_regenerated.xml +808 -0
  58. data/test/transformer_test.rb +3 -5
  59. metadata +52 -3
  60. data/lib/instantiators/ea_instantiator.rb +0 -39
@@ -0,0 +1,45 @@
1
+ module UML13EA
2
+ class << self
3
+ attr_accessor :idStore
4
+ end
5
+ module ModelElement::ClassModule
6
+ def qualifiedName
7
+ _name = (respond_to?(:_name) ? self._name : name) || "unnamed"
8
+ _namespace = respond_to?(:_namespace) ? self._namespace : namespace
9
+ _namespace && _namespace.qualifiedName ? _namespace.qualifiedName+"::"+_name : _name
10
+ end
11
+ end
12
+ module XmiIdProvider::ClassModule
13
+ def _xmi_id
14
+ UML13EA.idStore.idHash[qualifiedName] ||= "EAID_"+object_id.to_s
15
+ end
16
+ end
17
+ module Package::ClassModule
18
+ def _xmi_id
19
+ UML13EA.idStore.idHash[qualifiedName] ||= "EAPK_"+object_id.to_s
20
+ end
21
+ end
22
+ module Generalization::ClassModule
23
+ def _name
24
+ "#{subtype.name}_#{supertype.name}"
25
+ end
26
+ end
27
+ module Association::ClassModule
28
+ def _name
29
+ connection.collect{|c| "#{c.getType.name}_#{c.name}"}.sort.join("_")
30
+ end
31
+ end
32
+ module AssociationEnd::ClassModule
33
+ def _name
34
+ "#{getType.name}_#{name}"
35
+ end
36
+ def _namespace
37
+ association
38
+ end
39
+ end
40
+ module StateVertex::ClassModule
41
+ def _namespace
42
+ container
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,43 @@
1
+ require 'metamodels/uml13_metamodel'
2
+ require 'mmgen/metamodel_generator'
3
+ require 'rgen/transformer'
4
+ require 'rgen/environment'
5
+ require 'rgen/ecore/ecore'
6
+
7
+ include MMGen::MetamodelGenerator
8
+
9
+ class ECoreCopyTransformer < RGen::Transformer
10
+ copy_all RGen::ECore
11
+ end
12
+
13
+ eaMMRoot = ECoreCopyTransformer.new.trans(UML13.ecore)
14
+
15
+ eaMMRoot.name = "UML13EA"
16
+ eaMMRoot.eClassifiers.find{|c| c.name == "ActivityGraph"}.name = "ActivityModel"
17
+ eaMMRoot.eClassifiers.find{|c| c.name == "Pseudostate"}.name = "PseudoState"
18
+
19
+ compositeState = eaMMRoot.eClassifiers.find{|c| c.name == "CompositeState"}
20
+ compositeState.eReferences.find{|r| r.name == "subvertex"}.name = "substate"
21
+
22
+ generalization = eaMMRoot.eClassifiers.find{|c| c.name == "Generalization"}
23
+ generalization.eReferences.find{|r| r.name == "parent"}.name = "supertype"
24
+ generalization.eReferences.find{|r| r.name == "child"}.name = "subtype"
25
+
26
+ assocEnd = eaMMRoot.eClassifiers.find{|c| c.name == "AssociationEnd"}
27
+ assocEnd.eAttributes.find{|r| r.name == "ordering"}.name = "isOrdered"
28
+ assocEnd.eAttributes.find{|r| r.name == "changeability"}.name = "changeable"
29
+ assocEnd.eAttributes.find{|r| r.name == "isOrdered"}.eType = RGen::ECore::EBoolean
30
+ assocEnd.eAttributes.find{|r| r.name == "changeable"}.eType.eLiterals.find{|l| l.name == "frozen"}.name = "none"
31
+ multRef = assocEnd.eStructuralFeatures.find{|f| f.name == "multiplicity"}
32
+ multRef.eType = nil
33
+ assocEnd.removeEStructuralFeatures(multRef)
34
+ assocEnd.addEStructuralFeatures(RGen::ECore::EAttribute.new(:name => "multiplicity", :eType => RGen::ECore::EString))
35
+
36
+ xmiIdProvider = RGen::ECore::EClass.new(:name => "XmiIdProvider", :ePackage => eaMMRoot)
37
+ eaMMRoot.eClassifiers.each do |c|
38
+ if %w(Package Class Generalization Association AssociationEnd StateVertex).include?(c.name)
39
+ c.addESuperTypes(xmiIdProvider)
40
+ end
41
+ end
42
+
43
+ generateMetamodel(eaMMRoot, File.dirname(__FILE__)+"/uml13_ea_metamodel.rb")
@@ -0,0 +1,72 @@
1
+ require 'rgen/transformer'
2
+ require 'metamodels/uml13_metamodel'
3
+ require 'ea_support/uml13_ea_metamodel'
4
+
5
+ class UML13EAToUML13 < RGen::Transformer
6
+ include UML13EA
7
+
8
+ def transform
9
+ trans(:class => Package)
10
+ trans(:class => Class)
11
+ end
12
+
13
+ def cleanModel
14
+ @env_out.find(:class => UML13::ModelElement).each do |me|
15
+ me.taggedValue = []
16
+ end
17
+ end
18
+
19
+ copy_all UML13EA, :to => UML13, :except => %w(
20
+ XmiIdProvider
21
+ AssociationEnd AssociationEndRole
22
+ StructuralFeature
23
+ Generalization
24
+ ActivityModel
25
+ CompositeState
26
+ PseudoState
27
+ )
28
+
29
+ transform AssociationEndRole, :to => UML13::AssociationEndRole do
30
+ copyAssociationEnd
31
+ end
32
+
33
+ transform AssociationEnd, :to => UML13::AssociationEnd do
34
+ copyAssociationEnd
35
+ end
36
+
37
+ def copyAssociationEnd
38
+ copy_features :except => [:isOrdered, :changeable] do
39
+ {:ordering => isOrdered ? :ordered : :unordered,
40
+ :changeability => {:none => :frozen}[changeable] || changeable,
41
+ :aggregation => {:shared => :aggregate}[aggregation] || aggregation,
42
+ :multiplicity => UML13::Multiplicity.new(
43
+ :range => [UML13::MultiplicityRange.new(
44
+ :lower => multiplicity && multiplicity.split("..").first,
45
+ :upper => multiplicity && multiplicity.split("..").last)])}
46
+ end
47
+ end
48
+
49
+ transform StructuralFeature, :to => UML13::StructuralFeature do
50
+ copy_features :except => [:changeable] do
51
+ {:changeability => {:none => :frozen}[changeable] }
52
+ end
53
+ end
54
+
55
+ transform Generalization, :to => UML13::Generalization do
56
+ copy_features :except => [:subtype, :supertype] do
57
+ { :child => trans(subtype),
58
+ :parent => trans(supertype) }
59
+ end
60
+ end
61
+
62
+ copy ActivityModel, :to => UML13::ActivityGraph
63
+
64
+ transform CompositeState, :to => UML13::CompositeState do
65
+ copy_features :except => [:substate] do
66
+ { :subvertex => trans(substate) }
67
+ end
68
+ end
69
+
70
+ copy PseudoState, :to => UML13::Pseudostate
71
+
72
+ end
@@ -0,0 +1,82 @@
1
+ require 'rgen/transformer'
2
+ require 'metamodels/uml13_metamodel'
3
+ require 'ea_support/uml13_ea_metamodel'
4
+ require 'ea_support/uml13_ea_metamodel_ext'
5
+
6
+ class UML13ToUML13EA < RGen::Transformer
7
+ include UML13
8
+
9
+ def transform
10
+ trans(:class => Package)
11
+ trans(:class => Class)
12
+ end
13
+
14
+ copy_all UML13, :to => UML13EA, :except => %w(
15
+ ActivityGraph
16
+ CompositeState SimpleState
17
+ Class
18
+ Association AssociationEnd AssociationEndRole
19
+ Generalization
20
+ Pseudostate
21
+ )
22
+
23
+ copy ActivityGraph, :to => UML13EA::ActivityModel
24
+
25
+ copy Pseudostate, :to => UML13EA::PseudoState
26
+
27
+ transform CompositeState, :to => UML13EA::CompositeState do
28
+ copy_features :except => [:subvertex] do
29
+ { :substate => trans(subvertex) }
30
+ end
31
+ end
32
+
33
+ transform SimpleState, :to => UML13EA::SimpleState do
34
+ copy_features :except => [:container] do
35
+ { :taggedValue => trans(taggedValue) +
36
+ [@env_out.new(UML13EA::TaggedValue, :tag => "ea_stype", :value => "State")] +
37
+ (container ? [ @env_out.new(UML13EA::TaggedValue, :tag => "owner", :value => trans(container)._xmi_id)] : []) }
38
+ end
39
+ end
40
+
41
+ transform Class, :to => UML13EA::Class do
42
+ copy_features do
43
+ { :taggedValue => trans(taggedValue) + [@env_out.new(UML13EA::TaggedValue, :tag => "ea_stype", :value => "Class")]}
44
+ end
45
+ end
46
+
47
+ transform Association, :to => UML13EA::Association do
48
+ copy_features do
49
+ { :connection => trans(connection[1].isNavigable ? [connection[0], connection[1]] : [connection[1], connection[0]]),
50
+ :taggedValue => trans(taggedValue) + [
51
+ @env_out.new(UML13EA::TaggedValue, :tag => "ea_type", :value => "Association"),
52
+ @env_out.new(UML13EA::TaggedValue, :tag => "direction", :value =>
53
+ connection.all?{|c| c.isNavigable} ? "Bi-Directional" : "Source -&gt; Destination")] }
54
+ end
55
+ end
56
+
57
+ transform AssociationEnd, :to => UML13EA::AssociationEnd do
58
+ copyAssociationEnd
59
+ end
60
+
61
+ transform AssociationEndRole, :to => UML13EA::AssociationEndRole do
62
+ copyAssociationEnd
63
+ end
64
+
65
+ def copyAssociationEnd
66
+ _lower = multiplicity && multiplicity.range.first.lower
67
+ _upper = multiplicity && multiplicity.range.first.upper
68
+ copy_features :except => [:multiplicity, :ordering, :changeability] do
69
+ { :multiplicity => _lower == _upper ? _lower : "#{_lower}..#{_upper}",
70
+ :isOrdered => ordering == :ordered,
71
+ :changeable => :none } #{:frozen => :none}[changeability] || changeability}
72
+ end
73
+ end
74
+
75
+ transform Generalization, :to => UML13EA::Generalization do
76
+ copy_features :except => [:child, :parent] do
77
+ { :taggedValue => trans(taggedValue) + [@env_out.new(UML13EA::TaggedValue, :tag => "ea_type", :value => "Generalization")],
78
+ :subtype => trans(child),
79
+ :supertype => trans(parent)}
80
+ end
81
+ end
82
+ end
@@ -52,7 +52,21 @@ module RGen
52
52
  has_attr 'volatile', Boolean, :defaultValueLiteral => "false"
53
53
  module ClassModule
54
54
  def defaultValue_derived
55
- eval(defaultValueLiteral) unless defaultValueLiteral.nil?
55
+ return nil if defaultValueLiteral.nil?
56
+ case eType
57
+ when EInt
58
+ defaultValueLiteral.to_i
59
+ when EFloat
60
+ defaultValueLiteral.to_f
61
+ when EEnum
62
+ defaultValueLiteral.to_sym
63
+ when EBoolean
64
+ defaultValueLiteral == "true"
65
+ when EString
66
+ defaultValueLiteral
67
+ else
68
+ raise "Unhandled type"
69
+ end
56
70
  end
57
71
  end
58
72
  end
@@ -187,4 +201,4 @@ module RGen
187
201
  ECore::EAttribute.has_one 'eAttributeType', ECore::EDataType, :lowerBound=>1, :derived=>true
188
202
  ECore::EReference.has_one 'eReferenceType', ECore::EClass, :lowerBound=>1, :derived=>true
189
203
 
190
- end
204
+ end
@@ -0,0 +1,81 @@
1
+ module RGen
2
+
3
+ module ECore
4
+
5
+ module ECoreBuilderMethods
6
+ def eAttr(name, type, argHash={}, &block)
7
+ eAttribute(name, {:eType => type}.merge(argHash), &block)
8
+ end
9
+
10
+ def eRef(name, type, argHash={}, &block)
11
+ eReference(name, {:eType => type}.merge(argHash), &block)
12
+ end
13
+
14
+ # create bidirectional reference at once
15
+ def eBiRef(name, type, oppositeName, argHash={})
16
+ raise BuilderError.new("eOpposite attribute not allowed for bidirectional references") \
17
+ if argHash[:eOpposite] || argHash[:opposite_eOpposite]
18
+ eReference(name, {:eType => type}.merge(argHash.reject{|k,v| k.to_s =~ /^opposite_/})) do
19
+ eReference oppositeName, {:eContainingClass => type, :eType => _context(2),
20
+ :as => :eOpposite, :eOpposite => _context(1)}.
21
+ merge(Hash[*(argHash.select{|k,v| k.to_s =~ /^opposite_/}.
22
+ collect{|p| [p[0].to_s.sub(/^opposite_/,"").to_sym, p[1]]}.flatten)])
23
+ end
24
+ end
25
+
26
+ # reference shortcuts
27
+
28
+ alias references_1 eRef
29
+ alias references_one eRef
30
+
31
+ def references_N(name, type, argHash={})
32
+ eRef(name, type, {:upperBound => -1}.merge(argHash))
33
+ end
34
+ alias references_many references_N
35
+
36
+ def references_1to1(name, type, oppositeName, argHash={})
37
+ eBiRef(name, type, oppositeName, {:upperBound => 1, :opposite_upperBound => 1}.merge(argHash))
38
+ end
39
+ alias references_one_to_one references_1to1
40
+
41
+ def references_1toN(name, type, oppositeName, argHash={})
42
+ eBiRef(name, type, oppositeName, {:upperBound => -1, :opposite_upperBound => 1}.merge(argHash))
43
+ end
44
+ alias references_one_to_many references_1toN
45
+
46
+ def references_Nto1(name, type, oppositeName, argHash={})
47
+ eBiRef(name, type, oppositeName, {:upperBound => 1, :opposite_upperBound => -1}.merge(argHash))
48
+ end
49
+ alias references_many_to_one references_Nto1
50
+
51
+ def references_MtoN(name, type, oppositeName, argHash={})
52
+ eBiRef(name, type, oppositeName, {:upperBound => -1, :opposite_upperBound => -1}.merge(argHash))
53
+ end
54
+ alias references_many_to_many references_MtoN
55
+
56
+ # containment reference shortcuts
57
+
58
+ def contains_1(name, type, argHash={})
59
+ references_1(name, type, {:containment => true}.merge(argHash))
60
+ end
61
+ alias contains_one contains_1
62
+
63
+ def contains_N(name, type, argHash={})
64
+ references_N(name, type, {:containment => true}.merge(argHash))
65
+ end
66
+ alias contains_many contains_N
67
+
68
+ def contains_1to1(name, type, oppositeName, argHash={})
69
+ references_1to1(name, type, oppositeName, {:containment => true}.merge(argHash))
70
+ end
71
+ alias contains_one_to_one contains_1to1
72
+
73
+ def contains_1toN(name, type, oppositeName, argHash={})
74
+ references_1toN(name, type, oppositeName, {:containment => true}.merge(argHash))
75
+ end
76
+ alias contains_one_to_many contains_1toN
77
+ end
78
+
79
+ end
80
+
81
+ end
@@ -19,7 +19,11 @@ module ECoreInstantiator
19
19
  end
20
20
  @@transformer.trans(self)
21
21
  end
22
-
22
+
23
+ def self.clear_ecore_cache
24
+ require 'rgen/ecore/ecore_transformer'
25
+ @@transformer = ECoreTransformer.new
26
+ end
23
27
  end
24
28
 
25
29
  end
@@ -217,7 +217,15 @@ module BuilderExtensions
217
217
 
218
218
  def _metamodel_description # :nodoc:
219
219
  @metamodel_description ||= []
220
- end
220
+ end
221
+
222
+ def _add_metamodel_description(desc) # :nodoc
223
+ @metamodel_description ||= []
224
+ @metamodelDescriptionByName ||= {}
225
+ @metamodel_description.delete(@metamodelDescriptionByName[desc.value(:name)])
226
+ @metamodel_description << desc
227
+ @metamodelDescriptionByName[desc.value(:name)] = desc
228
+ end
221
229
 
222
230
  def abstract
223
231
  @abstract = true
@@ -236,7 +244,7 @@ module BuilderExtensions
236
244
  # Central builder method
237
245
  #
238
246
  def _build_internal(props1, props2=nil)
239
- _metamodel_description << props1
247
+ _add_metamodel_description(props1)
240
248
  if props1.is_a?(ReferenceDescription) && props1.many?
241
249
  _build_many_methods(props1, props2)
242
250
  else
@@ -246,7 +254,7 @@ module BuilderExtensions
246
254
  # this is a bidirectional reference
247
255
  props1.opposite, props2.opposite = props2, props1
248
256
  other_class = props1.impl_type
249
- other_class._metamodel_description << props2
257
+ other_class._add_metamodel_description(props2)
250
258
  raise "Internal error: second description must be a ReferenceDescription" \
251
259
  unless props2.is_a?(ReferenceDescription)
252
260
  if props2.many?
@@ -0,0 +1,205 @@
1
+ require 'rgen/ecore/ecore_ext'
2
+
3
+ module RGen
4
+
5
+ module ModelBuilder
6
+
7
+ class BuilderContext
8
+ attr_accessor :contextElement, :resolver
9
+ end
10
+
11
+ class ReferenceResolver
12
+ ResolverJob = Struct.new(:receiver, :reference, :namespace, :string)
13
+
14
+ class ResolverException < Exception
15
+ end
16
+
17
+ def addJob(job)
18
+ @jobs ||= []
19
+ @jobs << job
20
+ end
21
+
22
+ def resolve(env=nil)
23
+ (@jobs || []).each do |job|
24
+ begin
25
+ target = resolveReference(env, job.namespace, job.string.split("."), job.reference.eType.instanceClass, true)
26
+ rescue ResolverException => e
27
+ raise ResolverException.new("Can not resolve reference #{job.string}: #{e.message}")
28
+ end
29
+ if job.reference.many
30
+ job.receiver.addGeneric(job.reference.name, target)
31
+ else
32
+ job.receiver.setGeneric(job.reference.name, target)
33
+ end
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def resolveReference(env, namespace, nameParts, targetClass, toplevel=false)
40
+ #puts "resolveReferences nameParts " + nameParts.inspect + " namespace #{namespace}"
41
+ firstPart, *restParts = nameParts
42
+ if namespace
43
+ children = elementChildren(namespace)
44
+ #puts children.inspect
45
+ #puts "looking for a element named #{firstPart}"
46
+ elements = children.select{|e| e.respond_to?(:name) && e.name == firstPart}
47
+ #puts elements.inspect
48
+ #puts elementParents(namespace).inspect
49
+ if elements.empty? && elementParents(namespace).size > 0 && toplevel
50
+ #puts "Trying parent"
51
+ raise ResolverException.new("Element #{namespace} has multiple parents") if elementParents(namespace).size > 1
52
+ elements << resolveReference(env, elementParents(namespace).first, nameParts, targetClass, true)
53
+ else
54
+ where = "within children of #{namespace}"
55
+ where += " named #{namespace.name}" if namespace.respond_to?(:name)
56
+ end
57
+ elsif env
58
+ elements = env.find(:class => targetClass, :name => firstPart)
59
+ where = "in environment"
60
+ else
61
+ raise ResolverException.new("Neither namespace nor environment specified")
62
+ end
63
+ raise ResolverException.new("Can not find element named #{firstPart} #{where}") if elements.size == 0
64
+ raise ResolverException.new("Multiple elements named #{firstPart} found #{where}") if elements.size > 1
65
+ if restParts.size > 0
66
+ resolveReference(env, elements.first, restParts, targetClass)
67
+ else
68
+ elements.first
69
+ end
70
+ end
71
+
72
+ def elementChildren(element)
73
+ @elementChildren ||= {}
74
+ return @elementChildren[element] if @elementChildren[element]
75
+ children = element.class.ecore.eAllReferences.select{|r| r.containment}.collect do |r|
76
+ element.getGeneric(r.name)
77
+ end.flatten.compact
78
+ @elementChildren[element] = children
79
+ end
80
+
81
+ def elementParents(element)
82
+ @elementParents ||= {}
83
+ return @elementParents[element] if @elementParents[element]
84
+ parents = element.class.ecore.eAllReferences.select{|r| r.eOpposite && r.eOpposite.containment}.collect do |r|
85
+ element.getGeneric(r.name)
86
+ end.flatten.compact
87
+ @elementParents[element] = parents
88
+ end
89
+ end
90
+
91
+ # this module takes up helper methods to avoid littering the package modules
92
+ module Helper
93
+ class << self
94
+ def processArguments(args)
95
+ unless (args.size == 2 && args.first.is_a?(String) && args.last.is_a?(Hash)) ||
96
+ (args.size == 1 && (args.first.is_a?(String) || args.first.is_a?(Hash)))
97
+ raise "Provide a Hash to set feature values, " +
98
+ "optionally the first argument may be a String specifying " +
99
+ "the value of the \"name\" attribute."
100
+ end
101
+ if args.last.is_a?(Hash)
102
+ argHash = args.last
103
+ else
104
+ argHash = {}
105
+ end
106
+ argHash[:name] ||= args.first if args.first.is_a?(String)
107
+ argHash
108
+ end
109
+
110
+ def processArgHash(argHash, eClass)
111
+ resolverJobs = []
112
+ asRole = nil
113
+ argHash.each_pair do |k,v|
114
+ if k == :as
115
+ asRole = v
116
+ argHash.delete(k)
117
+ elsif v.is_a?(String)
118
+ ref = eClass.eAllReferences.find{|r| r.name == k.to_s}
119
+ if ref
120
+ argHash.delete(k)
121
+ resolverJobs << ReferenceResolver::ResolverJob.new(nil, ref, nil, v)
122
+ end
123
+ end
124
+ end
125
+ [ resolverJobs, asRole ]
126
+ end
127
+
128
+ def associateWithContextElement(element, contextElement, asRole)
129
+ return unless contextElement
130
+ contextClass = contextElement.class.ecore
131
+ if asRole
132
+ asRoleRef = contextClass.eAllReferences.find{|r| r.name == asRole.to_s}
133
+ raise "Context class #{contextClass.name} has no reference named #{asRole}" unless asRoleRef
134
+ ref = asRoleRef
135
+ else
136
+ possibleContainmentRefs = contextClass.eAllReferences.select { |r| r.containment &&
137
+ (element.class.ecore.eAllSuperTypes << element.class.ecore).include?(r.eType) }
138
+ if possibleContainmentRefs.size == 1
139
+ ref = possibleContainmentRefs.first
140
+ elsif possibleContainmentRefs.size == 0
141
+ raise "Context class #{contextClass.name} can not contain a #{element.class.ecore.name}"
142
+ else
143
+ raise "Context class #{contextClass.name} has several containment references to a #{element.class.ecore.name}." +
144
+ " Clearify using \":as => <role>\""
145
+ end
146
+ end
147
+ if ref.many
148
+ contextElement.addGeneric(ref.name, element)
149
+ else
150
+ contextElement.setGeneric(ref.name, element)
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ end
157
+
158
+ module MetamodelBuilder
159
+
160
+ module ModuleExtension
161
+
162
+ def method_missing(m, *args, &block)
163
+ return super unless self.ecore.is_a?(RGen::ECore::EPackage)
164
+ className = m.to_s[0..0].upcase + m.to_s[1..-1]
165
+ eClass = self.ecore.eClasses.find{|c| c.name == className}
166
+ return super unless eClass
167
+ argHash = ModelBuilder::Helper.processArguments(args)
168
+ resolverJobs, asRole = ModelBuilder::Helper.processArgHash(argHash, eClass)
169
+ element = eClass.instanceClass.new(argHash)
170
+ if @builderContext
171
+ ModelBuilder::Helper.associateWithContextElement(element, @builderContext.contextElement, asRole)
172
+ resolver = @builderContext.resolver
173
+ else
174
+ resolver = ModelBuilder::ReferenceResolver.new
175
+ end
176
+ resolverJobs.each do |job|
177
+ job.receiver = element
178
+ job.namespace = @builderContext && @builderContext.contextElement
179
+ resolver.addJob(job)
180
+ end
181
+ # process block
182
+ if block
183
+ if @builderContext
184
+ @builderContext, oldContext = @builderContext.dup, @builderContext
185
+ else
186
+ @builderContext = ModelBuilder::BuilderContext.new
187
+ @builderContext.resolver = resolver
188
+ oldContext = nil
189
+ end
190
+ @builderContext.contextElement = element
191
+ instance_eval(&block)
192
+ @builderContext = oldContext
193
+ if oldContext.nil?
194
+ # we are back on toplevel
195
+ resolver.resolve
196
+ end
197
+ end
198
+ element
199
+ end
200
+
201
+ end
202
+
203
+ end
204
+
205
+ end