rgen 0.5.3 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG CHANGED
@@ -115,3 +115,11 @@
115
115
  * Fixed string escaping in JSON instantiator and serializer
116
116
  * Fixed order of eClassifiers and eSubpackages within an EPackage created by reflection on a RGen module
117
117
 
118
+ =0.5.4
119
+
120
+ * Fixed undeterministic order of child elements in ModelSerializer
121
+ * Fixed undeterministic order of attributes in XMI serializers
122
+ * Fixed ModelSerializer to always serialize the to-one part of bidirectional 1:N references
123
+ * Fixed ModelSerializer to add :as => in case of ambiguous child roles
124
+ * Made JsonInstantiator search subpackages for unqualified class names
125
+
data/Rakefile CHANGED
@@ -3,8 +3,8 @@ require 'rake/rdoctask'
3
3
 
4
4
  RGenGemSpec = Gem::Specification.new do |s|
5
5
  s.name = %q{rgen}
6
- s.version = "0.5.3"
7
- s.date = %q{2010-08-13}
6
+ s.version = "0.5.4"
7
+ s.date = Time.now.strftime("%Y-%m-%d")
8
8
  s.summary = %q{Ruby Modelling and Generator Framework}
9
9
  s.email = %q{martin dot thiede at gmx de}
10
10
  s.homepage = %q{http://ruby-gen.org}
@@ -5,19 +5,43 @@ module RGen
5
5
 
6
6
  module Instantiator
7
7
 
8
+ # JsonInstantiator is used to create RGen models from JSON.
9
+ #
10
+ # Each JSON object needs to have an attribute "_class" which is used to find
11
+ # the metamodel class to instantiate. The value of "_class" should be the
12
+ # the relative qualified class name within the root package as a string.
13
+ #
14
+ # If the option "short_class_names" is set to true, unqualified class names can be used.
15
+ # In this case, metamodel classes are searched in the metamodel root package first.
16
+ # If this search is not successful, all subpackages will be searched for the class name.
17
+ #
8
18
  class JsonInstantiator
9
19
 
20
+ # Model elements will be created in evironment +env+,
21
+ # classes are looked for in metamodel package module +mm+,
22
+ # +options+ include:
23
+ # short_class_names: if true subpackages will be searched for unqualifed class names (default: true)
24
+ # The options are also passed to the underlying QualifiedNameResolver.
25
+ #
10
26
  def initialize(env, mm, options={})
11
27
  @env = env
12
28
  @mm = mm
13
29
  @options = options
30
+ @short_class_names = !@options.has_key?(:short_class_names) || @options[:short_class_names]
14
31
  @unresolvedReferences = []
32
+ @classes = {}
33
+ @classes_flat = {}
34
+ mm.ecore.eAllClasses.each do |c|
35
+ @classes[c.instanceClass.name.sub(mm.name+"::","")] = c
36
+ @classes_flat[c.name] = c
37
+ end
15
38
  @parser = JsonParser.new(self)
16
39
  end
17
40
 
18
- # creates the elements described by the json string +str+
19
- # returns an array of ReferenceResolver::UnresolvedReference
41
+ # Creates the elements described by the json string +str+.
42
+ # Returns an array of ReferenceResolver::UnresolvedReference
20
43
  # describing the references which could not be resolved
44
+ #
21
45
  def instantiate(str)
22
46
  root = @parser.parse(str)
23
47
  resolver = QualifiedNameResolver.new(root, @options)
@@ -27,8 +51,13 @@ class JsonInstantiator
27
51
  def createObject(hash)
28
52
  className = hash["_class"]
29
53
  raise "no class information" unless className
30
- clazz = @mm.const_get(className)
31
- raise "class not found: #{className}" unless clazz
54
+ if @classes[className]
55
+ clazz = @classes[className].instanceClass
56
+ elsif @short_class_names && @classes_flat[className]
57
+ clazz = @classes_flat[className].instanceClass
58
+ else
59
+ raise "class not found: #{className}"
60
+ end
32
61
  hash.delete("_class")
33
62
  urefs = []
34
63
  hash.keys.each do |k|
@@ -68,7 +97,11 @@ class JsonInstantiator
68
97
  def eFeature(name, clazz)
69
98
  @eFeature ||= {}
70
99
  @eFeature[clazz] ||= {}
71
- @eFeature[clazz][name] ||= clazz.ecore.eAllStructuralFeatures.find{|f| f.name == name}
100
+ unless @eFeature[clazz][name]
101
+ feature = clazz.ecore.eAllStructuralFeatures.find{|f| f.name == name}
102
+ raise "feature '#{name}' not found in class '#{clazz}'" unless feature
103
+ end
104
+ @eFeature[clazz][name] ||= feature
72
105
  end
73
106
 
74
107
  end
@@ -31,7 +31,7 @@ class ModelSerializer
31
31
  cmd = className[0..0].downcase+className[1..-1]
32
32
  args = ["\"#{@internalElementName[element]}\""]
33
33
  namePath = namePath + [@internalElementName[element]]
34
- childs = {}
34
+ childs = []
35
35
  eAllStructuralFeatures(element).each do |f|
36
36
  next if f.derived
37
37
  if f.is_a?(RGen::ECore::EAttribute)
@@ -50,11 +50,11 @@ class ModelSerializer
50
50
  if cs.is_a?(Array)
51
51
  cs.compact!
52
52
  rcs = cs.select{|c| serializeChild?(c, namePath)}
53
- childs[f] = rcs unless rcs.empty?
53
+ childs << [f, rcs] unless rcs.empty?
54
54
  refString = serializeReference(element, f, cs-rcs)
55
55
  else
56
56
  if cs && serializeChild?(cs, namePath)
57
- childs[f] = [cs]
57
+ childs << [f, [cs]]
58
58
  else
59
59
  refString = serializeReference(element, f, cs)
60
60
  end
@@ -62,12 +62,15 @@ class ModelSerializer
62
62
  args << ":#{f.name} => #{refString}" if refString
63
63
  end
64
64
  end
65
+
66
+ args << ":as => :#{viaRef.name}" if viaRef && containmentRefs(viaRef.eContainingClass, element.class.ecore).size > 1
65
67
  cmd = elementPackage(element)+"."+cmd if elementPackage(element).size > 0
66
68
  @writable.write " " * indent + cmd + " " + args.join(", ")
67
69
  if childs.size > 0
68
70
  @writable.write " do\n"
69
71
  oldPackage, @currentPackage = @currentPackage, element.class.ecore.ePackage
70
- childs.each_pair do |f,cs|
72
+ childs.each do |pair|
73
+ f, cs = pair
71
74
  cs.each {|c| serializeElement(c, f, namePath, indent+1) }
72
75
  end
73
76
  @currentPackage = oldPackage
@@ -96,21 +99,29 @@ class ModelSerializer
96
99
  def serializeReference(element, ref, value)
97
100
  if value.is_a?(Array)
98
101
  value = value.compact
99
- value = value.select{|v| compareWithOppositeReference(element, v) > 0} if ref.eOpposite
102
+ value = value.select{|v| compareWithOppositeReference(ref, element, v) > 0} if ref.eOpposite
100
103
  qualNames = value.collect do |v|
101
104
  relativeQualifiedElementName(v, element).join(".")
102
105
  end
103
106
  !qualNames.empty? && ("[" + qualNames.collect { |v| "\"#{v}\"" }.join(", ") + "]")
104
- elsif value && (!ref.eOpposite || compareWithOppositeReference(element, value) > 0)
107
+ elsif value && (!ref.eOpposite || compareWithOppositeReference(ref, element, value) > 0)
105
108
  qualName = relativeQualifiedElementName(value, element).join(".")
106
109
  ("\"#{qualName}\"")
107
110
  end
108
111
  end
109
112
 
110
- def compareWithOppositeReference(element, target)
113
+ # descide which part of a bidirectional reference get serialized
114
+ def compareWithOppositeReference(ref, element, target)
115
+ result = 0
116
+ # first try to make the reference from the many side to the one side
117
+ result = -1 if ref.many && !ref.eOpposite.many
118
+ result = 1 if !ref.many && ref.eOpposite.many
119
+ return result if result != 0
120
+ # for 1:1 or many:many perfer, shorter references
111
121
  result = relativeQualifiedElementName(element, target).size <=>
112
122
  relativeQualifiedElementName(target, element).size
113
123
  return result if result != 0
124
+ # there just needs to be a descision, use class name or object_id
114
125
  result = element.class.name <=> target.class.name
115
126
  return result if result != 0
116
127
  element.object_id <=> target.object_id
@@ -194,8 +205,21 @@ class ModelSerializer
194
205
  @eAllStructuralFeatures[element.class] ||= element.class.ecore.eAllStructuralFeatures
195
206
  end
196
207
 
208
+ def eAllReferences(eClass)
209
+ @eAllReferences ||= {}
210
+ @eAllReferences[eClass] ||= eClass.eAllReferences
211
+ end
212
+
213
+ def containmentRefs(contextClass, eClass)
214
+ @containmentRefs ||= {}
215
+ @containmentRefs[[contextClass, eClass]] ||=
216
+ eAllReferences(contextClass).select do |r|
217
+ r.containment && (eClass.eAllSuperTypes << eClass).include?(r.eType)
218
+ end
219
+ end
220
+
197
221
  end
198
222
 
199
223
  end
200
224
 
201
- end
225
+ end
@@ -19,10 +19,10 @@ class XMI11Serializer < XMLSerializer
19
19
  end
20
20
 
21
21
  def serialize(rootElement, headerInfo=nil)
22
- attrs = {}
23
- attrs['xmi.version'] = "1.1"
24
- attrs['xmlns:'+@namespaceShortcut] = @namespaceUrl if @namespaceUrl
25
- attrs['timestamp'] = Time.now.to_s
22
+ attrs = []
23
+ attrs << ['xmi.version', "1.1"]
24
+ attrs << ['xmlns:'+@namespaceShortcut, @namespaceUrl] if @namespaceUrl
25
+ attrs << ['timestamp', Time.now.to_s]
26
26
  startTag("XMI", attrs)
27
27
  if headerInfo
28
28
  startTag("XMI.header")
@@ -56,7 +56,7 @@ class XMI11Serializer < XMLSerializer
56
56
 
57
57
  def writeElement(element)
58
58
  tag = @namespacePrefix + element.class.ecore.name
59
- attrs = attributeHash(element)
59
+ attrs = attributeValues(element)
60
60
  startTag(tag, attrs)
61
61
  containmentReferences(element).each do |r|
62
62
  roletag = @namespacePrefix + r.eContainingClass.name + "." + r.name
@@ -77,22 +77,21 @@ class XMI11Serializer < XMLSerializer
77
77
  endTag(tag)
78
78
  end
79
79
 
80
- def attributeHash(element)
81
- result = {"xmi.id" => xmiId(element)}
80
+ def attributeValues(element)
81
+ result = [["xmi.id", xmiId(element)]]
82
82
  eAllAttributes(element).select{|a| !a.derived}.each do |a|
83
83
  val = element.getGeneric(a.name)
84
- result[a.name] = val unless val.nil? || val == ""
84
+ result << [a.name, val] unless val.nil? || val == ""
85
85
  end
86
86
  eAllReferences(element).each do |r|
87
87
  next if r.derived
88
88
  next if r.containment
89
89
  next if r.eOpposite && r.eOpposite.containment && xmiLevel(element).nil?
90
90
  next if r.eOpposite && r.many && !r.eOpposite.many
91
- targetElements = element.getGeneric(r.name)
92
- targetElements = [targetElements] unless targetElements.is_a?(Array)
91
+ targetElements = element.getGenericAsArray(r.name)
93
92
  targetElements.compact!
94
93
  val = targetElements.collect{|te| xmiId(te)}.compact.join(' ')
95
- result[r.name] = val unless val == ""
94
+ result << [r.name, val] unless val == ""
96
95
  end
97
96
  result
98
97
  end
@@ -114,4 +113,4 @@ end
114
113
 
115
114
  end
116
115
 
117
- end
116
+ end
@@ -10,11 +10,11 @@ class XMI20Serializer < XMLSerializer
10
10
  @referenceStrings = {}
11
11
  buildReferenceStrings(rootElement, "#/")
12
12
  addBuiltinReferenceStrings
13
- attrs = attributeHash(rootElement)
14
- attrs['xmi:version'] = "2.0"
15
- attrs['xmlns:xmi'] = "http://www.omg.org/XMI"
16
- attrs['xmlns:xsi'] = "http://www.w3.org/2001/XMLSchema-instance"
17
- attrs['xmlns:ecore'] = "http://www.eclipse.org/emf/2002/Ecore"
13
+ attrs = attributeValues(rootElement)
14
+ attrs << ['xmi:version', "2.0"]
15
+ attrs << ['xmlns:xmi', "http://www.omg.org/XMI"]
16
+ attrs << ['xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"]
17
+ attrs << ['xmlns:ecore', "http://www.eclipse.org/emf/2002/Ecore" ]
18
18
  tag = "ecore:"+rootElement.class.ecore.name
19
19
  startTag(tag, attrs)
20
20
  writeComposites(rootElement)
@@ -23,8 +23,8 @@ class XMI20Serializer < XMLSerializer
23
23
 
24
24
  def writeComposites(element)
25
25
  eachReferencedElement(element, containmentReferences(element)) do |r,te|
26
- attrs = attributeHash(te)
27
- attrs['xsi:type'] = "ecore:"+te.class.ecore.name
26
+ attrs = attributeValues(te)
27
+ attrs << ['xsi:type', "ecore:"+te.class.ecore.name]
28
28
  tag = r.name
29
29
  startTag(tag, attrs)
30
30
  writeComposites(te)
@@ -32,17 +32,16 @@ class XMI20Serializer < XMLSerializer
32
32
  end
33
33
  end
34
34
 
35
- def attributeHash(element)
36
- result = {}
35
+ def attributeValues(element)
36
+ result = []
37
37
  eAllAttributes(element).select{|a| !a.derived}.each do |a|
38
38
  val = element.getGeneric(a.name)
39
- result[a.name] = val unless val.nil? || val == ""
39
+ result << [a.name, val] unless val.nil? || val == ""
40
40
  end
41
41
  eAllReferences(element).select{|r| !r.containment && !(r.eOpposite && r.eOpposite.containment) && !r.derived}.each do |r|
42
- targetElements = element.getGeneric(r.name)
43
- targetElements = [targetElements] unless targetElements.is_a?(Array)
42
+ targetElements = element.getGenericAsArray(r.name)
44
43
  val = targetElements.collect{|te| @referenceStrings[te]}.compact.join(' ')
45
- result[r.name] = val unless val.nil? || val == ""
44
+ result << [r.name, val] unless val.nil? || val == ""
46
45
  end
47
46
  result
48
47
  end
@@ -20,8 +20,12 @@ class XMLSerializer
20
20
  def startTag(tag, attributes={})
21
21
  @textContent = false
22
22
  handleLastStartTag(false, true)
23
- @lastStartTag = " "*@indent*INDENT_SPACE +
24
- "<#{tag} "+attributes.keys.collect{|k| "#{k}=\"#{attributes[k]}\""}.join(" ")
23
+ if attributes.is_a?(Hash)
24
+ attrString = attributes.keys.collect{|k| "#{k}=\"#{attributes[k]}\""}.join(" ")
25
+ else
26
+ attrString = attributes.collect{|pair| "#{pair[0]}=\"#{pair[1]}\""}.join(" ")
27
+ end
28
+ @lastStartTag = " "*@indent*INDENT_SPACE + "<#{tag} "+attrString
25
29
  @indent += 1
26
30
  end
27
31
 
data/test/json_test.rb CHANGED
@@ -18,6 +18,27 @@ class JsonTest < Test::Unit::TestCase
18
18
  end
19
19
  end
20
20
 
21
+ module TestMMData
22
+ extend RGen::MetamodelBuilder::ModuleExtension
23
+ # class "Data" exists in the standard Ruby namespace
24
+ class Data < RGen::MetamodelBuilder::MMBase
25
+ has_attr 'notTheBuiltin', String
26
+ end
27
+ end
28
+
29
+ module TestMMSubpackage
30
+ extend RGen::MetamodelBuilder::ModuleExtension
31
+ module SubPackage
32
+ extend RGen::MetamodelBuilder::ModuleExtension
33
+ class Data < RGen::MetamodelBuilder::MMBase
34
+ has_attr 'notTheBuiltin', String
35
+ end
36
+ class Data2 < RGen::MetamodelBuilder::MMBase
37
+ has_attr 'data2', String
38
+ end
39
+ end
40
+ end
41
+
21
42
  class StringWriter < String
22
43
  alias write concat
23
44
  end
@@ -95,5 +116,41 @@ class JsonTest < Test::Unit::TestCase
95
116
  inst.instantiate(%q({ "_class": "TestNode", "float": 1.23 }))
96
117
  assert_equal 1.23, env.elements.first.float
97
118
  end
119
+
120
+ def test_json_instantiator_conflict_builtin
121
+ env = RGen::Environment.new
122
+ inst = RGen::Instantiator::JsonInstantiator.new(env, TestMMData)
123
+ inst.instantiate(%q({ "_class": "Data", "notTheBuiltin": "for sure" }))
124
+ assert_equal "for sure", env.elements.first.notTheBuiltin
125
+ end
126
+
127
+ def test_json_serializer_subpacakge
128
+ testModel = TestMMSubpackage::SubPackage::Data2.new(:data2 => "xxx")
129
+ output = StringWriter.new
130
+ ser = RGen::Serializer::JsonSerializer.new(output)
131
+ assert_equal %q({ "_class": "Data2", "data2": "xxx" }), ser.serialize(testModel)
132
+ end
133
+
134
+ def test_json_instantiator_builtin_in_subpackage
135
+ env = RGen::Environment.new
136
+ inst = RGen::Instantiator::JsonInstantiator.new(env, TestMMSubpackage)
137
+ inst.instantiate(%q({ "_class": "Data", "notTheBuiltin": "for sure" }))
138
+ assert_equal "for sure", env.elements.first.notTheBuiltin
139
+ end
140
+
141
+ def test_json_instantiator_subpackage
142
+ env = RGen::Environment.new
143
+ inst = RGen::Instantiator::JsonInstantiator.new(env, TestMMSubpackage)
144
+ inst.instantiate(%q({ "_class": "Data2", "data2": "something" }))
145
+ assert_equal "something", env.elements.first.data2
146
+ end
147
+
148
+ def test_json_instantiator_subpackage_no_shortname_opt
149
+ env = RGen::Environment.new
150
+ inst = RGen::Instantiator::JsonInstantiator.new(env, TestMMSubpackage, :short_class_names => false)
151
+ assert_raise RuntimeError do
152
+ inst.instantiate(%q({ "_class": "Data2", "data2": "something" }))
153
+ end
154
+ end
98
155
  end
99
156
 
@@ -1,8 +1,8 @@
1
- <ecore:EPackage xmi:version="2.0" name="P1" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore">
2
- <eClassifiers name="C1" xsi:type="ecore:EClass">
3
- <eStructuralFeatures name="a1" derived="false" transient="false" changeable="true" unsettable="false" iD="false" xsi:type="ecore:EAttribute" upperBound="1" ordered="true" volatile="false" lowerBound="0" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" unique="true"/>
4
- <eStructuralFeatures name="a2" derived="false" transient="false" changeable="true" unsettable="false" iD="false" xsi:type="ecore:EAttribute" upperBound="1" ordered="true" volatile="false" lowerBound="0" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt" unique="true"/>
5
- <eStructuralFeatures name="a3" derived="false" transient="false" changeable="true" unsettable="false" iD="false" xsi:type="ecore:EAttribute" upperBound="1" ordered="true" volatile="false" lowerBound="0" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloat" unique="true"/>
6
- <eStructuralFeatures name="a4" derived="false" transient="false" changeable="true" unsettable="false" iD="false" xsi:type="ecore:EAttribute" upperBound="1" ordered="true" volatile="false" lowerBound="0" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean" unique="true"/>
7
- </eClassifiers>
8
- </ecore:EPackage>
1
+ <ecore:EPackage name="P1" xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore">
2
+ <eClassifiers name="C1" xsi:type="ecore:EClass">
3
+ <eStructuralFeatures iD="false" changeable="true" derived="false" transient="false" unsettable="false" volatile="false" lowerBound="0" ordered="true" unique="true" upperBound="1" name="a1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" xsi:type="ecore:EAttribute"/>
4
+ <eStructuralFeatures iD="false" changeable="true" derived="false" transient="false" unsettable="false" volatile="false" lowerBound="0" ordered="true" unique="true" upperBound="1" name="a2" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt" xsi:type="ecore:EAttribute"/>
5
+ <eStructuralFeatures iD="false" changeable="true" derived="false" transient="false" unsettable="false" volatile="false" lowerBound="0" ordered="true" unique="true" upperBound="1" name="a3" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloat" xsi:type="ecore:EAttribute"/>
6
+ <eStructuralFeatures iD="false" changeable="true" derived="false" transient="false" unsettable="false" volatile="false" lowerBound="0" ordered="true" unique="true" upperBound="1" name="a4" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean" xsi:type="ecore:EAttribute"/>
7
+ </eClassifiers>
8
+ </ecore:EPackage>
@@ -36,29 +36,59 @@ class ModelSerializerTest < Test::Unit::TestCase
36
36
  end
37
37
  end
38
38
 
39
- def xxx_test_ecore_original
40
- env = RGen::Environment.new
41
- File.open(File.dirname(__FILE__)+"/Ecore.ecore") { |f|
42
- ECoreXMLInstantiator.new(env,ECoreXMLInstantiator::ERROR).instantiate(f.read)
43
- }
44
- serializeEcore(env, "ecore", File.dirname(__FILE__)+"/ecore_original.rb")
45
- b = nil
46
- env2 = RGen::Environment.new
47
- RGen::ModelBuilder.build(RGen::ECore, env2) do
48
- b = binding
39
+ def test_roundtrip
40
+ model = %{\
41
+ statemachine "Airconditioner" do
42
+ state "Off", :kind => :START
43
+ compositeState "On" do
44
+ state "Heating"
45
+ state "Cooling"
46
+ state "Dumm"
47
+ end
48
+ transition "_Transition1", :sourceState => "On.Cooling", :targetState => "On.Heating"
49
+ transition "_Transition2", :sourceState => "On.Heating", :targetState => "On.Cooling"
50
+ end
51
+ }
52
+ check_roundtrip(StatemachineMetamodel, model)
53
+ end
54
+
55
+ module AmbiguousRoleMM
56
+ extend RGen::MetamodelBuilder::ModuleExtension
57
+ class A < RGen::MetamodelBuilder::MMBase
58
+ end
59
+ class B < RGen::MetamodelBuilder::MMBase
49
60
  end
50
- File.open(File.dirname(__FILE__)+"/ecore_original.rb") do |f|
51
- eval(f.read, b)
61
+ class C < B
52
62
  end
53
- serializeEcore(env2, "ecore", File.dirname(__FILE__)+"/ecore_original_regenerated.rb")
63
+ A.contains_many 'role1', B, 'back1'
64
+ A.contains_many 'role2', B, 'back2'
54
65
  end
55
-
56
- def serializeEcore(env, rootPackageName, fileName)
57
- env.find(:class => RGen::ECore::EClass).each {|c| c.eOperations = []}
58
- env.find(:class => RGen::ECore::EModelElement).each {|e| e.eAnnotations = []}
59
- File.open(fileName,"w") do |f|
60
- serializer = RGen::ModelBuilder::ModelSerializer.new(f, RGen::ECore.ecore)
61
- serializer.serialize(env.find(:class => RGen::ECore::EPackage, :name => rootPackageName))
66
+
67
+ def test_roundtrip_ambiguous_role
68
+ model = %{\
69
+ a "_A1" do
70
+ b "_B1", :as => :role1
71
+ b "_B2", :as => :role2
72
+ c "_C1", :as => :role2
73
+ end
74
+ }
75
+ check_roundtrip(AmbiguousRoleMM, model)
76
+ end
77
+
78
+ private
79
+
80
+ def build_model(mm, model)
81
+ RGen::ModelBuilder.build(mm) do
82
+ eval(model)
62
83
  end
63
84
  end
64
- end
85
+
86
+ def check_roundtrip(mm, model)
87
+ sm = build_model(mm, model)
88
+ f = StringIO.new
89
+ serializer = RGen::ModelBuilder::ModelSerializer.new(f, mm.ecore)
90
+ serializer.serialize(sm)
91
+ assert_equal model, f.string
92
+ end
93
+
94
+ end
@@ -1,3 +1,5 @@
1
+ $:.unshift File.dirname(__FILE__) + "/../lib"
2
+
1
3
  require 'model_builder/builder_test'
2
4
  require 'model_builder/serializer_test'
3
5
  require 'model_builder/builder_context_test'
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 5
8
- - 3
9
- version: 0.5.3
8
+ - 4
9
+ version: 0.5.4
10
10
  platform: ruby
11
11
  authors:
12
12
  - Martin Thiede
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-08-13 00:00:00 +02:00
17
+ date: 2010-11-07 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies: []
20
20