rgen 0.6.1 → 0.6.2
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 +5 -0
- data/Rakefile +1 -1
- data/lib/rgen/array_extensions.rb +35 -23
- data/lib/rgen/serializer/qualified_name_provider.rb +14 -12
- data/test/array_extensions_test.rb +50 -46
- data/test/metamodel_builder_test.rb +38 -19
- data/test/qualified_name_provider_test.rb +48 -0
- data/test/rgen_test.rb +1 -0
- data/test/testmodel/ea_testmodel_regenerated.xml +583 -583
- metadata +4 -3
data/CHANGELOG
CHANGED
@@ -161,3 +161,8 @@
|
|
161
161
|
* Fixed ModelFragment#elements not containing root elements
|
162
162
|
* Added optional output of invalidation reason to FileCacheMap#load_data
|
163
163
|
|
164
|
+
=0.6.2
|
165
|
+
|
166
|
+
* Made qualified name provider work with unidirectional containment references
|
167
|
+
* Fixed array_extension breaking the Hash[] method
|
168
|
+
|
data/Rakefile
CHANGED
@@ -3,7 +3,7 @@ require 'rdoc/task'
|
|
3
3
|
|
4
4
|
RGenGemSpec = Gem::Specification.new do |s|
|
5
5
|
s.name = %q{rgen}
|
6
|
-
s.version = "0.6.
|
6
|
+
s.version = "0.6.2"
|
7
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}
|
@@ -5,27 +5,39 @@ require 'rgen/metamodel_builder'
|
|
5
5
|
|
6
6
|
class Array
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
super unless size == 0 or compact.any?{|e| e.is_a? RGen::MetamodelBuilder::MMBase}
|
14
|
-
# use an array to build the result to achiev similar ordering
|
15
|
-
result = []
|
16
|
-
inResult = {}
|
17
|
-
compact.each do |e|
|
18
|
-
if e.is_a? RGen::MetamodelBuilder::MMBase
|
19
|
-
((o=e.send(m)).is_a?(Array) ? o : [o] ).each do |v|
|
20
|
-
next if inResult[v.object_id]
|
21
|
-
inResult[v.object_id] = true
|
22
|
-
result << v
|
23
|
-
end
|
24
|
-
else
|
25
|
-
raise StandardError.new("Trying to call a method on an array element not a RGen MMBase")
|
26
|
-
end
|
27
|
-
end
|
28
|
-
result.compact
|
29
|
-
end
|
8
|
+
def >>(method)
|
9
|
+
compact.inject([]) { |r,e| r | ( (o=e.send(method)).is_a?(Array) ? o : [o] ) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing(m, *args)
|
30
13
|
|
31
|
-
|
14
|
+
# This extensions has the side effect that it allows to call any method on any
|
15
|
+
# empty array with an empty array as the result. This behavior is required for
|
16
|
+
# navigating models.
|
17
|
+
#
|
18
|
+
# This is a problem for Hash[] called with an (empty) array of tupels.
|
19
|
+
# It will call to_hash expecting a Hash as the result. When it gets an array instead,
|
20
|
+
# it fails with an exception. Make sure it gets a NoMethodException as without this
|
21
|
+
# extension and it will catch that and return an empty hash as expected.
|
22
|
+
#
|
23
|
+
return super unless (size == 0 &&
|
24
|
+
m != :to_hash) ||
|
25
|
+
compact.any?{|e| e.is_a? RGen::MetamodelBuilder::MMBase}
|
26
|
+
# use an array to build the result to achiev similar ordering
|
27
|
+
result = []
|
28
|
+
inResult = {}
|
29
|
+
compact.each do |e|
|
30
|
+
if e.is_a? RGen::MetamodelBuilder::MMBase
|
31
|
+
((o=e.send(m)).is_a?(Array) ? o : [o] ).each do |v|
|
32
|
+
next if inResult[v.object_id]
|
33
|
+
inResult[v.object_id] = true
|
34
|
+
result << v
|
35
|
+
end
|
36
|
+
else
|
37
|
+
raise StandardError.new("Trying to call a method on an array element not a RGen MMBase")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
result.compact
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -2,10 +2,10 @@ module RGen
|
|
2
2
|
|
3
3
|
module Serializer
|
4
4
|
|
5
|
-
# simple identifier calculation based on qualified names
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
5
|
+
# simple identifier calculation based on qualified names.
|
6
|
+
# as a prerequisit, elements must have a local name stored in single attribute +attribute_name+.
|
7
|
+
# there may be classes without the name attribute though and there may be elements without a
|
8
|
+
# local name. in both cases the element will have the same qualified name as its container.
|
9
9
|
#
|
10
10
|
class QualifiedNameProvider
|
11
11
|
|
@@ -17,23 +17,25 @@ class QualifiedNameProvider
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def identifier(element)
|
20
|
-
|
20
|
+
if element.is_a?(RGen::MetamodelBuilder::MMProxy)
|
21
|
+
element.targetIdentifier
|
22
|
+
else
|
23
|
+
qualified_name(element)
|
24
|
+
end
|
21
25
|
end
|
22
26
|
|
23
27
|
def qualified_name(element)
|
24
28
|
return @qualified_name_cache[element] if @qualified_name_cache[element]
|
25
|
-
|
26
|
-
|
27
|
-
parent = parentRef && element.getGeneric(parentRef.name)
|
29
|
+
local_ident = ((element.respond_to?(@attribute_name) && element.getGeneric(@attribute_name)) || "").strip
|
30
|
+
parent = element.eContainer
|
28
31
|
if parent
|
29
|
-
if
|
30
|
-
|
31
|
-
result = parentIdent + @separator + localIdent
|
32
|
+
if local_ident.size > 0
|
33
|
+
result = qualified_name(parent) + @separator + local_ident
|
32
34
|
else
|
33
35
|
result = qualified_name(parent)
|
34
36
|
end
|
35
37
|
else
|
36
|
-
result = (@leading_separator ? @separator : "") +
|
38
|
+
result = (@leading_separator ? @separator : "") + local_ident
|
37
39
|
end
|
38
40
|
@qualified_name_cache[element] = result
|
39
41
|
end
|
@@ -5,50 +5,54 @@ require 'rgen/array_extensions'
|
|
5
5
|
|
6
6
|
class ArrayExtensionsTest < Test::Unit::TestCase
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
8
|
+
def test_element_methods
|
9
|
+
c = Struct.new("SomeClass",:name,:age)
|
10
|
+
a = []
|
11
|
+
a << c.new('MyName',33)
|
12
|
+
a << c.new('YourName',22)
|
13
|
+
assert_equal ["MyName", "YourName"], a >> :name
|
14
|
+
assert_raise NoMethodError do
|
15
|
+
a.name
|
16
|
+
end
|
17
|
+
assert_equal [33, 22], a>>:age
|
18
|
+
assert_raise NoMethodError do
|
19
|
+
a.age
|
20
|
+
end
|
21
|
+
# unfortunately, any method can be called on an empty array
|
22
|
+
assert_equal [], [].age
|
23
|
+
end
|
24
|
+
|
25
|
+
class MMBaseClass < RGen::MetamodelBuilder::MMBase
|
26
|
+
has_attr 'name'
|
27
|
+
has_attr 'age', Integer
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_with_mmbase
|
31
|
+
e1 = MMBaseClass.new
|
32
|
+
e1.name = "MyName"
|
33
|
+
e1.age = 33
|
34
|
+
e2 = MMBaseClass.new
|
35
|
+
e2.name = "YourName"
|
36
|
+
e2.age = 22
|
37
|
+
a = [e1, e2]
|
38
|
+
assert_equal ["MyName", "YourName"], a >> :name
|
39
|
+
assert_equal ["MyName", "YourName"], a.name
|
40
|
+
assert_equal [33, 22], a>>:age
|
41
|
+
assert_equal [33, 22], a.age
|
42
|
+
# put something into the array that is not an MMBase
|
43
|
+
a << "not a MMBase"
|
44
|
+
# the dot operator will tell that there is something not a MMBase
|
45
|
+
assert_raise StandardError do
|
46
|
+
a.age
|
47
|
+
end
|
48
|
+
# the >> operator will try to call the method anyway
|
49
|
+
assert_raise NoMethodError do
|
50
|
+
a >> :age
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_hash_square
|
55
|
+
assert_equal({}, Hash[[]])
|
56
|
+
end
|
57
|
+
|
54
58
|
end
|
@@ -167,9 +167,10 @@ class MetamodelBuilderTest < Test::Unit::TestCase
|
|
167
167
|
assert_equal "TestName", sc.name
|
168
168
|
sc.name = nil
|
169
169
|
assert_equal nil, sc.name
|
170
|
-
assert_raise StandardError do
|
170
|
+
err = assert_raise StandardError do
|
171
171
|
sc.name = 5
|
172
172
|
end
|
173
|
+
assert_match /In (\w+::)+SimpleClass : Can not use a Fixnum where a String is expected/, err.message
|
173
174
|
assert_equal "EString", mm::SimpleClass.ecore.eAttributes.find{|a| a.name=="name"}.eType.name
|
174
175
|
|
175
176
|
assert_equal "xtest", sc.stringWithDefault
|
@@ -195,12 +196,14 @@ class MetamodelBuilderTest < Test::Unit::TestCase
|
|
195
196
|
assert_equal false, sc.allowed
|
196
197
|
sc.allowed = nil
|
197
198
|
assert_equal nil, sc.allowed
|
198
|
-
assert_raise StandardError do
|
199
|
+
err = assert_raise StandardError do
|
199
200
|
sc.allowed = :someSymbol
|
200
201
|
end
|
201
|
-
|
202
|
+
assert_match /In (\w+::)+SimpleClass : Can not use a Symbol\(:someSymbol\) where a \[true,false\] is expected/, err.message
|
203
|
+
err = assert_raise StandardError do
|
202
204
|
sc.allowed = "a string"
|
203
205
|
end
|
206
|
+
assert_match /In (\w+::)+SimpleClass : Can not use a String where a \[true,false\] is expected/, err.message
|
204
207
|
assert_equal "EBoolean", mm::SimpleClass.ecore.eAttributes.find{|a| a.name=="allowed"}.eType.name
|
205
208
|
|
206
209
|
assert_respond_to sc, :kind
|
@@ -211,12 +214,14 @@ class MetamodelBuilderTest < Test::Unit::TestCase
|
|
211
214
|
assert_equal :extended, sc.kind
|
212
215
|
sc.kind = nil
|
213
216
|
assert_equal nil, sc.kind
|
214
|
-
assert_raise StandardError do
|
217
|
+
err = assert_raise StandardError do
|
215
218
|
sc.kind = :false
|
216
219
|
end
|
217
|
-
|
220
|
+
assert_match /In (\w+::)+SimpleClass : Can not use a Symbol\(:false\) where a \[:simple,:extended\] is expected/, err.message
|
221
|
+
err = assert_raise StandardError do
|
218
222
|
sc.kind = "a string"
|
219
223
|
end
|
224
|
+
assert_match /In (\w+::)+SimpleClass : Can not use a String where a \[:simple,:extended\] is expected/, err.message
|
220
225
|
|
221
226
|
enum = mm::SimpleClass.ecore.eAttributes.find{|a| a.name=="kind"}.eType
|
222
227
|
assert_equal ["extended", "simple"], enum.eLiterals.name.sort
|
@@ -229,9 +234,10 @@ class MetamodelBuilderTest < Test::Unit::TestCase
|
|
229
234
|
assert_respond_to o, :addLiterals
|
230
235
|
assert_respond_to o, :removeLiterals
|
231
236
|
|
232
|
-
assert_raise(StandardError) do
|
237
|
+
err = assert_raise(StandardError) do
|
233
238
|
o.addLiterals(1)
|
234
239
|
end
|
240
|
+
assert_match /In (\w+::)+ManyAttrClass : Can not use a Fixnum where a String is expected/, err.message
|
235
241
|
|
236
242
|
assert_equal [], o.literals
|
237
243
|
o.addLiterals("a")
|
@@ -263,9 +269,10 @@ class MetamodelBuilderTest < Test::Unit::TestCase
|
|
263
269
|
o.literals = ["a", "b", "c"]
|
264
270
|
assert_equal ["a", "b", "c"], o.literals
|
265
271
|
# can only take enumerables
|
266
|
-
assert_raise(StandardError) do
|
272
|
+
err = assert_raise(StandardError) do
|
267
273
|
o.literals = 1
|
268
274
|
end
|
275
|
+
assert_match /In (\w+::)+ManyAttrClass : Can not use a Fixnum where a Enumerable is expected/, err.message
|
269
276
|
|
270
277
|
o.bools = [true, false, true, false]
|
271
278
|
assert_equal [true, false, true, false], o.bools
|
@@ -309,9 +316,10 @@ class MetamodelBuilderTest < Test::Unit::TestCase
|
|
309
316
|
sc.classB = cb
|
310
317
|
assert_equal cb, sc.classB
|
311
318
|
|
312
|
-
assert_raise StandardError do
|
319
|
+
err = assert_raise StandardError do
|
313
320
|
sc.classB = ca
|
314
321
|
end
|
322
|
+
assert_match /In (\w+::)+HasOneTestClass : Can not use a (\w+::)+ClassA where a (\w+::)+ClassB is expected/, err.message
|
315
323
|
|
316
324
|
assert_equal [], mm::ClassA.ecore.eReferences
|
317
325
|
assert_equal [], mm::ClassB.ecore.eReferences
|
@@ -335,9 +343,10 @@ class MetamodelBuilderTest < Test::Unit::TestCase
|
|
335
343
|
assert_equal [ca1, ca2], o.classA
|
336
344
|
o.removeClassA(ca2)
|
337
345
|
assert_equal [ca1], o.classA
|
338
|
-
assert_raise StandardError do
|
346
|
+
err = assert_raise StandardError do
|
339
347
|
o.addClassA(mm::ClassB.new)
|
340
348
|
end
|
349
|
+
assert_match /In (\w+::)+HasManyTestClass : Can not use a (\w+::)+ClassB where a (\w+::)+ClassA is expected/, err.message
|
341
350
|
assert_equal [], mm::HasManyTestClass.ecore.eReferences.select{|r| r.many == false}
|
342
351
|
assert_equal ["classA"], mm::HasManyTestClass.ecore.eReferences.select{|r| r.many == true}.name
|
343
352
|
end
|
@@ -543,9 +552,10 @@ class MetamodelBuilderTest < Test::Unit::TestCase
|
|
543
552
|
assert ac.bClasses.include?(bc)
|
544
553
|
|
545
554
|
# put something else into the BClass
|
546
|
-
assert_raise StandardError do
|
555
|
+
err = assert_raise StandardError do
|
547
556
|
bc.addAClasses :notaaclass
|
548
557
|
end
|
558
|
+
assert_match /In (\w+::)+BClassMM : Can not use a Symbol\(:notaaclass\) where a (\w+::)+AClassMM is expected/, err.message
|
549
559
|
|
550
560
|
# remove the AClass from the BClass
|
551
561
|
bc.removeAClasses ac
|
@@ -558,9 +568,10 @@ class MetamodelBuilderTest < Test::Unit::TestCase
|
|
558
568
|
assert bc.aClasses.include?(ac)
|
559
569
|
|
560
570
|
# put something else into the AClass
|
561
|
-
assert_raise StandardError do
|
571
|
+
err = assert_raise StandardError do
|
562
572
|
ac.addBClasses :notabclass
|
563
573
|
end
|
574
|
+
assert_match /In (\w+::)+AClassMM : Can not use a Symbol\(:notabclass\) where a (\w+::)+BClassMM is expected/, err.message
|
564
575
|
|
565
576
|
# remove the BClass from the AClass
|
566
577
|
ac.removeBClasses bc
|
@@ -789,9 +800,10 @@ class MetamodelBuilderTest < Test::Unit::TestCase
|
|
789
800
|
end
|
790
801
|
|
791
802
|
def test_abstract
|
792
|
-
assert_raise StandardError do
|
803
|
+
err = assert_raise StandardError do
|
793
804
|
mm::AbstractClass.new
|
794
805
|
end
|
806
|
+
assert_match /Class (\w+::)+AbstractClass is abstract/, err.message
|
795
807
|
end
|
796
808
|
|
797
809
|
module BadDefaultValueLiteralContainer
|
@@ -835,27 +847,34 @@ class MetamodelBuilderTest < Test::Unit::TestCase
|
|
835
847
|
end
|
836
848
|
|
837
849
|
def test_bad_default_value_literal
|
838
|
-
assert_raise StandardError do
|
850
|
+
err = assert_raise StandardError do
|
839
851
|
BadDefaultValueLiteralContainer::Test1.call
|
840
852
|
end
|
841
|
-
|
853
|
+
assert_equal "Property integerWithDefault can not take value 1.1, expected an Integer", err.message
|
854
|
+
err = assert_raise StandardError do
|
842
855
|
BadDefaultValueLiteralContainer::Test2.call
|
843
856
|
end
|
844
|
-
|
857
|
+
assert_equal "Property integerWithDefault can not take value x, expected an Integer", err.message
|
858
|
+
err = assert_raise StandardError do
|
845
859
|
BadDefaultValueLiteralContainer::Test3.call
|
846
860
|
end
|
847
|
-
|
861
|
+
assert_equal "Property boolWithDefault can not take value 1, expected true or false", err.message
|
862
|
+
err = assert_raise StandardError do
|
848
863
|
BadDefaultValueLiteralContainer::Test4.call
|
849
864
|
end
|
850
|
-
|
865
|
+
assert_equal "Property floatWithDefault can not take value 1, expected a Float", err.message
|
866
|
+
err = assert_raise StandardError do
|
851
867
|
BadDefaultValueLiteralContainer::Test5.call
|
852
868
|
end
|
853
|
-
|
869
|
+
assert_equal "Property floatWithDefault can not take value true, expected a Float", err.message
|
870
|
+
err = assert_raise StandardError do
|
854
871
|
BadDefaultValueLiteralContainer::Test6.call
|
855
872
|
end
|
856
|
-
|
873
|
+
assert_equal "Property enumWithDefault can not take value xxx, expected one of :simple, :extended", err.message
|
874
|
+
err = assert_raise StandardError do
|
857
875
|
BadDefaultValueLiteralContainer::Test7.call
|
858
876
|
end
|
877
|
+
assert_equal "Property enumWithDefault can not take value 7, expected one of :simple, :extended", err.message
|
859
878
|
end
|
860
879
|
|
861
880
|
def test_isset_set_to_nil
|
@@ -0,0 +1,48 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),"..","lib")
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'rgen/metamodel_builder'
|
5
|
+
require 'rgen/serializer/qualified_name_provider'
|
6
|
+
|
7
|
+
class QualifiedNameProviderTest < Test::Unit::TestCase
|
8
|
+
|
9
|
+
class AbstractTestNode < RGen::MetamodelBuilder::MMBase
|
10
|
+
contains_many 'children', AbstractTestNode, "parent"
|
11
|
+
end
|
12
|
+
|
13
|
+
class NamedNode < AbstractTestNode
|
14
|
+
has_attr 'n', String
|
15
|
+
end
|
16
|
+
|
17
|
+
class UnnamedNode < AbstractTestNode
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_simple
|
21
|
+
root = NamedNode.new(:n => "root", :children => [
|
22
|
+
NamedNode.new(:n => "a", :children => [
|
23
|
+
NamedNode.new(:n => "a1")
|
24
|
+
]),
|
25
|
+
UnnamedNode.new(:children => [
|
26
|
+
NamedNode.new(:n => "b1")
|
27
|
+
])
|
28
|
+
])
|
29
|
+
|
30
|
+
qnp = RGen::Serializer::QualifiedNameProvider.new(:attribute_name => "n")
|
31
|
+
|
32
|
+
assert_equal "/root", qnp.identifier(root)
|
33
|
+
assert_equal "/root/a", qnp.identifier(root.children[0])
|
34
|
+
assert_equal "/root/a/a1", qnp.identifier(root.children[0].children[0])
|
35
|
+
assert_equal "/root", qnp.identifier(root.children[1])
|
36
|
+
assert_equal "/root/b1", qnp.identifier(root.children[1].children[0])
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_unnamed_root
|
40
|
+
root = UnnamedNode.new
|
41
|
+
|
42
|
+
qnp = RGen::Serializer::QualifiedNameProvider.new(:attribute_name => "n")
|
43
|
+
|
44
|
+
assert_equal "/", qnp.identifier(root)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|