rgen 0.2.0

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.
Files changed (54) hide show
  1. data/CHANGELOG +9 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +73 -0
  4. data/lib/ea/xmi_class_instantiator.rb +45 -0
  5. data/lib/ea/xmi_helper.rb +26 -0
  6. data/lib/ea/xmi_metamodel.rb +19 -0
  7. data/lib/ea/xmi_object_instantiator.rb +42 -0
  8. data/lib/ea/xmi_to_classmodel.rb +78 -0
  9. data/lib/ea/xmi_to_objectmodel.rb +89 -0
  10. data/lib/mmgen/metamodel_generator.rb +19 -0
  11. data/lib/mmgen/mm_ext/uml_classmodel_ext.rb +71 -0
  12. data/lib/mmgen/mmgen.rb +21 -0
  13. data/lib/mmgen/templates/uml_classmodel.tpl +63 -0
  14. data/lib/rgen/array_extensions.rb +23 -0
  15. data/lib/rgen/auto_class_creator.rb +56 -0
  16. data/lib/rgen/environment.rb +57 -0
  17. data/lib/rgen/metamodel_builder.rb +102 -0
  18. data/lib/rgen/metamodel_builder/build_helper.rb +29 -0
  19. data/lib/rgen/metamodel_builder/builder_extensions.rb +191 -0
  20. data/lib/rgen/metamodel_builder/builder_runtime.rb +67 -0
  21. data/lib/rgen/name_helper.rb +18 -0
  22. data/lib/rgen/template_language.rb +169 -0
  23. data/lib/rgen/template_language/directory_template_container.rb +51 -0
  24. data/lib/rgen/template_language/output_handler.rb +84 -0
  25. data/lib/rgen/template_language/template_container.rb +153 -0
  26. data/lib/rgen/template_language/template_helper.rb +26 -0
  27. data/lib/rgen/transformer.rb +316 -0
  28. data/lib/rgen/xml_instantiator/dependency_resolver.rb +23 -0
  29. data/lib/rgen/xml_instantiator/xml_instantiator.rb +78 -0
  30. data/lib/rgen/xml_instantiator/xml_parser.rb +39 -0
  31. data/lib/uml/objectmodel_instantiator.rb +53 -0
  32. data/lib/uml/uml_classmodel.rb +92 -0
  33. data/lib/uml/uml_objectmodel.rb +65 -0
  34. data/test/array_extensions_test.rb +54 -0
  35. data/test/environment_test.rb +47 -0
  36. data/test/metamodel_builder_test.rb +175 -0
  37. data/test/metamodel_generator_test.rb +45 -0
  38. data/test/metamodel_generator_test/TestModel.rb +40 -0
  39. data/test/metamodel_generator_test/expected_result.txt +40 -0
  40. data/test/output_handler_test.rb +40 -0
  41. data/test/rgen_test.rb +13 -0
  42. data/test/template_language_test.rb +46 -0
  43. data/test/template_language_test/expected_result.txt +10 -0
  44. data/test/template_language_test/templates/content/chapter.tpl +5 -0
  45. data/test/template_language_test/templates/index/c/cmod.tpl +1 -0
  46. data/test/template_language_test/templates/index/chapter.tpl +3 -0
  47. data/test/template_language_test/templates/root.tpl +22 -0
  48. data/test/template_language_test/testout.txt +10 -0
  49. data/test/transformer_test.rb +176 -0
  50. data/test/xmi_class_instantiator_test.rb +107 -0
  51. data/test/xmi_instantiator_test/testmodel.eap +0 -0
  52. data/test/xmi_instantiator_test/testmodel.xml +962 -0
  53. data/test/xmi_object_instantiator_test.rb +65 -0
  54. metadata +117 -0
