rgen 0.7.0 → 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +27 -0
  3. data/Project.yaml +21 -0
  4. data/README.rdoc +1 -1
  5. data/Rakefile +22 -25
  6. data/lib/rgen/ecore/ecore.rb +1 -1
  7. data/lib/rgen/ecore/ecore_ext.rb +9 -1
  8. data/lib/rgen/ecore/ecore_to_json.rb +188 -0
  9. data/lib/rgen/ecore/ecore_to_ruby.rb +146 -47
  10. data/lib/rgen/fragment/fragmented_model.rb +2 -0
  11. data/lib/rgen/fragment/model_fragment.rb +3 -0
  12. data/lib/rgen/instantiator/default_xml_instantiator.rb +93 -88
  13. data/lib/rgen/metamodel_builder/builder_extensions.rb +33 -9
  14. data/lib/rgen/metamodel_builder/builder_runtime.rb +12 -5
  15. data/lib/rgen/template_language/output_handler.rb +52 -19
  16. data/lib/rgen/template_language/template_container.rb +17 -7
  17. data/lib/rgen/template_language.rb +2 -1
  18. data/test/array_extensions_test.rb +7 -7
  19. data/test/ea_instantiator_test.rb +2 -2
  20. data/test/ea_serializer_test.rb +2 -2
  21. data/test/ecore_self_test.rb +2 -2
  22. data/test/ecore_to_ruby_test.rb +73 -0
  23. data/test/environment_test.rb +2 -2
  24. data/test/json_test.rb +4 -4
  25. data/test/metamodel_builder_test.rb +79 -44
  26. data/test/metamodel_from_ecore_test.rb +1 -1
  27. data/test/metamodel_order_test.rb +2 -2
  28. data/test/metamodel_roundtrip_test.rb +2 -2
  29. data/test/method_delegation_test.rb +5 -5
  30. data/test/model_builder/builder_context_test.rb +3 -3
  31. data/test/model_builder/builder_test.rb +11 -11
  32. data/test/model_builder/reference_resolver_test.rb +3 -3
  33. data/test/model_builder/serializer_test.rb +2 -2
  34. data/test/model_fragment_test.rb +2 -2
  35. data/test/output_handler_test.rb +2 -2
  36. data/test/qualified_name_provider_test.rb +2 -2
  37. data/test/qualified_name_resolver_test.rb +4 -4
  38. data/test/reference_resolver_test.rb +4 -4
  39. data/test/rgen_test.rb +2 -1
  40. data/test/template_language_test/templates/indent_nonl_at_eof_test/test.tpl +14 -0
  41. data/test/template_language_test/templates/indent_same_line_sub/test.tpl +16 -0
  42. data/test/template_language_test/templates/line_endings/mixed.tpl +6 -0
  43. data/test/template_language_test/templates/line_endings/unix.tpl +6 -0
  44. data/test/template_language_test/templates/line_endings/windows.tpl +6 -0
  45. data/test/template_language_test/templates/ws_test.tpl +21 -0
  46. data/test/template_language_test.rb +60 -9
  47. data/test/testmodel/class_model_checker.rb +17 -17
  48. data/test/testmodel/ecore_model_checker.rb +13 -13
  49. data/test/testmodel/object_model_checker.rb +6 -6
  50. data/test/transformer_test.rb +3 -3
  51. data/test/util/file_cache_map_test.rb +2 -2
  52. data/test/util/pattern_matcher_test.rb +7 -7
  53. data/test/xml_instantiator_test/simple_ecore_model_checker.rb +12 -12
  54. data/test/xml_instantiator_test.rb +8 -8
  55. metadata +93 -22
  56. data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +0 -71
  57. data/test/metamodel_roundtrip_test/houseMetamodel_Regenerated.ecore +0 -162
  58. data/test/metamodel_roundtrip_test/using_builtin_types_serialized.ecore +0 -9
  59. data/test/model_builder/ecore_internal.rb +0 -113
  60. data/test/testmodel/ea_testmodel_regenerated.xml +0 -813
  61. data/test/util/file_cache_map_test/testdir/fileA +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe212a74ff9c45d6fcd848596acb527d6def24f5
