rgen 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +9 -0
- data/MIT-LICENSE +20 -0
- data/README +73 -0
- data/lib/ea/xmi_class_instantiator.rb +45 -0
- data/lib/ea/xmi_helper.rb +26 -0
- data/lib/ea/xmi_metamodel.rb +19 -0
- data/lib/ea/xmi_object_instantiator.rb +42 -0
- data/lib/ea/xmi_to_classmodel.rb +78 -0
- data/lib/ea/xmi_to_objectmodel.rb +89 -0
- data/lib/mmgen/metamodel_generator.rb +19 -0
- data/lib/mmgen/mm_ext/uml_classmodel_ext.rb +71 -0
- data/lib/mmgen/mmgen.rb +21 -0
- data/lib/mmgen/templates/uml_classmodel.tpl +63 -0
- data/lib/rgen/array_extensions.rb +23 -0
- data/lib/rgen/auto_class_creator.rb +56 -0
- data/lib/rgen/environment.rb +57 -0
- data/lib/rgen/metamodel_builder.rb +102 -0
- data/lib/rgen/metamodel_builder/build_helper.rb +29 -0
- data/lib/rgen/metamodel_builder/builder_extensions.rb +191 -0
- data/lib/rgen/metamodel_builder/builder_runtime.rb +67 -0
- data/lib/rgen/name_helper.rb +18 -0
- data/lib/rgen/template_language.rb +169 -0
- data/lib/rgen/template_language/directory_template_container.rb +51 -0
- data/lib/rgen/template_language/output_handler.rb +84 -0
- data/lib/rgen/template_language/template_container.rb +153 -0
- data/lib/rgen/template_language/template_helper.rb +26 -0
- data/lib/rgen/transformer.rb +316 -0
- data/lib/rgen/xml_instantiator/dependency_resolver.rb +23 -0
- data/lib/rgen/xml_instantiator/xml_instantiator.rb +78 -0
- data/lib/rgen/xml_instantiator/xml_parser.rb +39 -0
- data/lib/uml/objectmodel_instantiator.rb +53 -0
- data/lib/uml/uml_classmodel.rb +92 -0
- data/lib/uml/uml_objectmodel.rb +65 -0
- data/test/array_extensions_test.rb +54 -0
- data/test/environment_test.rb +47 -0
- data/test/metamodel_builder_test.rb +175 -0
- data/test/metamodel_generator_test.rb +45 -0
- data/test/metamodel_generator_test/TestModel.rb +40 -0
- data/test/metamodel_generator_test/expected_result.txt +40 -0
- data/test/output_handler_test.rb +40 -0
- data/test/rgen_test.rb +13 -0
- data/test/template_language_test.rb +46 -0
- data/test/template_language_test/expected_result.txt +10 -0
- data/test/template_language_test/templates/content/chapter.tpl +5 -0
- data/test/template_language_test/templates/index/c/cmod.tpl +1 -0
- data/test/template_language_test/templates/index/chapter.tpl +3 -0
- data/test/template_language_test/templates/root.tpl +22 -0
- data/test/template_language_test/testout.txt +10 -0
- data/test/transformer_test.rb +176 -0
- data/test/xmi_class_instantiator_test.rb +107 -0
- data/test/xmi_instantiator_test/testmodel.eap +0 -0
- data/test/xmi_instantiator_test/testmodel.xml +962 -0
- data/test/xmi_object_instantiator_test.rb +65 -0
- 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
|
data/test/rgen_test.rb
ADDED
@@ -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 @@
|
|
1
|
+
<% define 'cmod' do %>Module C is special !<% 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,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
|