@@ -0,0 +1,45 @@
1
+ $:.unshift File.join(File.dirname(__FILE__),"..","lib")
2
+
3
+ require 'test/unit'
4
+ require 'ea/xmi_class_instantiator'
5
+ require 'mmgen/metamodel_generator'
6
+
7
+ class MetamodelGeneratorTest < Test::Unit::TestCase
8
+
9
+ MODEL_DIR = File.join(File.dirname(__FILE__),"xmi_instantiator_test")
10
+ OUTPUT_DIR = File.dirname(__FILE__)+"/metamodel_generator_test"
11
+ MM_FILE = OUTPUT_DIR+"/TestModel.rb"
12
+
13
+ include XMIClassInstantiator
14
+ include MMGen::MetamodelGenerator
15
+
16
+ def test_generator
17
+ envUML = RGen::Environment.new
18
+ File.open(MODEL_DIR+"/testmodel.xml") { |f|
19
+ instantiateUMLClassModel(envUML, f.read)
20
+ }
21
+
22
+ rootPackage = envUML.find(:class => UMLClassModel::UMLPackage).select{|p| p.name == "HouseMetamodel"}.first
23
+ assert_not_nil rootPackage
24
+
25
+ assert_raise StandardError do
26
+ # this will raise an exception because multiple inheritance is not resolved
27
+ generateMetamodel(rootPackage, MM_FILE)
28
+ end
29
+
30
+ # resolve multiple inheritance by specifying which class should be a module
31
+ modules = ['MeetingPlace']
32
+ generateMetamodel(rootPackage, MM_FILE, modules)
33
+
34
+ # try to use the generated metamodel
35
+ File.open(MM_FILE) { |f|
36
+ eval(f.read)
37
+ }
38
+ assert HouseMetamodel::House.new
39
+
40
+ result = expected = ""
41
+ File.open(MM_FILE) {|f| result = f.read}
42
+ File.open(OUTPUT_DIR+"/expected_result.txt") {|f| expected = f.read}
43
+ assert_equal expected, result
44
+ end
45
+ end
@@ -0,0 +1,40 @@
1
+ require 'rgen/metamodel_builder'
2
+ module HouseMetamodel
3
+
4
+ class Person < RGen::MetamodelBuilder::MMBase
5
+ has_one 'name', String
6
+ end
7
+
8
+ class House < RGen::MetamodelBuilder::MMBase
9
+ has_one 'name', String
10
+ has_one 'address', String
11
+ end
12
+
13
+ module MeetingPlace
14
+ extend RGen::MetamodelBuilder::BuilderExtensions
15
+ has_one 'name', String
16
+ end
17
+
18
+
19
+ module Rooms
20
+
21
+ class Room < RGen::MetamodelBuilder::MMBase
22
+ has_one 'name', String
23
+ end
24
+
25
+ class Bathroom < Room
26
+ has_one 'name', String
27
+ end
28
+
29
+ class Kitchen < Room
30
+ include MeetingPlace
31
+ has_one 'name', String
32
+ end
33
+
34
+ end
35
+ end
36
+
37
+ HouseMetamodel::Person.one_to_many 'home', HouseMetamodel::House, 'person'
38
+ HouseMetamodel::House.one_to_one 'bathroom', HouseMetamodel::Rooms::Bathroom, 'house'
39
+ HouseMetamodel::Rooms::Kitchen.one_to_one 'house', HouseMetamodel::House, 'kitchen'
40
+ HouseMetamodel::House.one_to_many 'room', HouseMetamodel::Rooms::Room, 'house'
@@ -0,0 +1,40 @@
1
+ require 'rgen/metamodel_builder'
2
+ module HouseMetamodel
3
+
4
+ class Person < RGen::MetamodelBuilder::MMBase
5
+ has_one 'name', String
6
+ end
7
+
8
+ class House < RGen::MetamodelBuilder::MMBase
9
+ has_one 'name', String
10
+ has_one 'address', String
11
+ end
12
+
13
+ module MeetingPlace
14
+ extend RGen::MetamodelBuilder::BuilderExtensions
15
+ has_one 'name', String
16
+ end
17
+
18
+
19
+ module Rooms
20
+
21
+ class Room < RGen::MetamodelBuilder::MMBase
22
+ has_one 'name', String
23
+ end
24
+
25
+ class Bathroom < Room
26
+ has_one 'name', String
27
+ end
28
+
29
+ class Kitchen < Room
30
+ include MeetingPlace
31
+ has_one 'name', String
32
+ end
33
+
34
+ end
35
+ end
36
+
37
+ HouseMetamodel::Person.one_to_many 'home', HouseMetamodel::House, 'person'
38
+ HouseMetamodel::House.one_to_one 'bathroom', HouseMetamodel::Rooms::Bathroom, 'house'
39
+ HouseMetamodel::Rooms::Kitchen.one_to_one 'house', HouseMetamodel::House, 'kitchen'
40
+ HouseMetamodel::House.one_to_many 'room', HouseMetamodel::Rooms::Room, 'house'
@@ -0,0 +1,40 @@
1
+ $:.unshift File.join(File.dirname(__FILE__),"..","lib")
2
+
3
+ require 'test/unit'
4
+ require 'rgen/template_language/output_handler'
5
+
6
+ class MetamodelBuilderTest < Test::Unit::TestCase
7
+ def test_direct_nl
8
+ h = RGen::TemplateLanguage::OutputHandler.new
9
+ h.mode = :direct
10
+ h << "Test"
11
+ h.ignoreNextNL
12
+ h << "\nContent"
13
+ assert_equal "TestContent", h.to_s
14
+ end
15
+ def test_direct_ws
16
+ h = RGen::TemplateLanguage::OutputHandler.new
17
+ h.mode = :direct
18
+ h << "Test"
19
+ h.ignoreNextWS
20
+ h << " \n Content"
21
+ assert_equal "TestContent", h.to_s
22
+ end
23
+ def test_explicit_indent
24
+ h = RGen::TemplateLanguage::OutputHandler.new
25
+ h.mode = :explicit
26
+ h.indent = 1
27
+ h << "Start"
28
+ h << " \n "
29
+ h << "Test"
30
+ h << " \n \n Content"
31
+ assert_equal " Start\n Test\n Content", h.to_s
32
+ end
33
+ def test_explicit_endswithws
34
+ h = RGen::TemplateLanguage::OutputHandler.new
35
+ h.mode = :explicit
36
+ h.indent = 1
37
+ h << "Start \n\n"
38
+ assert_equal " Start\n", h.to_s
39
+ end
40
+ end
@@ -0,0 +1,13 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'test/unit'
4
+
5
+ require 'array_extensions_test'
6
+ require 'environment_test'
7
+ require 'metamodel_builder_test'
8
+ require 'output_handler_test'
9
+ require 'template_language_test'
10
+ require 'xmi_class_instantiator_test'
11
+ require 'xmi_object_instantiator_test'
12
+ require 'metamodel_generator_test'
13
+ require 'transformer_test'
@@ -0,0 +1,46 @@
1
+ $:.unshift File.join(File.dirname(__FILE__),"..","lib")
2
+
3
+ require 'test/unit'
4
+ require 'rgen/template_language'
5
+
6
+ class TemplateContainerTest < Test::Unit::TestCase
7
+
8
+ TEMPLATES_DIR = File.dirname(__FILE__)+"/template_language_test/templates"
9
+ OUTPUT_DIR = File.dirname(__FILE__)+"/template_language_test"
10
+
11
+ module MyMM
12
+
13
+ class Chapter
14
+ attr_reader :title
15
+ def initialize(title)
16
+ @title = title
17
+ end
18
+ end
19
+
20
+ class Document
21
+ attr_reader :title, :author, :chapters
22
+ def initialize(title, author)
23
+ @title, @author = title, author
24
+ @chapters = []
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ TEST_MODEL = MyMM::Document.new("SomeDocument","MyName")
31
+ TEST_MODEL.chapters << MyMM::Chapter.new("Intro")
32
+ TEST_MODEL.chapters << MyMM::Chapter.new("MainPart")
33
+ TEST_MODEL.chapters << MyMM::Chapter.new("Summary")
34
+
35
+ def test_with_model
36
+ tc = RGen::TemplateLanguage::DirectoryTemplateContainer.new(MyMM, OUTPUT_DIR)
37
+ tc.load(TEMPLATES_DIR)
38
+ File.delete(OUTPUT_DIR+"/testout.txt") if File.exists? OUTPUT_DIR+"/testout.txt"
39
+ tc.expand('root::Root', :for => TEST_MODEL, :indent => 1)
40
+ result = expected = ""
41
+ File.open(OUTPUT_DIR+"/testout.txt") {|f| result = f.read}
42
+ File.open(OUTPUT_DIR+"/expected_result.txt") {|f| expected = f.read}
43
+ assert_equal expected, result
44
+ end
45
+
46
+ end
@@ -0,0 +1,10 @@
1
+ Document: SomeDocument
2
+ Index:
3
+ 1 Intro in SomeDocument
4
+ 2 MainPart in SomeDocument
5
+ 3 Summary in SomeDocument
6
+ by MyName
7
+ ----------------
8
+ *** Intro ***
9
+ *** MainPart ***
10
+ *** Summary ***
@@ -0,0 +1,5 @@
1
+ <% define 'Root', :for => Chapter do %>
2
+ *** <%= title %> ***
3
+
4
+
5
+ <% end %>
@@ -0,0 +1 @@
1
+ <% define 'cmod' do %>Module C is special !<% end %>
@@ -0,0 +1,3 @@
1
+ <% define 'Root' do |idx, doc| %>
2
+ <%= idx%> <%= title %> in <%= doc.title %>
3
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <% define 'Root' do %>
2
+ <% file 'testout.txt' do %>
3
+ Document: <%= title %>
4
+
5
+ Index:<%iinc%>
6
+ <% for c in chapters %>
7
+ <% nr = (nr || 0); nr += 1 %>
8
+ <% expand 'index/chapter::Root', nr, this, :for => c %>
9
+ <% end %><%idec%>
10
+
11
+ by <%= author %>
12
+
13
+ ----------------
14
+
15
+ <% expand 'content/chapter::Root', :foreach => chapters %>
16
+
17
+ <% end %>
18
+ <% end %>
19
+
20
+ <% def MyNewMethod(arg1, arg2, arg3) %>
21
+ <% end %>
22
+
@@ -0,0 +1,10 @@
1
+ Document: SomeDocument
2
+ Index:
3
+ 1 Intro in SomeDocument
4
+ 2 MainPart in SomeDocument
5
+ 3 Summary in SomeDocument
6
+ by MyName
7
+ ----------------
8
+ *** Intro ***
9
+ *** MainPart ***
10
+ *** Summary ***
@@ -0,0 +1,176 @@
1
+ $:.unshift File.join(File.dirname(__FILE__),"..","lib")
2
+
3
+ require 'test/unit'
4
+ require 'rgen/transformer'
5
+ require 'rgen/environment'
6
+
7
+ class TransformerTest < Test::Unit::TestCase
8
+
9
+ class ModelIn
10
+ attr_accessor :name
11
+ end
12
+
13
+ class ModelAIn
14
+ attr_accessor :name
15
+ attr_accessor :modelB
16
+ end
17
+
18
+ class ModelBIn
19
+ attr_accessor :name
20
+ attr_accessor :modelA
21
+ end
22
+
23
+ class ModelCIn
24
+ attr_accessor :number
25
+ end
26
+
27
+ class ModelOut
28
+ attr_accessor :name
29
+ end
30
+
31
+ class ModelAOut
32
+ attr_accessor :name
33
+ attr_accessor :modelB
34
+ end
35
+
36
+ class ModelBOut
37
+ attr_accessor :name
38
+ attr_accessor :modelA
39
+ end
40
+
41
+ class ModelCOut
42
+ attr_accessor :number
43
+ end
44
+
45
+ class MyTransformer < RGen::Transformer
46
+ attr_reader :modelInTrans_count
47
+ attr_reader :modelAInTrans_count
48
+ attr_reader :modelBInTrans_count
49
+
50
+ transform ModelIn, :to => ModelOut do
51
+ # aribitrary ruby code may be placed before the hash creating the output element
52
+ @modelInTrans_count ||= 0; @modelInTrans_count += 1
53
+ { :name => name }
54
+ end
55
+
56
+ transform ModelAIn, :to => ModelAOut do
57
+ @modelAInTrans_count ||= 0; @modelAInTrans_count += 1
58
+ { :name => name, :modelB => trans(modelB) }
59
+ end
60
+
61
+ transform ModelBIn, :to => ModelBOut do
62
+ @modelBInTrans_count ||= 0; @modelBInTrans_count += 1
63
+ { :name => name, :modelA => trans(modelA) }
64
+ end
65
+
66
+ transform ModelCIn, :to => ModelCOut, :if => :largeNumber do
67
+ # a method can be called anywhere in a transformer block
68
+ { :number => duplicateNumber }
69
+ end
70
+
71
+ transform ModelCIn, :to => ModelCOut, :if => :smallNumber do
72
+ { :number => number / 2 }
73
+ end
74
+
75
+ method :largeNumber do
76
+ number > 1000
77
+ end
78
+
79
+ method :smallNumber do
80
+ number < 500
81
+ end
82
+
83
+ method :duplicateNumber do
84
+ number * 2;
85
+ end
86
+
87
+ end
88
+
89
+ class MyTransformer2 < RGen::Transformer
90
+ # check that subclasses are independent (i.e. do not share the rules)
91
+ transform ModelIn, :to => ModelOut do
92
+ { :name => name }
93
+ end
94
+ end
95
+
96
+ def test_transformer
97
+ from = ModelIn.new
98
+ from.name = "TestName"
99
+ env_out = RGen::Environment.new
100
+ t = MyTransformer.new(:env_in, env_out)
101
+ assert t.trans(from).is_a?(ModelOut)
102
+ assert_equal "TestName", t.trans(from).name
103
+ assert_equal 1, env_out.elements.size
104
+ assert_equal env_out.elements.first, t.trans(from)
105
+ assert_equal 1, t.modelInTrans_count
106
+ end
107
+
108
+ def test_transformer_array
109
+ froms = [ModelIn.new, ModelIn.new]
110
+ froms[0].name = "M1"
111
+ froms[1].name = "M2"
112
+ env_out = RGen::Environment.new
113
+ t = MyTransformer.new(:env_in, env_out)
114
+ assert t.trans(froms).is_a?(Array)
115
+ assert t.trans(froms)[0].is_a?(ModelOut)
116
+ assert_equal "M1", t.trans(froms)[0].name
117
+ assert t.trans(froms)[1].is_a?(ModelOut)
118
+ assert_equal "M2", t.trans(froms)[1].name
119
+ assert_equal 2, env_out.elements.size
120
+ assert (t.trans(froms)-env_out.elements).empty?
121
+ assert_equal 2, t.modelInTrans_count
122
+ end
123
+
124
+ def test_transformer_cyclic
125
+ # setup a cyclic dependency between fromA and fromB
126
+ fromA = ModelAIn.new
127
+ fromB = ModelBIn.new
128
+ fromA.modelB = fromB
129
+ fromA.name = "ModelA"
130
+ fromB.modelA = fromA
131
+ fromB.name = "ModelB"
132
+ env_out = RGen::Environment.new
133
+ t = MyTransformer.new(:env_in, env_out)
134
+ # check that trans resolves the cycle correctly (no endless loop)
135
+ # both elements, fromA and fromB will be transformed with the transformation
136
+ # of the first element, either fromA or fromB
137
+ assert t.trans(fromA).is_a?(ModelAOut)
138
+ assert_equal "ModelA", t.trans(fromA).name
139
+ assert t.trans(fromA).modelB.is_a?(ModelBOut)
140
+ assert_equal "ModelB", t.trans(fromA).modelB.name
141
+ assert_equal t.trans(fromA), t.trans(fromA).modelB.modelA
142
+ assert_equal t.trans(fromB), t.trans(fromA).modelB
143
+ assert_equal 2, env_out.elements.size
144
+ assert (env_out.elements - [t.trans(fromA), t.trans(fromB)]).empty?
145
+ assert_equal 1, t.modelAInTrans_count
146
+ assert_equal 1, t.modelBInTrans_count
147
+ end
148
+
149
+ def test_transformer_conditional
150
+ froms = [ModelCIn.new, ModelCIn.new, ModelCIn.new]
151
+ froms[0].number = 100
152
+ froms[1].number = 1000
153
+ froms[2].number = 2000
154
+
155
+ env_out = RGen::Environment.new
156
+ t = MyTransformer.new(:env_in, env_out)
157
+
158
+ assert t.trans(froms).is_a?(Array)
159
+ assert_equal 2, t.trans(froms).size
160
+
161
+ # this one matched the smallNumber rule
162
+ assert t.trans(froms[0]).is_a?(ModelCOut)
163
+ assert_equal 50, t.trans(froms[0]).number
164
+
165
+ # this one did not match any rule
166
+ assert t.trans(froms[1]).nil?
167
+
168
+ # this one matched the largeNumber rule
169
+ assert t.trans(froms[2]).is_a?(ModelCOut)
170
+ assert_equal 4000, t.trans(froms[2]).number
171
+
172
+ # elements in environment are the same as the ones returned
173
+ assert_equal 2, env_out.elements.size
174
+ assert (t.trans(froms)-env_out.elements).empty?
175
+ end
176
+ end