4
- data.tar.gz: 3c99d2170dab24b922a30a5a5420f03aaa05779e
3
+ metadata.gz: e58b57346e1f7e95fcaa15f29112706c911d20ed
4
+ data.tar.gz: 6551cb4e9579f7e76582018876973edd9a58d0e6
5
5
  SHA512:
6
- metadata.gz: a70a59af207fcf7d3c35c0f8785a9bcceebb370b9a0f41e07a2103bc563256acd6e5160d256c1e8c786d52f48f9e540ed62e2105348b9b9a520a57f9d0a99c0b
7
- data.tar.gz: eae33d63df0964a0175917aa7efd711306e933a4ab56fa938976a5d28eb8fc53a3e7e18e984a4c89dd134d0421418f6d86ff02a60c1e7e011620a544a62b6edd
6
+ metadata.gz: 1e82e58dd4eaf95de47ef1714a778558a6bd3cb76f8229fb43e029a98f9e03c6234ee2fab831adde1d7de1b953665afab031f27f39b0ad7a060a91c4ed7c7328
7
+ data.tar.gz: 47b73a00783a82d630b0771fb55b01c4da6adffe73a459cd35828dd5040644b8b0f6cd00a565a4abf257d8c4d2e97ca17db2c072cbe05e8ae44fe9b2b3a2637e
data/CHANGELOG CHANGED
@@ -195,3 +195,30 @@
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
+
208
+ =0.8.1
209
+
210
+ * Improved performance of ECoreToRuby
211
+ * Fixed <%ws%> command to trigger indentation if starting a new line
212
+
213
+ =0.8.2
214
+
215
+ * Added helper methods
216
+
217
+ =0.8.3
218
+
219
+ * Performance improvement: getGeneric made a lot faster
220
+
221
+ =0.8.4
222
+
223
+ * Add early loading for types which have attributes conflicting with Ruby reserved words.
224
+ * Change type checking code to use ObjectSpace to find class objects. This is to find classes with an unbound name.
data/Project.yaml ADDED
@@ -0,0 +1,21 @@
1
+ name: rgen
2
+ gemspec: rgen.gemspec
3
+ git: https://github.com/mthiede/rgen.git
4
+ version: 0.8.4
5
+ summary: Ruby Modelling and Generator Framework
6
+ email: martin dot thiede at gmx de
7
+ homepage: http://ruby-gen.org
8
+ rubyforge_project: rgen
9
+ description: RGen is a framework for Model Driven Software Development (MDSD) in Ruby. This means that it helps you build Metamodels, instantiate Models, modify and transform Models and finally generate arbitrary textual content from it.
10
+ authors: [Martin Thiede]
11
+ rdoc_options: [--main, README.rdoc, -x, test, -x, metamodels, -x, ea_support/uml13*]
12
+ extra_rdoc_files: [README.rdoc, CHANGELOG, MIT-LICENSE]
13
+ include_files: ['lib/**/*', 'test/**/*', README.rdoc, CHANGELOG, MIT-LICENSE, Rakefile]
14
+ exclude_files: ['**/*.bak']
15
+ encrypt_sources: false
16
+ dependencies:
17
+ https://rubygems.org:
18
+ - {name: nokogiri, version: ['~> 1.6.0', '>= 1.6.8.1'], development: true}
19
+ - {name: rake, version: '~> 12.0', development: true}
20
+ - {name: minitest, version: ['~> 5.0', '>= 5.10.1'], development: true}
21
+ - {name: minitest-fail-fast, version: '~> 0.1.0', development: true}
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.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
@@ -1,41 +1,38 @@
1
1
  require 'rubygems/package_task'
2
2
  require 'rdoc/task'
3
+ require 'bundler/setup'
4
+ require 'rake/testtask'
3
5
 
