rgen 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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