rgen 0.7.0 → 0.8.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.
- 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
|
|