4
- RGenGemSpec = Gem::Specification.new do |s|
5
- s.name = %q{rgen}
6
- s.version = "0.7.0"
7
- s.date = Time.now.strftime("%Y-%m-%d")
8
- s.summary = %q{Ruby Modelling and Generator Framework}
9
- s.email = %q{martin dot thiede at gmx de}
10
- s.homepage = %q{http://ruby-gen.org}
11
- s.rubyforge_project = %q{rgen}
12
- s.description = %q{RGen is a framework for Model Driven Software Development (MDSD) in Ruby. This means that it helps you build Metamodels, instantiate Models, modify and transform Models and finally generate arbitrary textual content from it.}
13
- s.authors = ["Martin Thiede"]
14
- gemfiles = Rake::FileList.new
15
- gemfiles.include("{lib,test}/**/*")
16
- gemfiles.include("README.rdoc", "CHANGELOG", "MIT-LICENSE", "Rakefile")
17
- gemfiles.exclude(/\b\.bak\b/)
18
- s.files = gemfiles
19
- s.rdoc_options = ["--main", "README.rdoc", "-x", "test", "-x", "metamodels", "-x", "ea_support/uml13*"]
20
- s.extra_rdoc_files = ["README.rdoc", "CHANGELOG", "MIT-LICENSE"]
21
- end
6
+ RGenGemSpec = eval(File.read('rgen.gemspec'))
22
7
 
23
8
  RDoc::Task.new do |rd|
24
- rd.main = "README.rdoc"
25
- rd.rdoc_files.include("README.rdoc", "CHANGELOG", "MIT-LICENSE", "lib/**/*.rb")
26
- rd.rdoc_files.exclude("lib/metamodels/*")
27
- rd.rdoc_files.exclude("lib/ea_support/uml13*")
28
- rd.rdoc_dir = "doc"
9
+ rd.main = 'README.rdoc'
10
+ rd.rdoc_files.include('README.rdoc', 'CHANGELOG', 'MIT-LICENSE', 'lib/**/*.rb')
11
+ rd.rdoc_files.exclude('lib/metamodels/*')
12
+ rd.rdoc_files.exclude('lib/ea_support/uml13*')
13
+ rd.rdoc_dir = 'doc'
29
14
  end
30
15
 
31
16
  RGenPackageTask = Gem::PackageTask.new(RGenGemSpec) do |p|
32
17
  p.need_zip = false
33
- end
18
+ end
19
+
20
+ ::Rake::TestTask.new(:test) do |t|
21
+ t.test_files = ['test/rgen_test.rb']
22
+ t.warning = false
23
+ end
34
24
 
35
25
  task :prepare_package_rdoc => :rdoc do
36
- RGenPackageTask.package_files.include("doc/**/*")
26
+ RGenPackageTask.package_files.include('doc/**/*')
37
27
  end
38
28
 
39
29
  task :release => [:prepare_package_rdoc, :package]
40
30
 
41
31
  task :clobber => [:clobber_rdoc, :clobber_package]
32
+
33
+ task :ecore_to_json do
34
+ require 'rgen/ecore/ecore_to_json'
35
+
36
+ exporter = RGen::ECore::ECoreToJson.new
37
+ File.write('ecore.json', exporter.epackage_to_json_string(RGen.ecore, exporter.ecore_datatypes))
38
+ end
@@ -155,7 +155,7 @@ module RGen
155
155
  has_many 'eAttributes', ECore::EAttribute, :derived=>true
156
156
  has_many 'eReferences', ECore::EReference, :derived=>true
157
157
 
158
- module ClassModule
158
+ module ClassModule
159
159
  def eAllAttributes_derived
160
160
  eAttributes + eSuperTypes.eAllAttributes
161
161
  end
@@ -63,7 +63,15 @@ module RGen
63
63
  def eAllSubTypes
64
64
  eSubTypes + eSubTypes.eAllSubTypes
65
65
  end
66
+
67
+ def concrete
68
+ !(abstract || interface)
69
+ end
70
+
71
+ def isAssignableFrom(cls)
72
+ cls == self || cls.eAllSuperTypes.any? { |super_type| super_type == self }
73
+ end
66
74
 
67
- end
75
+ end
68
76
  end
69
77
  end
@@ -0,0 +1,188 @@
1
+ require 'rgen/ecore/ecore'
2
+ require 'json'
3
+
4
+ module RGen
5
+
6
+ module ECore
7
+
8
+ # ECoreToJson can turn ECore models into their JSON metamodel representations
9
+ class ECoreToJson
10
+
11
+ def initialize
12
+
13
+ end
14
+
15
+ def root_elements_to_json_string(root_elements)
16
+ JSON.pretty_generate(root_elements.map do |el|
17
+ if el.is_a?(RGen::ECore::EPackage)
18
+ epackage(el)
19
+ elsif el.is_a?(RGen::ECore::EClass)
20
+ eclass(el)
21
+ else
22
+ raise "Not implemented for #{el}"
23
+ end
24
+ end)
25
+ end
26
+
27
+ def epackage_to_json(package)
28
+ epackage(package)
29
+ end
30
+
31
+ def ecore_datatypes
32
+ [RGen::ECore::EString, RGen::ECore::EInt, RGen::ECore::ELong, RGen::ECore::EBoolean, RGen::ECore::EFloat,
33
+ RGen::ECore::ERubyObject, RGen::ECore::EJavaObject, RGen::ECore::ERubyClass, RGen::ECore::EJavaClass]
34
+ .map {|dt| edatatype(dt)}
35
+ end
36
+
37
+ def epackage_to_json_pretty_string(package, append = [])
38
+ JSON.pretty_generate([epackage_to_json(package)] + append)
39
+ end
40
+
41
+ def epackage_to_json_string(package, append = [])
42
+ JSON.generate([epackage_to_json(package)] + append)
43
+ end
44
+
45
+ def emodelelement(me)
46
+ {
47
+ :eAnnotations => me.eAnnotations.map { |e| eannotation(e) }
48
+ }
49
+ end
50
+
51
+
52
+ def enamedelement(ne)
53
+ merge(emodelelement(ne), {:name => ne.name})
54
+ end
55
+
56
+ def epackage(package)
57
+ merge(enamedelement(package), {
58
+ :_class_ref => 'RGen.ECore.EPackage',
59
+ :eClassifiers => package.eClassifiers.map do |classifier|
60
+ if classifier.is_a?(RGen::ECore::EClass)
61
+ eclass(classifier)
62
+ elsif classifier.is_a?(RGen::ECore::EEnum)
63
+ eenum(classifier)
64
+ else
65
+ edatatype(classifier)
66
+ end
67
+ end,
68
+ :eSubpackages => package.eSubpackages.map { |sp| epackage(sp) },
69
+ :nsURI => package.nsURI,
70
+ :nsPrefix => package.nsPrefix
71
+ })
72
+ end
73
+
74
+ def eclassifier(classifier)
75
+ enamedelement(classifier).merge({
76
+ # omit :instanceClassName => classifier.instanceClassName
77
+ })
78
+ end
79
+
80
+ def eclass(_class)
81
+ merge(eclassifier(_class), {
82
+ :_class_ref => 'RGen.ECore.EClass',
83
+ :abstract => _class.abstract,
84
+ :interface => _class.interface,
85
+ :eStructuralFeatures => _class.eStructuralFeatures.map do |sf|
86
+ if sf.is_a?(RGen::ECore::EReference)
87
+ ereference(sf)
88
+ else
89
+ eattribute(sf)
90
+ end
91
+ end,
92
+ :eSuperTypes => _class.eSuperTypes.map { |st| {:_ref => ref_id(st)} }
93
+ })
94
+ end
95
+
96
+ def edatatype(_datatype)
97
+ merge(eclassifier(_datatype), {
98
+ :_class_ref => 'RGen.ECore.EDataType',
99
+ :serializable => _datatype.serializable,
100
+ :instanceClassName => _datatype.instanceClassName
101
+ })
102
+ end
103
+
104
+ def eenum(enum)
105
+ merge(edatatype(enum), {
106
+ :_class_ref => 'RGen.ECore.EEnum',
107
+ :eLiterals => enum.eLiterals.map do |l|
108
+ merge({}, {
109
+ :_class_ref => 'RGen.ECore.EEnumLiteral',
110
+ :value => l.value,
111
+ :literal => l.literal
112
+ })
113
+ end
114
+ })
115
+ end
116
+
117
+ def eannotation(e)
118
+ merge(emodelelement(e), {
119
+ :source => e.source,
120
+ :details => e.details.map do |d|
121
+ merge({}, {
122
+ :_class_ref => 'RGen.ECore.EStringToStringMapEntry',
123
+ :key => d.key,
124
+ :value => d.value
125
+ })
126
+ end
127
+ })
128
+ end
129
+
130
+ def etypedelement(te)
131
+ merge(enamedelement(te), {
132
+ :ordered => te.ordered,
133
+ :unique => te.unique,
134
+ :lowerBound => te.lowerBound,
135
+ :upperBound => te.upperBound,
136
+ :many => te.many,
137
+ :required => te.required,
138
+ :eType => {:_ref => te.eType ? ref_id(te.eType) : nil}
139
+ })
140
+ end
141
+
142
+ def estructuralfeature(sf)
143
+ merge(etypedelement(sf), {
144
+ :changeable => sf.changeable,
145
+ :volatile => sf.volatile,
146
+ :transient => sf.transient,
147
+ :defaultValueLiteral => sf.defaultValueLiteral,
148
+ :unsettable => sf.unsettable,
149
+ :derived => sf.derived,
150
+ })
151
+ end
152
+
153
+ def eattribute(attr)
154
+ merge(estructuralfeature(attr), {
155
+ :_class_ref => 'RGen.ECore.EAttribute',
156
+ :iD => attr.iD
157
+ })
158
+ end
159
+
160
+ def ereference(ref)
161
+ merge(estructuralfeature(ref), {
162
+ :_class_ref => 'RGen.ECore.EReference',
163
+ :containment => ref.containment,
164
+ :resolveProxies => ref.resolveProxies,
165
+ :eOpposite => ref.eOpposite ? {:_ref => "#{ref_id(ref.eOpposite.eContainer)}.#{ref.eOpposite.name}"} : nil
166
+ })
167
+ end
168
+
169
+ def ref_id(obj)
170
+ res = ref_parts(obj)
171
+ res.join('.')
172
+ end
173
+
174
+ def ref_parts(obj)
175
+ return [obj.name] unless obj&.eContainer
176
+ ref_parts(obj.eContainer) << obj.name
177
+ end
178
+
179
+ def merge(hash, values)
180
+ values.each { |k, v| hash[k] = v unless v.nil? }
181
+ hash
182
+ end
183
+
184
+ end
185
+
186
+ end
187
+
188
+ end
@@ -1,66 +1,131 @@
1
+ require 'set'
1
2
  require 'rgen/ecore/ecore'
2
3
 
3
4
  module RGen
4
5
 
5
6
  module ECore
6
7
 
8
+ # ECoreToRuby can turn ECore models into their Ruby metamodel representations
7
9
  class ECoreToRuby
8
10
 
9
11
  def initialize
10
12
  @modules = {}
11
13
  @classifiers = {}
12
14
  @features_added = {}
13
- @in_create_module = false
15
+ @reserved = Set.new(Object.methods)
14
16
  end
15
17
 
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
24
- end
25
- @modules[epackage] = m
26
-
27
- epackage.eSubpackages.each{|p| create_module(p)}
28
- m._set_ecore_internal(epackage)
29
-
30
- create_module(epackage.eSuperPackage).const_set(epackage.name, m) if epackage.eSuperPackage
18
+ # Create a Ruby module representing +epackage+.
19
+ # This includes all nested modules/packages, classes and enums.
20
+ #
21
+ # If a parent module is provided with the "under" parameter,
22
+ # the new module will be nested under the parent module.
23
+ #
24
+ # If the parent module has a non-temporary name,
25
+ # (more precisely: a non-temporary classpath) i.e. if it is reachable
26
+ # via a path of constant names from the root, then the nested
27
+ # modules and classes will also have non-temporary names.
28
+ # In particular, this means that they will keep their names even
29
+ # if they are assigned to new constants.
30
+ #
31
+ # If no parent module is provided or the parent module has a
32
+ # temporary name by itself, then the nested modules and classes will
33
+ # also have temporary names. This means that their name will stay
34
+ # 'volatile' until they are assigned to constants reachable from
35
+ # the root and the Module#name method is called for the first time.
36
+ #
37
+ # While the second approach is more flexible, it can come with a major
38
+ # performance impact. The reason is that Ruby searches the space of
39
+ # all known non-temporary classes/modules every time the name
40
+ # of a class/module with a temporary name is queried.
41
+ #
42
+ def create_module(epackage, under=Module.new)
43
+ with_empty_constant_order_helper do
44
+ temp = under.to_s.start_with?("#")
45
+ mod = create_module_internal(epackage, under, temp)
31
46
 
32
- # create classes only after all modules have been created
33
- # otherwise classes may be created multiple times
34
- if top
35
47
  epackage.eAllClassifiers.each do |c|
36
48
  if c.is_a?(RGen::ECore::EClass)
37
- create_class(c)
49
+ create_class(c, temp)
38
50
  elsif c.is_a?(RGen::ECore::EEnum)
39
51
  create_enum(c)
40
52
  end
41
53
  end
42
- @in_create_module = false
54
+
55
+ load_classes_with_reserved_keywords(epackage)
56
+ mod
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def load_classes_with_reserved_keywords(epackage)
63
+ epackage.eAllClassifiers.each do |eclass|
64
+ # we early load classes which have ruby reserved keywords
65
+ if eclass.is_a?(RGen::ECore::EClass)
66
+ reserved_used = eclass.eStructuralFeatures.any? { |f| @reserved.include?(f.name.to_sym) }
67
+ add_features(eclass) if reserved_used
68
+ end
43
69
  end
44
- m
45
70
  end
46
71
 
47
- def create_class(eclass)
72
+ def create_module_internal(epackage, under, temp)
73
+ return @modules[epackage] if @modules[epackage]
74
+
75
+ if temp
76
+ mod = Module.new do
77
+ extend RGen::MetamodelBuilder::ModuleExtension
78
+ end
79
+ under.const_set(epackage.name, mod)
80
+ else
81
+ under.module_eval <<-END
82
+ module #{epackage.name}
83
+ extend RGen::MetamodelBuilder::ModuleExtension
84
+ end
85
+ END
86
+ mod = under.const_get(epackage.name)
87
+ end
88
+ @modules[epackage] = mod
89
+
90
+ epackage.eSubpackages.each{|p| create_module_internal(p, mod, temp)}
91
+ mod._set_ecore_internal(epackage)
92
+
93
+ mod
94
+ end
95
+
96
+ def create_class(eclass, temp)
48
97
  return @classifiers[eclass] if @classifiers[eclass]
49
98
 
50
- c = Class.new(super_class(eclass)) do
51
- abstract if eclass.abstract
52
- class << self
53
- attr_accessor :_ecore_to_ruby
99
+ mod = @modules[eclass.ePackage]
100
+ if temp
101
+ cls = Class.new(super_class(eclass, temp)) do
102
+ abstract if eclass.abstract
103
+ class << self
104
+ attr_accessor :_ecore_to_ruby
105
+ end
54
106
  end
107
+ mod.const_set(eclass.name, cls)
108
+ else
109
+ mod.module_eval <<-END
110
+ class #{eclass.name} < #{super_class(eclass, temp)}
111
+ #{eclass.abstract ? 'abstract' : ''}
112
+ class << self
113
+ attr_accessor :_ecore_to_ruby
114
+ end
115
+ end
116
+ END
117
+ cls = mod.const_get(eclass.name)
55
118
  end
119
+
56
120
  class << eclass
57
121
  attr_accessor :instanceClass
58
122
  def instanceClassName
59
123
  instanceClass.to_s
60
124
  end
61
125
  end
62
- eclass.instanceClass = c
63
- c::ClassModule.module_eval do
126
+ eclass.instanceClass = cls
127
+
128
+ cls::ClassModule.module_eval do
64
129
  alias _method_missing method_missing
65
130
  def method_missing(m, *args)
66
131
  if self.class._ecore_to_ruby.add_features(self.class.ecore)
@@ -75,12 +140,11 @@ class ECoreToRuby
75
140
  _respond_to(m)
76
141
  end
77
142
  end
78
- @classifiers[eclass] = c
79
- c._set_ecore_internal(eclass)
80
- c._ecore_to_ruby = self
143
+ @classifiers[eclass] = cls
144
+ cls._set_ecore_internal(eclass)
145
+ cls._ecore_to_ruby = self
81
146
 
82
- create_module(eclass.ePackage).const_set(eclass.name, c)
83
- c
147
+ cls
84
148
  end
85
149
 
86
150
  def create_enum(eenum)
@@ -89,7 +153,7 @@ class ECoreToRuby
89
153
  e = RGen::MetamodelBuilder::DataTypes::Enum.new(eenum.eLiterals.collect{|l| l.name.to_sym})
90
154
  @classifiers[eenum] = e
91
155
 
92
- create_module(eenum.ePackage).const_set(eenum.name, e)
156
+ @modules[eenum.ePackage].const_set(eenum.name, e)
93
157
  e
94
158
  end
95
159
 
@@ -126,6 +190,53 @@ class ECoreToRuby
126
190
  end
127
191
  end
128
192
 
193
+ def super_class(eclass, temp)
194
+ super_types = eclass.eSuperTypes
195
+ if temp
196
+ case super_types.size
197
+ when 0
198
+ RGen::MetamodelBuilder::MMBase
199
+ when 1
200
+ create_class(super_types.first, temp)
201
+ else
202
+ RGen::MetamodelBuilder::MMMultiple(*super_types.collect{|t| create_class(t, temp)})
203
+ end
204
+ else
205
+ case super_types.size
206
+ when 0
207
+ "RGen::MetamodelBuilder::MMBase"
208
+ when 1
209
+ create_class(super_types.first, temp).name
210
+ else
211
+ "RGen::MetamodelBuilder::MMMultiple(" +
212
+ super_types.collect{|t| create_class(t, temp).name}.join(",") + ")"
213
+ end
214
+ end
215
+ end
216
+
217
+ class EmptyConstantOrderHelper
218
+ def classCreated(c); end
219
+ def moduleCreated(m); end
220
+ def enumCreated(e); end
221
+ end
222
+
223
+ def with_empty_constant_order_helper
224
+ orig_coh = RGen::MetamodelBuilder::ConstantOrderHelper
225
+ RGen::MetamodelBuilder.instance_eval { remove_const(:ConstantOrderHelper) }
226
+ RGen::MetamodelBuilder.const_set(:ConstantOrderHelper, EmptyConstantOrderHelper.new)
227
+
228
+ begin
229
+ result = yield
230
+ ensure
231
+ RGen::MetamodelBuilder.instance_eval { remove_const(:ConstantOrderHelper) }
232
+ RGen::MetamodelBuilder.const_set(:ConstantOrderHelper, orig_coh)
233
+ end
234
+
235
+ result
236
+ end
237
+
238
+ public
239
+
129
240
  def add_features(eclass)
130
241
  return false if @features_added[eclass]
131
242
  c = @classifiers[eclass]
@@ -147,18 +258,6 @@ class ECoreToRuby
147
258
  true
148
259
  end
149
260
 
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
261
  end
163
262
 
164
263
  end
@@ -111,6 +111,8 @@ class FragmentedModel
111
111
  # This is a Hash mapping identifiers to model elements accessible via the identifier.
112
112
  #
113
113
  def index
114
+ # Invalidate the cache when any fragment's local index changes.
115
+ # Assumption: If the local index content changes, there is a new index object.
114
116
  fragments.each do |f|
115
117
  if !@fragment_index[f] || (@fragment_index[f].object_id != f.index.object_id)
116
118
  @fragment_index[f] = f.index
@@ -117,6 +117,9 @@ class ModelFragment
117
117
  end
118
118
 
119
119
  # Returns the index of the element contained in this fragment.
120
+ #
121
+ # FragmentedModel's index caching depends on the fact that any change
122
+ # of a fragment's index contents implies a new index object.
120
123
  #
121
124
  def index
122
125
  build_index unless @index