rgen 0.5.3 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
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