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 +8 -0
- data/Rakefile +2 -2
- data/lib/rgen/instantiator/json_instantiator.rb +38 -5
- data/lib/rgen/model_builder/model_serializer.rb +32 -8
- data/lib/rgen/serializer/xmi11_serializer.rb +11 -12
- data/lib/rgen/serializer/xmi20_serializer.rb +12 -13
- data/lib/rgen/serializer/xml_serializer.rb +6 -2
- data/test/json_test.rb +57 -0
- data/test/metamodel_roundtrip_test/using_builtin_types.ecore +8 -8
- data/test/model_builder/serializer_test.rb +51 -21
- data/test/model_builder_test.rb +2 -0
- metadata +3 -3
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.
|
7
|
-
s.date = %
|
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
|
-
#
|
19
|
-
#
|
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
|
-
|
31
|
-
|
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]
|
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
|
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
|
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.
|
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
|
-
|
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'
|
24
|
-
attrs['xmlns:'+@namespaceShortcut
|
25
|
-
attrs['timestamp'
|
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 =
|
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
|
81
|
-
result =
|
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
|
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.
|
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
|
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 =
|
14
|
-
attrs['xmi:version'
|
15
|
-
attrs['xmlns:xmi'
|
16
|
-
attrs['xmlns:xsi'
|
17
|
-
attrs['xmlns: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 =
|
27
|
-
attrs['xsi:type'
|
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
|
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
|
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.
|
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
|
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
|
-
|
24
|
-
|
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"
|
2
|
-
<eClassifiers name="C1" xsi:type="ecore:EClass">
|
3
|
-
<eStructuralFeatures
|
4
|
-
<eStructuralFeatures
|
5
|
-
<eStructuralFeatures
|
6
|
-
<eStructuralFeatures
|
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
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
51
|
-
eval(f.read, b)
|
61
|
+
class C < B
|
52
62
|
end
|
53
|
-
|
63
|
+
A.contains_many 'role1', B, 'back1'
|
64
|
+
A.contains_many 'role2', B, 'back2'
|
54
65
|
end
|
55
|
-
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
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
|
data/test/model_builder_test.rb
CHANGED
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 5
|
8
|
-
-
|
9
|
-
version: 0.5.
|
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-
|
17
|
+
date: 2010-11-07 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|