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 +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
|
|