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.
Files changed (43) hide show
  1. data/CHANGELOG +10 -0
  2. data/README.rdoc +1 -1
  3. data/Rakefile +1 -1
  4. data/lib/rgen/ecore/ecore_to_ruby.rb +112 -49
  5. data/lib/rgen/instantiator/default_xml_instantiator.rb +93 -88
  6. data/lib/rgen/metamodel_builder/builder_extensions.rb +20 -4
  7. data/lib/rgen/template_language/output_handler.rb +42 -19
  8. data/lib/rgen/template_language/template_container.rb +10 -4
  9. data/test/coverage/assets/0.10.0/application.css +799 -0
  10. data/test/coverage/assets/0.10.0/application.js +1707 -0
  11. data/test/coverage/assets/0.10.0/colorbox/border.png +0 -0
  12. data/test/coverage/assets/0.10.0/colorbox/controls.png +0 -0
  13. data/test/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
  14. data/test/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
  15. data/test/coverage/assets/0.10.0/favicon_green.png +0 -0
  16. data/test/coverage/assets/0.10.0/favicon_red.png +0 -0
  17. data/test/coverage/assets/0.10.0/favicon_yellow.png +0 -0
  18. data/test/coverage/assets/0.10.0/loading.gif +0 -0
  19. data/test/coverage/assets/0.10.0/magnify.png +0 -0
  20. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  21. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  22. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  23. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  24. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  25. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  26. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  27. data/test/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  28. data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
  29. data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  30. data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
  31. data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
  32. data/test/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  33. data/test/coverage/index.html +72 -0
  34. data/test/ecore_to_ruby_test.rb +73 -0
  35. data/test/metamodel_builder_test.rb +2 -2
  36. data/test/model_builder/ecore_internal.rb +12 -12
  37. data/test/rgen_test.rb +1 -0
  38. data/test/template_language_test.rb +15 -1
  39. data/test/template_language_test/templates/indent_nonl_at_eof_test/test.tpl +14 -0
  40. data/test/template_language_test/templates/indent_same_line_sub/test.tpl +16 -0
  41. data/test/testmodel/ea_testmodel_regenerated.xml +583 -583
  42. metadata +37 -7
  43. 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
+
@@ -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.6, 1.8.7 and 1.9.x
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.7.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
- def create_module(epackage)
17
- return @modules[epackage] if @modules[epackage]
18
-
19
- top = (@in_create_module == false)
20
- @in_create_module = true
21
-
22
- m = Module.new do
23
- extend RGen::MetamodelBuilder::ModuleExtension
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
- epackage.eSubpackages.each{|p| create_module(p)}
28
- m._set_ecore_internal(epackage)
52
+ mod
53
+ end
29
54
 
30
- create_module(epackage.eSuperPackage).const_set(epackage.name, m) if epackage.eSuperPackage
55
+ private
31
56
 
32
- # create classes only after all modules have been created
33
- # otherwise classes may be created multiple times
34
- if top
35
- epackage.eAllClassifiers.each do |c|
36
- if c.is_a?(RGen::ECore::EClass)
37
- create_class(c)
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
- @in_create_module = false
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
- m
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
- c = Class.new(super_class(eclass)) do
51
- abstract if eclass.abstract
52
- class << self
53
- attr_accessor :_ecore_to_ruby
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 = c
63
- c::ClassModule.module_eval do
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] = c
79
- c._set_ecore_internal(eclass)
80
- c._ecore_to_ruby = self
128
+ @classifiers[eclass] = cls
129
+ cls._set_ecore_internal(eclass)
130
+ cls._ecore_to_ruby = self
81
131
 
82
- create_module(eclass.ePackage).const_set(eclass.name, c)
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
- create_module(eenum.ePackage).const_set(eenum.name, e)
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
- include Util::NameHelper
11
+ include Util::NameHelper
12
12
 
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
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
- 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
-
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
- 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
- mod.const_get(class_name).new
57
- end
58
- end
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
- def build_class(name, mod)
61
- mod.const_set(name, Class.new(RGen::MetamodelBuilder::MMBase))
62
- end
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
- def assoc_p2c(parent, child)
69
- return unless parent.object && child.object
70
- method_name = method_name(className(child.object))
71
- build_on_error(NoMethodError, :build_p2c_assoc, parent, child, method_name) do
72
- parent.object.addGeneric(method_name, child.object)
73
- child.object.setGeneric("parent", parent.object)
74
- end
75
- end
76
-
77
- def build_p2c_assoc(parent, child, method_name)
78
- parent.object.class.has_many(method_name, child.object.class)
79
- child.object.class.has_one("parent", RGen::MetamodelBuilder::MMBase)
80
- end
81
-
82
- def set_attribute(node, attr, value)
83
- return unless node.object
84
- build_on_error(NoMethodError, :build_attribute, node, attr, value) do
85
- node.object.setGeneric(method_name(attr), value)
86
- end
87
- end
88
-
89
- def build_attribute(node, attr, value)
90
- node.object.class.has_attr(method_name(attr))
91
- end
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
- protected
94
-
95
- # Helper method for implementing classes.
96
- # This method yields the given block.
97
- # If the metamodel should be create automatically (see constructor)
98
- # rescues +error+ and calls +builder_method+ with +args+, then
99
- # yields the block again.
100
- def build_on_error(error, builder_method, *args)
101
- begin
102
- yield
103
- rescue error
104
- if @create_mm
105
- send(builder_method, *args)
106
- yield
107
- else
108
- raise
109
- end
110
- end
111
- end
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