rgen 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
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.1"
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
- 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)
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
- end
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
- # prerequisits:
7
- # * containment relations must be bidirectionsl
8
- # * local name stored in single attribute +@attribute_name+ for all classes
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
- (element.is_a?(RGen::MetamodelBuilder::MMProxy) && element.targetIdentifier) || qualified_name(element)
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
- localIdent = ((element.respond_to?(@attribute_name) && element.getGeneric(@attribute_name)) || "").strip
26
- parentRef = element.class.ecore.eAllReferences.select{|r| r.eOpposite && r.eOpposite.containment}.first
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 localIdent.size > 0
30
- parentIdent = qualified_name(parent)
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 : "") + localIdent
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
- 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
-
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
- assert_raise StandardError do
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
- assert_raise StandardError do
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
- assert_raise StandardError do
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
- assert_raise StandardError do
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
- assert_raise StandardError do
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
- assert_raise StandardError do
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
- assert_raise StandardError do
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
- assert_raise StandardError do
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
+
data/test/rgen_test.rb CHANGED
@@ -22,4 +22,5 @@ require 'metamodel_order_test'
22
22
  require 'metamodel_from_ecore_test'
23
23
  require 'util_test'
24
24
  require 'model_fragment_test'
25
+ require 'qualified_name_provider_test'
25
26