rgen 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +10 -0
- data/README.rdoc +1 -1
- data/Rakefile +1 -1
- data/lib/rgen/ecore/ecore_to_ruby.rb +112 -49
- data/lib/rgen/instantiator/default_xml_instantiator.rb +93 -88
- data/lib/rgen/metamodel_builder/builder_extensions.rb +20 -4
- data/lib/rgen/template_language/output_handler.rb +42 -19
- data/lib/rgen/template_language/template_container.rb +10 -4
- data/test/coverage/assets/0.10.0/application.css +799 -0
- data/test/coverage/assets/0.10.0/application.js +1707 -0
- data/test/coverage/assets/0.10.0/colorbox/border.png +0 -0
- data/test/coverage/assets/0.10.0/colorbox/controls.png +0 -0
- data/test/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
- data/test/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
- data/test/coverage/assets/0.10.0/favicon_green.png +0 -0
- data/test/coverage/assets/0.10.0/favicon_red.png +0 -0
- data/test/coverage/assets/0.10.0/favicon_yellow.png +0 -0
- data/test/coverage/assets/0.10.0/loading.gif +0 -0
- data/test/coverage/assets/0.10.0/magnify.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/test/coverage/index.html +72 -0
- data/test/ecore_to_ruby_test.rb +73 -0
- data/test/metamodel_builder_test.rb +2 -2
- data/test/model_builder/ecore_internal.rb +12 -12
- data/test/rgen_test.rb +1 -0
- data/test/template_language_test.rb +15 -1
- data/test/template_language_test/templates/indent_nonl_at_eof_test/test.tpl +14 -0
- data/test/template_language_test/templates/indent_same_line_sub/test.tpl +16 -0
- data/test/testmodel/ea_testmodel_regenerated.xml +583 -583
- metadata +37 -7
- checksums.yaml +0 -7
data/CHANGELOG
CHANGED
@@ -195,3 +195,13 @@
|
|
195
195
|
* Added setNilOrRemoveGeneric and setNilOrRemoveAllGeneric methods
|
196
196
|
* Added disconnectContainer method
|
197
197
|
|
198
|
+
=0.8.0
|
199
|
+
|
200
|
+
* Fixed missing indentation when template file is not terminated by a newline
|
201
|
+
* Fixed missing indentation when expand in same line expands sub templates
|
202
|
+
* Fixed DefaultXMLInstantiator naming error with a tag named 'File' (issue #19, pull request #21 from jkugs)
|
203
|
+
* Simplified ECoreToRuby and optionally let it create modules with non-temporary names
|
204
|
+
* Improved performance of output handler
|
205
|
+
* Improved performance of setXXX and addXXX methods (pull request #22 from thallgren)
|
206
|
+
* Use a value larger than Fixnum max to test Bignum support (pull request #18 from graaff)
|
207
|
+
|
data/README.rdoc
CHANGED
@@ -5,7 +5,7 @@ This means that it helps you build Metamodels, instantiate Models, modify
|
|
5
5
|
and transform Models and finally generate arbitrary textual content from it.
|
6
6
|
|
7
7
|
RGen features include:
|
8
|
-
* Supporting Ruby 1.8.
|
8
|
+
* Supporting Ruby 1.8.7, 1.9.x, 2.0, 2.1, 2.2
|
9
9
|
* Metamodel definition language (internal Ruby DSL)
|
10
10
|
* ECore Meta-metamodel with an ECore instance available for every Metamodel
|
11
11
|
* Generator creating the Ruby metamodel definition from an ECore instance
|
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
|
+
s.version = "0.8.0"
|
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}
|
@@ -4,63 +4,113 @@ module RGen
|
|
4
4
|
|
5
5
|
module ECore
|
6
6
|
|
7
|
+
# ECoreToRuby can turn ECore models into their Ruby metamodel representations
|
7
8
|
class ECoreToRuby
|
8
9
|
|
9
10
|
def initialize
|
10
11
|
@modules = {}
|
11
12
|
@classifiers = {}
|
12
13
|
@features_added = {}
|
13
|
-
@in_create_module = false
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
16
|
+
# Create a Ruby module representing +epackage+.
|
17
|
+
# This includes all nested modules/packages, classes and enums.
|
18
|
+
#
|
19
|
+
# If a parent module is provided with the "under" parameter,
|
20
|
+
# the new module will be nested under the parent module.
|
21
|
+
#
|
22
|
+
# If the parent module has a non-temporary name,
|
23
|
+
# (more precisely: a non-temporary classpath) i.e. if it is reachable
|
24
|
+
# via a path of constant names from the root, then the nested
|
25
|
+
# modules and classes will also have non-temporary names.
|
26
|
+
# In particular, this means that they will keep their names even
|
27
|
+
# if they are assigned to new constants.
|
28
|
+
#
|
29
|
+
# If no parent module is provided or the parent module has a
|
30
|
+
# temporary name by itself, then the nested modules and classes will
|
31
|
+
# also have temporary names. This means that their name will stay
|
32
|
+
# 'volatile' until they are assigned to constants reachable from
|
33
|
+
# the root and the Module#name method is called for the first time.
|
34
|
+
#
|
35
|
+
# While the second approach is more flexible, it can come with a major
|
36
|
+
# performance impact. The reason is that Ruby searches the space of
|
37
|
+
# all known non-temporary classes/modules every time the name
|
38
|
+
# of a class/module with a temporary name is queried.
|
39
|
+
#
|
40
|
+
def create_module(epackage, under=Module.new)
|
41
|
+
temp = under.to_s.start_with?("#")
|
42
|
+
mod = create_module_internal(epackage, under, temp)
|
43
|
+
|
44
|
+
epackage.eAllClassifiers.each do |c|
|
45
|
+
if c.is_a?(RGen::ECore::EClass)
|
46
|
+
create_class(c, temp)
|
47
|
+
elsif c.is_a?(RGen::ECore::EEnum)
|
48
|
+
create_enum(c)
|
49
|
+
end
|
24
50
|
end
|
25
|
-
@modules[epackage] = m
|
26
51
|
|
27
|
-
|
28
|
-
|
52
|
+
mod
|
53
|
+
end
|
29
54
|
|
30
|
-
|
55
|
+
private
|
31
56
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
elsif c.is_a?(RGen::ECore::EEnum)
|
39
|
-
create_enum(c)
|
40
|
-
end
|
57
|
+
def create_module_internal(epackage, under, temp)
|
58
|
+
return @modules[epackage] if @modules[epackage]
|
59
|
+
|
60
|
+
if temp
|
61
|
+
mod = Module.new do
|
62
|
+
extend RGen::MetamodelBuilder::ModuleExtension
|
41
63
|
end
|
42
|
-
|
64
|
+
under.const_set(epackage.name, mod)
|
65
|
+
else
|
66
|
+
under.module_eval <<-END
|
67
|
+
module #{epackage.name}
|
68
|
+
extend RGen::MetamodelBuilder::ModuleExtension
|
69
|
+
end
|
70
|
+
END
|
71
|
+
mod = under.const_get(epackage.name)
|
43
72
|
end
|
44
|
-
|
73
|
+
@modules[epackage] = mod
|
74
|
+
|
75
|
+
epackage.eSubpackages.each{|p| create_module_internal(p, mod, temp)}
|
76
|
+
mod._set_ecore_internal(epackage)
|
77
|
+
|
78
|
+
mod
|
45
79
|
end
|
46
80
|
|
47
|
-
def create_class(eclass)
|
81
|
+
def create_class(eclass, temp)
|
48
82
|
return @classifiers[eclass] if @classifiers[eclass]
|
49
83
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
84
|
+
mod = @modules[eclass.ePackage]
|
85
|
+
if temp
|
86
|
+
cls = Class.new(super_class(eclass, temp)) do
|
87
|
+
abstract if eclass.abstract
|
88
|
+
class << self
|
89
|
+
attr_accessor :_ecore_to_ruby
|
90
|
+
end
|
54
91
|
end
|
92
|
+
mod.const_set(eclass.name, cls)
|
93
|
+
else
|
94
|
+
mod.module_eval <<-END
|
95
|
+
class #{eclass.name} < #{super_class(eclass, temp)}
|
96
|
+
#{eclass.abstract ? 'abstract' : ''}
|
97
|
+
class << self
|
98
|
+
attr_accessor :_ecore_to_ruby
|
99
|
+
end
|
100
|
+
end
|
101
|
+
END
|
102
|
+
cls = mod.const_get(eclass.name)
|
55
103
|
end
|
104
|
+
|
56
105
|
class << eclass
|
57
106
|
attr_accessor :instanceClass
|
58
107
|
def instanceClassName
|
59
108
|
instanceClass.to_s
|
60
109
|
end
|
61
110
|
end
|
62
|
-
eclass.instanceClass =
|
63
|
-
|
111
|
+
eclass.instanceClass = cls
|
112
|
+
|
113
|
+
cls::ClassModule.module_eval do
|
64
114
|
alias _method_missing method_missing
|
65
115
|
def method_missing(m, *args)
|
66
116
|
if self.class._ecore_to_ruby.add_features(self.class.ecore)
|
@@ -75,12 +125,11 @@ class ECoreToRuby
|
|
75
125
|
_respond_to(m)
|
76
126
|
end
|
77
127
|
end
|
78
|
-
@classifiers[eclass] =
|
79
|
-
|
80
|
-
|
128
|
+
@classifiers[eclass] = cls
|
129
|
+
cls._set_ecore_internal(eclass)
|
130
|
+
cls._ecore_to_ruby = self
|
81
131
|
|
82
|
-
|
83
|
-
c
|
132
|
+
cls
|
84
133
|
end
|
85
134
|
|
86
135
|
def create_enum(eenum)
|
@@ -89,7 +138,7 @@ class ECoreToRuby
|
|
89
138
|
e = RGen::MetamodelBuilder::DataTypes::Enum.new(eenum.eLiterals.collect{|l| l.name.to_sym})
|
90
139
|
@classifiers[eenum] = e
|
91
140
|
|
92
|
-
|
141
|
+
@modules[eenum.ePackage].const_set(eenum.name, e)
|
93
142
|
e
|
94
143
|
end
|
95
144
|
|
@@ -126,6 +175,32 @@ class ECoreToRuby
|
|
126
175
|
end
|
127
176
|
end
|
128
177
|
|
178
|
+
def super_class(eclass, temp)
|
179
|
+
super_types = eclass.eSuperTypes
|
180
|
+
if temp
|
181
|
+
case super_types.size
|
182
|
+
when 0
|
183
|
+
RGen::MetamodelBuilder::MMBase
|
184
|
+
when 1
|
185
|
+
create_class(super_types.first, temp)
|
186
|
+
else
|
187
|
+
RGen::MetamodelBuilder::MMMultiple(*super_types.collect{|t| create_class(t, temp)})
|
188
|
+
end
|
189
|
+
else
|
190
|
+
case super_types.size
|
191
|
+
when 0
|
192
|
+
"RGen::MetamodelBuilder::MMBase"
|
193
|
+
when 1
|
194
|
+
create_class(super_types.first, temp).name
|
195
|
+
else
|
196
|
+
"RGen::MetamodelBuilder::MMMultiple(" +
|
197
|
+
super_types.collect{|t| create_class(t, temp).name}.join(",") + ")"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
public
|
203
|
+
|
129
204
|
def add_features(eclass)
|
130
205
|
return false if @features_added[eclass]
|
131
206
|
c = @classifiers[eclass]
|
@@ -147,18 +222,6 @@ class ECoreToRuby
|
|
147
222
|
true
|
148
223
|
end
|
149
224
|
|
150
|
-
def super_class(eclass)
|
151
|
-
super_types = eclass.eSuperTypes
|
152
|
-
case super_types.size
|
153
|
-
when 0
|
154
|
-
RGen::MetamodelBuilder::MMBase
|
155
|
-
when 1
|
156
|
-
create_class(super_types.first)
|
157
|
-
else
|
158
|
-
RGen::MetamodelBuilder::MMMultiple(*super_types.collect{|t| create_class(t)})
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
225
|
end
|
163
226
|
|
164
227
|
end
|
@@ -8,107 +8,112 @@ module Instantiator
|
|
8
8
|
# Derive your own instantiator from this class or use it as is.
|
9
9
|
#
|
10
10
|
class DefaultXMLInstantiator < NodebasedXMLInstantiator
|
11
|
-
|
11
|
+
include Util::NameHelper
|
12
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
|
-
|
13
|
+
NamespaceDescriptor = Struct.new(:prefix, :target)
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
def map_tag_ns(from, to, prefix="")
|
18
|
+
tag_ns_map[from] = NamespaceDescriptor.new(prefix, to)
|
19
|
+
end
|
20
|
+
|
21
|
+
def tag_ns_map # :nodoc:
|
22
|
+
@tag_ns_map ||={}
|
23
|
+
@tag_ns_map
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(env, default_module, create_mm=false)
|
29
|
+
super(env)
|
30
|
+
@default_module = default_module
|
31
|
+
@create_mm = create_mm
|
32
|
+
end
|
33
|
+
|
34
|
+
def on_descent(node)
|
35
|
+
obj = new_object(node)
|
36
|
+
@env << obj unless obj.nil?
|
37
|
+
node.object = obj
|
38
|
+
node.attributes.each_pair { |k,v| set_attribute(node, k, v) }
|
39
|
+
end
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
def on_ascent(node)
|
42
|
+
node.children.each { |c| assoc_p2c(node, c) }
|
43
|
+
node.object.class.has_attr 'chardata', Object unless node.object.respond_to?(:chardata)
|
44
|
+
set_attribute(node, "chardata", node.chardata)
|
45
|
+
end
|
46
|
+
|
47
47
|
def class_name(str)
|
48
48
|
saneClassName(str)
|
49
49
|
end
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
51
|
+
def new_object(node)
|
52
|
+
ns_desc = self.class.tag_ns_map[node.namespace]
|
53
|
+
class_name = class_name(ns_desc.nil? ? node.qtag : ns_desc.prefix+node.tag)
|
54
|
+
mod = (ns_desc && ns_desc.target) || @default_module
|
55
|
+
build_on_error(NameError, :build_class, class_name, mod) do
|
56
|
+
begin
|
57
|
+
mod.const_get(class_name, false).new
|
58
|
+
rescue ArgumentError
|
59
|
+
# Ruby 1.8
|
60
|
+
mod.const_get(class_name).new
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
59
64
|
|
60
|
-
|
61
|
-
|
62
|
-
|
65
|
+
def build_class(name, mod)
|
66
|
+
mod.const_set(name, Class.new(RGen::MetamodelBuilder::MMBase))
|
67
|
+
end
|
63
68
|
|
64
69
|
def method_name(str)
|
65
70
|
saneMethodName(str)
|
66
71
|
end
|
67
72
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
73
|
+
def assoc_p2c(parent, child)
|
74
|
+
return unless parent.object && child.object
|
75
|
+
method_name = method_name(className(child.object))
|
76
|
+
build_on_error(NoMethodError, :build_p2c_assoc, parent, child, method_name) do
|
77
|
+
parent.object.addGeneric(method_name, child.object)
|
78
|
+
child.object.setGeneric("parent", parent.object)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def build_p2c_assoc(parent, child, method_name)
|
83
|
+
parent.object.class.has_many(method_name, child.object.class)
|
84
|
+
child.object.class.has_one("parent", RGen::MetamodelBuilder::MMBase)
|
85
|
+
end
|
86
|
+
|
87
|
+
def set_attribute(node, attr, value)
|
88
|
+
return unless node.object
|
89
|
+
build_on_error(NoMethodError, :build_attribute, node, attr, value) do
|
90
|
+
node.object.setGeneric(method_name(attr), value)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def build_attribute(node, attr, value)
|
95
|
+
node.object.class.has_attr(method_name(attr))
|
96
|
+
end
|
92
97
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
98
|
+
protected
|
99
|
+
|
100
|
+
# Helper method for implementing classes.
|
101
|
+
# This method yields the given block.
|
102
|
+
# If the metamodel should be create automatically (see constructor)
|
103
|
+
# rescues +error+ and calls +builder_method+ with +args+, then
|
104
|
+
# yields the block again.
|
105
|
+
def build_on_error(error, builder_method, *args)
|
106
|
+
begin
|
107
|
+
yield
|
108
|
+
rescue error
|
109
|
+
if @create_mm
|
110
|
+
send(builder_method, *args)
|
111
|
+
yield
|
112
|
+
else
|
113
|
+
raise
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
112
117
|
|
113
118
|
end
|
114
119
|
|