rgen 0.5.4 → 0.6.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 +28 -0
- data/Rakefile +3 -4
- data/lib/ea_support/uml13_ea_metamodel.rb +3 -3
- data/lib/ea_support/uml13_ea_to_uml13.rb +33 -2
- data/lib/ea_support/uml13_to_uml13_ea.rb +7 -0
- data/lib/mmgen/mm_ext/ecore_mmgen_ext.rb +4 -4
- data/lib/mmgen/templates/metamodel_generator.tpl +143 -143
- data/lib/rgen/ecore/ecore.rb +11 -1
- data/lib/rgen/ecore/ecore_interface.rb +47 -0
- data/lib/rgen/ecore/ecore_to_ruby.rb +166 -0
- data/lib/rgen/ecore/{ecore_transformer.rb → ruby_to_ecore.rb} +11 -11
- data/lib/rgen/environment.rb +15 -2
- data/lib/rgen/fragment/dump_file_cache.rb +63 -0
- data/lib/rgen/fragment/fragmented_model.rb +139 -0
- data/lib/rgen/fragment/model_fragment.rb +268 -0
- data/lib/rgen/instantiator/abstract_xml_instantiator.rb +44 -72
- data/lib/rgen/instantiator/default_xml_instantiator.rb +2 -2
- data/lib/rgen/instantiator/ecore_xml_instantiator.rb +16 -1
- data/lib/rgen/instantiator/json_instantiator.rb +16 -2
- data/lib/rgen/instantiator/nodebased_xml_instantiator.rb +118 -138
- data/lib/rgen/instantiator/qualified_name_resolver.rb +5 -1
- data/lib/rgen/instantiator/reference_resolver.rb +126 -24
- data/lib/rgen/instantiator/xmi11_instantiator.rb +6 -2
- data/lib/rgen/metamodel_builder.rb +18 -6
- data/lib/rgen/metamodel_builder/builder_extensions.rb +431 -407
- data/lib/rgen/metamodel_builder/builder_runtime.rb +8 -8
- data/lib/rgen/metamodel_builder/constant_order_helper.rb +4 -4
- data/lib/rgen/metamodel_builder/data_types.rb +5 -1
- data/lib/rgen/metamodel_builder/intermediate/feature.rb +167 -0
- data/lib/rgen/metamodel_builder/module_extension.rb +2 -2
- data/lib/rgen/model_builder.rb +10 -5
- data/lib/rgen/model_builder/builder_context.rb +17 -1
- data/lib/rgen/serializer/opposite_reference_filter.rb +18 -0
- data/lib/rgen/serializer/qualified_name_provider.rb +45 -0
- data/lib/rgen/template_language/template_container.rb +3 -1
- data/lib/rgen/{auto_class_creator.rb → util/auto_class_creator.rb} +6 -1
- data/lib/rgen/util/cached_glob.rb +67 -0
- data/lib/rgen/util/file_cache_map.rb +104 -0
- data/lib/rgen/util/file_change_detector.rb +78 -0
- data/lib/rgen/{method_delegation.rb → util/method_delegation.rb} +18 -3
- data/lib/rgen/{model_comparator.rb → util/model_comparator.rb} +17 -5
- data/lib/rgen/{model_comparator_base.rb → util/model_comparator_base.rb} +6 -1
- data/lib/rgen/{model_dumper.rb → util/model_dumper.rb} +6 -1
- data/lib/rgen/{name_helper.rb → util/name_helper.rb} +6 -1
- data/lib/rgen/util/pattern_matcher.rb +329 -0
- data/lib/transformers/uml13_to_ecore.rb +103 -60
- data/test/ecore_self_test.rb +43 -42
- data/test/json_test.rb +15 -0
- data/test/metamodel_builder_test.rb +361 -206
- data/test/metamodel_from_ecore_test.rb +45 -0
- data/test/metamodel_order_test.rb +10 -4
- data/test/metamodel_roundtrip_test.rb +2 -2
- data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +1 -1
- data/test/metamodel_roundtrip_test/houseMetamodel_Regenerated.ecore +50 -50
- data/test/method_delegation_test.rb +9 -9
- data/test/model_builder/ecore_internal.rb +19 -9
- data/test/model_builder/serializer_test.rb +1 -1
- data/test/reference_resolver_test.rb +79 -12
- data/test/rgen_test.rb +2 -0
- data/test/template_language_test.rb +7 -0
- data/test/template_language_test/templates/callback_indent_test/a.tpl +12 -0
- data/test/template_language_test/templates/callback_indent_test/b.tpl +5 -0
- data/test/testmodel/ea_testmodel_regenerated.xml +588 -583
- data/test/transformer_test.rb +3 -3
- data/test/util/file_cache_map_test.rb +91 -0
- data/test/util/file_cache_map_test/testdir/fileA +1 -0
- data/test/util_test.rb +4 -0
- data/test/xml_instantiator_test.rb +139 -135
- metadata +49 -104
- data/lib/rgen/ecore/ecore_instantiator.rb +0 -31
- data/lib/rgen/metamodel_builder/metamodel_description.rb +0 -232
- data/redist/xmlscan/ChangeLog +0 -1301
- data/redist/xmlscan/README +0 -34
- data/redist/xmlscan/THANKS +0 -11
- data/redist/xmlscan/doc/changes.html +0 -74
- data/redist/xmlscan/doc/changes.rd +0 -80
- data/redist/xmlscan/doc/en/conformance.html +0 -136
- data/redist/xmlscan/doc/en/conformance.rd +0 -152
- data/redist/xmlscan/doc/en/manual.html +0 -356
- data/redist/xmlscan/doc/en/manual.rd +0 -402
- data/redist/xmlscan/doc/ja/conformance.ja.html +0 -118
- data/redist/xmlscan/doc/ja/conformance.ja.rd +0 -134
- data/redist/xmlscan/doc/ja/manual.ja.html +0 -325
- data/redist/xmlscan/doc/ja/manual.ja.rd +0 -370
- data/redist/xmlscan/doc/src/Makefile +0 -41
- data/redist/xmlscan/doc/src/conformance.rd.src +0 -256
- data/redist/xmlscan/doc/src/langsplit.rb +0 -110
- data/redist/xmlscan/doc/src/manual.rd.src +0 -614
- data/redist/xmlscan/install.rb +0 -41
- data/redist/xmlscan/lib/xmlscan/encoding.rb +0 -311
- data/redist/xmlscan/lib/xmlscan/htmlscan.rb +0 -289
- data/redist/xmlscan/lib/xmlscan/namespace.rb +0 -352
- data/redist/xmlscan/lib/xmlscan/parser.rb +0 -299
- data/redist/xmlscan/lib/xmlscan/scanner.rb +0 -1109
- data/redist/xmlscan/lib/xmlscan/version.rb +0 -22
- data/redist/xmlscan/lib/xmlscan/visitor.rb +0 -158
- data/redist/xmlscan/lib/xmlscan/xmlchar.rb +0 -441
- data/redist/xmlscan/memo/CONFORMANCE +0 -1249
- data/redist/xmlscan/memo/PRODUCTIONS +0 -195
- data/redist/xmlscan/memo/contentspec.ry +0 -335
- data/redist/xmlscan/samples/chibixml.rb +0 -105
- data/redist/xmlscan/samples/getxmlchar.rb +0 -122
- data/redist/xmlscan/samples/rexml.rb +0 -159
- data/redist/xmlscan/samples/xmlbench.rb +0 -88
- data/redist/xmlscan/samples/xmlbench/parser/chibixml.rb +0 -22
- data/redist/xmlscan/samples/xmlbench/parser/nqxml.rb +0 -29
- data/redist/xmlscan/samples/xmlbench/parser/rexml.rb +0 -62
- data/redist/xmlscan/samples/xmlbench/parser/xmlparser.rb +0 -22
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan-0.0.10.rb +0 -62
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan-chibixml.rb +0 -22
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan-rexml.rb +0 -22
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan.rb +0 -99
- data/redist/xmlscan/samples/xmlbench/xmlbench-lib.rb +0 -116
- data/redist/xmlscan/samples/xmlconftest.rb +0 -200
- data/redist/xmlscan/test.rb +0 -7
- data/redist/xmlscan/tests/deftestcase.rb +0 -73
- data/redist/xmlscan/tests/runtest.rb +0 -47
- data/redist/xmlscan/tests/testall.rb +0 -14
- data/redist/xmlscan/tests/testencoding.rb +0 -438
- data/redist/xmlscan/tests/testhtmlscan.rb +0 -752
- data/redist/xmlscan/tests/testnamespace.rb +0 -457
- data/redist/xmlscan/tests/testparser.rb +0 -591
- data/redist/xmlscan/tests/testscanner.rb +0 -1749
- data/redist/xmlscan/tests/testxmlchar.rb +0 -143
- data/redist/xmlscan/tests/visitor.rb +0 -34
data/lib/rgen/ecore/ecore.rb
CHANGED
|
@@ -93,6 +93,14 @@ module RGen
|
|
|
93
93
|
class EDataType < EClassifier
|
|
94
94
|
has_attr 'serializable', Boolean
|
|
95
95
|
end
|
|
96
|
+
|
|
97
|
+
class EGenericType < EDataType
|
|
98
|
+
has_one 'eClassifier', EDataType
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
class ETypeArgument < EModelElement
|
|
102
|
+
has_one 'eClassifier', EDataType
|
|
103
|
+
end
|
|
96
104
|
|
|
97
105
|
class EEnum < EDataType
|
|
98
106
|
end
|
|
@@ -173,7 +181,7 @@ module RGen
|
|
|
173
181
|
|
|
174
182
|
EString = EDataType.new(:name => "EString", :instanceClassName => "String")
|
|
175
183
|
EInt = EDataType.new(:name => "EInt", :instanceClassName => "Integer")
|
|
176
|
-
EBoolean = EDataType.new(:name => "EBoolean", :instanceClassName => "
|
|
184
|
+
EBoolean = EDataType.new(:name => "EBoolean", :instanceClassName => "Boolean")
|
|
177
185
|
EFloat = EDataType.new(:name => "EFloat", :instanceClassName => "Float")
|
|
178
186
|
ERubyObject = EDataType.new(:name => "ERubyObject", :instanceClassName => "Object")
|
|
179
187
|
EJavaObject = EDataType.new(:name => "EJavaObject")
|
|
@@ -200,5 +208,7 @@ module RGen
|
|
|
200
208
|
|
|
201
209
|
ECore::EAttribute.has_one 'eAttributeType', ECore::EDataType, :lowerBound=>1, :derived=>true
|
|
202
210
|
ECore::EReference.has_one 'eReferenceType', ECore::EClass, :lowerBound=>1, :derived=>true
|
|
211
|
+
ECore::EParameter.contains_one 'eGenericType', ECore::EGenericType, 'eParameter'
|
|
212
|
+
ECore::EGenericType.contains_many 'eTypeArguments', ECore::ETypeArgument, 'eGenericType'
|
|
203
213
|
|
|
204
214
|
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module RGen
|
|
2
|
+
|
|
3
|
+
module ECore
|
|
4
|
+
|
|
5
|
+
# Mixin to provide access to the ECore model describing a Ruby class or module
|
|
6
|
+
# built using MetamodelBuilder.
|
|
7
|
+
# The module should be used to +extend+ a class or module, i.e. to make its
|
|
8
|
+
# methods class methods.
|
|
9
|
+
#
|
|
10
|
+
module ECoreInterface
|
|
11
|
+
|
|
12
|
+
# This method will lazily build to ECore model element belonging to the calling
|
|
13
|
+
# class or module using RubyToECore.
|
|
14
|
+
# Alternatively, the ECore model element can be provided up front. This is used
|
|
15
|
+
# when the Ruby metamodel classes and modules are created from ECore.
|
|
16
|
+
#
|
|
17
|
+
def ecore
|
|
18
|
+
if defined?(@ecore)
|
|
19
|
+
@ecore
|
|
20
|
+
else
|
|
21
|
+
unless defined?(@@transformer)
|
|
22
|
+
require 'rgen/ecore/ruby_to_ecore'
|
|
23
|
+
@@transformer = RubyToECore.new
|
|
24
|
+
end
|
|
25
|
+
@@transformer.trans(self)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# This method can be used to clear the ecore cache after the metamodel classes
|
|
30
|
+
# or modules have been changed; the ecore model will be recreated on next access
|
|
31
|
+
# to the +ecore+ method
|
|
32
|
+
# Beware, the ecore cache is global, i.e. for all metamodels.
|
|
33
|
+
#
|
|
34
|
+
def self.clear_ecore_cache
|
|
35
|
+
require 'rgen/ecore/ruby_to_ecore'
|
|
36
|
+
@@transformer = RubyToECore.new
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def _set_ecore_internal(ecore) # :nodoc:
|
|
40
|
+
@ecore = ecore
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
require 'rgen/ecore/ecore'
|
|
2
|
+
|
|
3
|
+
module RGen
|
|
4
|
+
|
|
5
|
+
module ECore
|
|
6
|
+
|
|
7
|
+
class ECoreToRuby
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@modules = {}
|
|
11
|
+
@classifiers = {}
|
|
12
|
+
@features_added = {}
|
|
13
|
+
@in_create_module = false
|
|
14
|
+
end
|
|
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
|
|
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
|
|
31
|
+
|
|
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
|
|
41
|
+
end
|
|
42
|
+
@in_create_module = false
|
|
43
|
+
end
|
|
44
|
+
m
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def create_class(eclass)
|
|
48
|
+
return @classifiers[eclass] if @classifiers[eclass]
|
|
49
|
+
|
|
50
|
+
c = Class.new(super_class(eclass)) do
|
|
51
|
+
abstract if eclass.abstract
|
|
52
|
+
class << self
|
|
53
|
+
attr_accessor :_ecore_to_ruby
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
class << eclass
|
|
57
|
+
attr_accessor :instanceClass
|
|
58
|
+
def instanceClassName
|
|
59
|
+
instanceClass.to_s
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
eclass.instanceClass = c
|
|
63
|
+
c::ClassModule.module_eval do
|
|
64
|
+
alias _method_missing method_missing
|
|
65
|
+
def method_missing(m, *args)
|
|
66
|
+
if self.class._ecore_to_ruby.add_features(self.class.ecore)
|
|
67
|
+
send(m, *args)
|
|
68
|
+
else
|
|
69
|
+
_method_missing(m, *args)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
alias _respond_to respond_to?
|
|
73
|
+
def respond_to?(m)
|
|
74
|
+
self.class._ecore_to_ruby.add_features(self.class.ecore)
|
|
75
|
+
_respond_to(m)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
@classifiers[eclass] = c
|
|
79
|
+
c._set_ecore_internal(eclass)
|
|
80
|
+
c._ecore_to_ruby = self
|
|
81
|
+
|
|
82
|
+
create_module(eclass.ePackage).const_set(eclass.name, c)
|
|
83
|
+
c
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def create_enum(eenum)
|
|
87
|
+
return @classifiers[eenum] if @classifiers[eenum]
|
|
88
|
+
|
|
89
|
+
e = RGen::MetamodelBuilder::DataTypes::Enum.new(eenum.eLiterals.collect{|l| l.name.to_sym})
|
|
90
|
+
@classifiers[eenum] = e
|
|
91
|
+
|
|
92
|
+
create_module(eenum.ePackage).const_set(eenum.name, e)
|
|
93
|
+
e
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
class FeatureWrapper
|
|
97
|
+
def initialize(efeature, classifiers)
|
|
98
|
+
@efeature = efeature
|
|
99
|
+
@classifiers = classifiers
|
|
100
|
+
end
|
|
101
|
+
def value(prop)
|
|
102
|
+
@efeature.send(prop)
|
|
103
|
+
end
|
|
104
|
+
def many
|
|
105
|
+
@efeature.many
|
|
106
|
+
end
|
|
107
|
+
def reference?
|
|
108
|
+
@efeature.is_a?(RGen::ECore::EReference)
|
|
109
|
+
end
|
|
110
|
+
def opposite
|
|
111
|
+
@efeature.eOpposite
|
|
112
|
+
end
|
|
113
|
+
def impl_type
|
|
114
|
+
etype = @efeature.eType
|
|
115
|
+
if etype.is_a?(RGen::ECore::EClass) || etype.is_a?(RGen::ECore::EEnum)
|
|
116
|
+
@classifiers[etype]
|
|
117
|
+
else
|
|
118
|
+
ic = etype.instanceClass
|
|
119
|
+
if ic
|
|
120
|
+
ic
|
|
121
|
+
else
|
|
122
|
+
raise "unknown type: #{etype.name}"
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def add_features(eclass)
|
|
129
|
+
return false if @features_added[eclass]
|
|
130
|
+
c = @classifiers[eclass]
|
|
131
|
+
eclass.eStructuralFeatures.each do |f|
|
|
132
|
+
w1 = FeatureWrapper.new(f, @classifiers)
|
|
133
|
+
w2 = FeatureWrapper.new(f.eOpposite, @classifiers) if f.is_a?(RGen::ECore::EReference) && f.eOpposite
|
|
134
|
+
c.module_eval do
|
|
135
|
+
if w1.many
|
|
136
|
+
_build_many_methods(w1, w2)
|
|
137
|
+
else
|
|
138
|
+
_build_one_methods(w1, w2)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
@features_added[eclass] = true
|
|
143
|
+
eclass.eSuperTypes.each do |t|
|
|
144
|
+
add_features(t)
|
|
145
|
+
end
|
|
146
|
+
true
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def super_class(eclass)
|
|
150
|
+
super_types = eclass.eSuperTypes
|
|
151
|
+
case super_types.size
|
|
152
|
+
when 0
|
|
153
|
+
RGen::MetamodelBuilder::MMBase
|
|
154
|
+
when 1
|
|
155
|
+
create_class(super_types.first)
|
|
156
|
+
else
|
|
157
|
+
RGen::MetamodelBuilder::MMMultiple(*super_types.collect{|t| create_class(t)})
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
end
|
|
166
|
+
|
|
@@ -8,7 +8,7 @@ module ECore
|
|
|
8
8
|
# This transformer creates an ECore model from Ruby classes built
|
|
9
9
|
# by RGen::MetamodelBuilder.
|
|
10
10
|
#
|
|
11
|
-
class
|
|
11
|
+
class RubyToECore < Transformer
|
|
12
12
|
|
|
13
13
|
transform Class, :to => EClass, :if => :convert? do
|
|
14
14
|
{ :name => name.gsub(/.*::(\w+)$/,'\1'),
|
|
@@ -31,13 +31,13 @@ class ECoreTransformer < Transformer
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
transform Module, :to => EPackage, :if => :convert? do
|
|
34
|
-
|
|
34
|
+
@enumParentModule ||= {}
|
|
35
35
|
_constants = _constantOrder + (constants - _constantOrder)
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
_constants.select {|c| const_get(c).is_a?(MetamodelBuilder::DataTypes::Enum)}.
|
|
37
|
+
each {|c| @enumParentModule[const_get(c)] = @current_object}
|
|
38
38
|
{ :name => name.gsub(/.*::(\w+)$/,'\1'),
|
|
39
39
|
:eClassifiers => trans(_constants.collect{|c| const_get(c)}.select{|c| c.is_a?(Class) ||
|
|
40
|
-
|
|
40
|
+
(c.is_a?(MetamodelBuilder::DataTypes::Enum) && c != MetamodelBuilder::DataTypes::Boolean) }),
|
|
41
41
|
:eSuperPackage => trans(name =~ /(.*)::\w+$/ ? eval($1) : nil),
|
|
42
42
|
:eSubpackages => trans(_constants.collect{|c| const_get(c)}.select{|c| c.is_a?(Module) && !c.is_a?(Class)}),
|
|
43
43
|
:eAnnotations => trans(_annotations)
|
|
@@ -48,15 +48,15 @@ class ECoreTransformer < Transformer
|
|
|
48
48
|
@current_object.respond_to?(:ecore) && @current_object != RGen::MetamodelBuilder::MMBase
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
transform MetamodelBuilder::
|
|
52
|
-
Hash[*MetamodelBuilder::
|
|
51
|
+
transform MetamodelBuilder::Intermediate::Attribute, :to => EAttribute do
|
|
52
|
+
Hash[*MetamodelBuilder::Intermediate::Attribute.properties.collect{|p| [p, value(p)]}.flatten].merge({
|
|
53
53
|
:eType => (etype == :EEnumerable ? trans(impl_type) : RGen::ECore.const_get(etype)),
|
|
54
54
|
:eAnnotations => trans(annotations)
|
|
55
55
|
})
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
transform MetamodelBuilder::
|
|
59
|
-
Hash[*MetamodelBuilder::
|
|
58
|
+
transform MetamodelBuilder::Intermediate::Reference, :to => EReference do
|
|
59
|
+
Hash[*MetamodelBuilder::Intermediate::Reference.properties.collect{|p| [p, value(p)]}.flatten].merge({
|
|
60
60
|
:eType => trans(impl_type),
|
|
61
61
|
:eOpposite => trans(opposite),
|
|
62
62
|
:eAnnotations => trans(annotations)
|
|
@@ -66,7 +66,7 @@ class ECoreTransformer < Transformer
|
|
|
66
66
|
transform MetamodelBuilder::Intermediate::Annotation, :to => EAnnotation do
|
|
67
67
|
{ :source => source,
|
|
68
68
|
:details => details.keys.collect do |k|
|
|
69
|
-
e = EStringToStringMapEntry.new
|
|
69
|
+
e = RGen::ECore::EStringToStringMapEntry.new
|
|
70
70
|
e.key = k
|
|
71
71
|
e.value = details[k]
|
|
72
72
|
e
|
|
@@ -78,7 +78,7 @@ class ECoreTransformer < Transformer
|
|
|
78
78
|
{ :name => name,
|
|
79
79
|
:instanceClassName => @enumParentModule && @enumParentModule[@current_object] && @enumParentModule[@current_object].name+"::"+name,
|
|
80
80
|
:eLiterals => literals.collect do |l|
|
|
81
|
-
lit = EEnumLiteral.new
|
|
81
|
+
lit = RGen::ECore::EEnumLiteral.new
|
|
82
82
|
lit.name = l.to_s
|
|
83
83
|
lit
|
|
84
84
|
end }
|
data/lib/rgen/environment.rb
CHANGED
|
@@ -8,6 +8,8 @@ class Environment
|
|
|
8
8
|
@elements = {}
|
|
9
9
|
@subClasses = {}
|
|
10
10
|
@subClassesUpdated = {}
|
|
11
|
+
@deleted = {}
|
|
12
|
+
@deletedClasses = {}
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
# Add a model element. Returns the environment so <code><<</code> can be chained.
|
|
@@ -22,19 +24,21 @@ class Environment
|
|
|
22
24
|
|
|
23
25
|
# Removes model element from environment.
|
|
24
26
|
def delete(el)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
@deleted[el] = true
|
|
28
|
+
@deletedClasses[el.class] = true
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
# Iterates each element
|
|
30
32
|
#
|
|
31
33
|
def each(&b)
|
|
34
|
+
removeDeleted
|
|
32
35
|
@elements.values.flatten.each(&b)
|
|
33
36
|
end
|
|
34
37
|
|
|
35
38
|
# Return the elements of the environment as an array
|
|
36
39
|
#
|
|
37
40
|
def elements
|
|
41
|
+
removeDeleted
|
|
38
42
|
@elements.values.flatten
|
|
39
43
|
end
|
|
40
44
|
|
|
@@ -57,6 +61,7 @@ class Environment
|
|
|
57
61
|
# class. In this case an array of possible classes can optionally be given.
|
|
58
62
|
#
|
|
59
63
|
def find(desc)
|
|
64
|
+
removeDeleted
|
|
60
65
|
result = []
|
|
61
66
|
classes = desc[:class] if desc[:class] and desc[:class].is_a?(Array)
|
|
62
67
|
classes = [ desc[:class] ] if !classes and desc[:class]
|
|
@@ -79,6 +84,14 @@ class Environment
|
|
|
79
84
|
end
|
|
80
85
|
|
|
81
86
|
private
|
|
87
|
+
|
|
88
|
+
def removeDeleted
|
|
89
|
+
@deletedClasses.keys.each do |c|
|
|
90
|
+
@elements[c].reject!{|e| @deleted[e]}
|
|
91
|
+
end
|
|
92
|
+
@deletedClasses.clear
|
|
93
|
+
@deleted.clear
|
|
94
|
+
end
|
|
82
95
|
|
|
83
96
|
def updateSubClasses(clazz)
|
|
84
97
|
return if @subClassesUpdated[clazz]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module RGen
|
|
2
|
+
|
|
3
|
+
module Fragment
|
|
4
|
+
|
|
5
|
+
# Caches model fragments in Ruby dump files.
|
|
6
|
+
#
|
|
7
|
+
# Dump files are created per each fragment file.
|
|
8
|
+
#
|
|
9
|
+
# The main goal is to support fast loading and joining of fragments. Therefore the cache
|
|
10
|
+
# stores additional information which makes the joining process faster (adding to
|
|
11
|
+
# environment, resolving references)
|
|
12
|
+
#
|
|
13
|
+
class DumpFileCache
|
|
14
|
+
|
|
15
|
+
# +cache_map+ must be an object responding to +load_data+ and +store_data+
|
|
16
|
+
# for loading or storing data associated with a file;
|
|
17
|
+
# this can be an instance of Util::FileCacheMap
|
|
18
|
+
def initialize(cache_map)
|
|
19
|
+
@cache_map = cache_map
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Note that the fragment must not be connected to other fragments by resolved references
|
|
23
|
+
# unresolve the fragment if necessary
|
|
24
|
+
def store(fragment)
|
|
25
|
+
fref = fragment.fragment_ref
|
|
26
|
+
# temporarily remove the reference to the fragment to avoid dumping the fragment
|
|
27
|
+
fref.fragment = nil
|
|
28
|
+
@cache_map.store_data(fragment.location,
|
|
29
|
+
Marshal.dump({
|
|
30
|
+
:root_elements => fragment.root_elements,
|
|
31
|
+
:elements => fragment.elements,
|
|
32
|
+
:index => fragment.index,
|
|
33
|
+
:unresolved_refs => fragment.unresolved_refs,
|
|
34
|
+
:fragment_ref => fref,
|
|
35
|
+
:data => fragment.data
|
|
36
|
+
}))
|
|
37
|
+
fref.fragment = fragment
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def load(fragment)
|
|
41
|
+
dump = @cache_map.load_data(fragment.location)
|
|
42
|
+
return :invalid if dump == :invalid
|
|
43
|
+
header = Marshal.load(dump)
|
|
44
|
+
fragment.set_root_elements(header[:root_elements],
|
|
45
|
+
:elements => header[:elements],
|
|
46
|
+
:index => header[:index],
|
|
47
|
+
:unresolved_refs => header[:unresolved_refs])
|
|
48
|
+
fragment.data = header[:data]
|
|
49
|
+
if header[:fragment_ref]
|
|
50
|
+
fragment.fragment_ref = header[:fragment_ref]
|
|
51
|
+
fragment.fragment_ref.fragment = fragment
|
|
52
|
+
else
|
|
53
|
+
raise "no fragment_ref in fragment loaded from cache"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
require 'rgen/instantiator/reference_resolver'
|
|
2
|
+
|
|
3
|
+
module RGen
|
|
4
|
+
|
|
5
|
+
module Fragment
|
|
6
|
+
|
|
7
|
+
# A FragmentedModel represents a model which consists of fragments (ModelFragment).
|
|
8
|
+
#
|
|
9
|
+
# The main purpose of this class is to resolve references across fragments and
|
|
10
|
+
# to keep the references consistent while fragments are added or removed.
|
|
11
|
+
# This way it also plays an important role in keeping the model fragments consistent
|
|
12
|
+
# and thus ModelFragment objects should only be accessed via this interface.
|
|
13
|
+
# Overall unresolved references after the resolution step are also maintained.
|
|
14
|
+
#
|
|
15
|
+
# A FragmentedModel can also keep an RGen::Environment object up to date while fragments
|
|
16
|
+
# are added or removed. The environment must be registered with the constructor.
|
|
17
|
+
#
|
|
18
|
+
# Reference resolution is based on arbitrary identifiers. The identifiers must be
|
|
19
|
+
# provided in the fragments' indices. The FragmentedModel takes care to maintain
|
|
20
|
+
# the overall index.
|
|
21
|
+
#
|
|
22
|
+
class FragmentedModel
|
|
23
|
+
attr_reader :fragments
|
|
24
|
+
attr_reader :environment
|
|
25
|
+
|
|
26
|
+
# Creates a fragmented model. Options:
|
|
27
|
+
#
|
|
28
|
+
# :env
|
|
29
|
+
# environment which will be updated as model elements are added and removed
|
|
30
|
+
#
|
|
31
|
+
def initialize(options={})
|
|
32
|
+
@environment = options[:env]
|
|
33
|
+
@fragments = []
|
|
34
|
+
@index = nil
|
|
35
|
+
@fragment_change_listeners = []
|
|
36
|
+
@fragment_index = {}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Adds a proc which is called when a fragment is added or removed
|
|
40
|
+
# The proc receives the fragment and one of :added, :removed
|
|
41
|
+
#
|
|
42
|
+
def add_fragment_change_listener(listener)
|
|
43
|
+
@fragment_change_listeners << listener
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def remove_fragment_change_listener(listener)
|
|
47
|
+
@fragment_change_listeners.delete(listener)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Add a fragment.
|
|
51
|
+
#
|
|
52
|
+
def add_fragment(fragment)
|
|
53
|
+
invalidate_cache
|
|
54
|
+
@fragments << fragment
|
|
55
|
+
fragment.elements.each{|e| @environment << e} if @environment
|
|
56
|
+
@fragment_change_listeners.each{|l| l.call(fragment, :added)}
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Removes the fragment. The fragment will be unresolved using unresolve_fragment.
|
|
60
|
+
#
|
|
61
|
+
def remove_fragment(fragment)
|
|
62
|
+
raise "fragment not part of model" unless @fragments.include?(fragment)
|
|
63
|
+
invalidate_cache
|
|
64
|
+
@fragments.delete(fragment)
|
|
65
|
+
@fragment_index.delete(fragment)
|
|
66
|
+
unresolve_fragment(fragment)
|
|
67
|
+
fragment.elements.each{|e| @environment.delete(e)} if @environment
|
|
68
|
+
@fragment_change_listeners.each{|l| l.call(fragment, :removed)}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Resolve references between fragments.
|
|
72
|
+
# It is assumed that references within fragments have already been resolved.
|
|
73
|
+
# This method can be called several times. It will update the overall unresolved references.
|
|
74
|
+
#
|
|
75
|
+
# Options:
|
|
76
|
+
#
|
|
77
|
+
# :fragment_provider:
|
|
78
|
+
# Only if a +fragment_provider+ is given, the resolve step can be reverted later on
|
|
79
|
+
# by a call to unresolve_fragment. The fragment provider is a proc which receives a model
|
|
80
|
+
# element and must return the fragment in which the element is contained.
|
|
81
|
+
#
|
|
82
|
+
# :use_target_type:
|
|
83
|
+
# reference resolver uses the expected target type to narrow the set of possible targets
|
|
84
|
+
#
|
|
85
|
+
def resolve(options)
|
|
86
|
+
@fragments.each do |f|
|
|
87
|
+
f.resolve_external(index, options)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Remove all references between this fragment and all other fragments.
|
|
92
|
+
# The references will be replaced with unresolved references (MMProxy objects).
|
|
93
|
+
#
|
|
94
|
+
def unresolve_fragment(fragment)
|
|
95
|
+
fragment.unresolve_external
|
|
96
|
+
@fragments.each do |f|
|
|
97
|
+
if f != fragment
|
|
98
|
+
f.unresolve_external_fragment(fragment)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Returns the overall unresolved references.
|
|
104
|
+
#
|
|
105
|
+
def unresolved_refs
|
|
106
|
+
@fragments.collect{|f| f.unresolved_refs}.flatten
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Returns the overall index.
|
|
110
|
+
# This is a Hash mapping identifiers to model elements accessible via the identifier.
|
|
111
|
+
#
|
|
112
|
+
def index
|
|
113
|
+
fragments.each do |f|
|
|
114
|
+
if !@fragment_index[f] || (@fragment_index[f].object_id != f.index.object_id)
|
|
115
|
+
@fragment_index[f] = f.index
|
|
116
|
+
invalidate_cache
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
return @index if @index
|
|
120
|
+
@index = {}
|
|
121
|
+
fragments.each do |f|
|
|
122
|
+
f.index.each do |i|
|
|
123
|
+
(@index[i[0]] ||= []) << i[1]
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
@index
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
def invalidate_cache
|
|
132
|
+
@index = nil
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
end
|