rgen 0.5.4 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,268 @@
|
|
1
|
+
require 'rgen/instantiator/reference_resolver'
|
2
|
+
|
3
|
+
module RGen
|
4
|
+
|
5
|
+
module Fragment
|
6
|
+
|
7
|
+
# A model fragment is a list of root model elements associated with a location (e.g. a file)
|
8
|
+
#
|
9
|
+
# Optionally, an arbitrary data object may be associated with the fragment. The data object
|
10
|
+
# will also be stored in the cache.
|
11
|
+
#
|
12
|
+
# If an element within the fragment changes this must be indicated to the fragment by calling
|
13
|
+
# +mark_changed+.
|
14
|
+
#
|
15
|
+
class ModelFragment
|
16
|
+
attr_reader :root_elements
|
17
|
+
attr_accessor :location, :fragment_ref, :data
|
18
|
+
|
19
|
+
# A FragmentRef serves as a single target object for elements which need to reference the
|
20
|
+
# fragment they are contained in. The FragmentRef references the fragment it is contained in.
|
21
|
+
# The FragmentRef is separate from the fragment itself to allow storing it in a marshal dump
|
22
|
+
# independently of the fragment.
|
23
|
+
#
|
24
|
+
class FragmentRef
|
25
|
+
attr_accessor :fragment
|
26
|
+
end
|
27
|
+
|
28
|
+
# A ResolvedReference wraps an unresolved reference after it has been resolved.
|
29
|
+
# It also holds the target element to which it has been resolved, i.e. with which the proxy
|
30
|
+
# object has been replaced.
|
31
|
+
#
|
32
|
+
class ResolvedReference
|
33
|
+
attr_reader :uref, :target
|
34
|
+
def initialize(uref, target)
|
35
|
+
@uref, @target = uref, target
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Create a model fragment
|
40
|
+
#
|
41
|
+
# :data
|
42
|
+
# data object associated with this fragment
|
43
|
+
#
|
44
|
+
# :identifier_provider
|
45
|
+
# identifier provider to be used when resolving references
|
46
|
+
# it must be a proc which receives a model element and must return
|
47
|
+
# that element's identifier or nil if the element has no identifier
|
48
|
+
#
|
49
|
+
def initialize(location, options={})
|
50
|
+
@location = location
|
51
|
+
@fragment_ref = FragmentRef.new
|
52
|
+
@fragment_ref.fragment = self
|
53
|
+
@data = options[:data]
|
54
|
+
@resolved_refs = nil
|
55
|
+
@changed = false
|
56
|
+
@identifier_provider = options[:identifier_provider]
|
57
|
+
end
|
58
|
+
|
59
|
+
# Set the root elements, normally done by an instantiator.
|
60
|
+
#
|
61
|
+
# For optimization reasons the instantiator of the fragment may provide data explicitly which
|
62
|
+
# is normally derived by the fragment itself. In this case it is essential that this
|
63
|
+
# data is consistent with the fragment.
|
64
|
+
#
|
65
|
+
def set_root_elements(root_elements, options={})
|
66
|
+
@root_elements = root_elements
|
67
|
+
@elements = options[:elements]
|
68
|
+
@index = options[:index]
|
69
|
+
@unresolved_refs = options[:unresolved_refs]
|
70
|
+
@resolved_refs = nil
|
71
|
+
@changed = false
|
72
|
+
end
|
73
|
+
|
74
|
+
# Must be called when any of the elements in this fragment has been changed
|
75
|
+
#
|
76
|
+
def mark_changed
|
77
|
+
@changed = true
|
78
|
+
@elements = nil
|
79
|
+
@index = nil
|
80
|
+
@unresolved_refs = nil
|
81
|
+
@resolved_refs = :dirty
|
82
|
+
end
|
83
|
+
|
84
|
+
# Can be used to reset the change status to unchanged.
|
85
|
+
#
|
86
|
+
def mark_unchanged
|
87
|
+
@changed = false
|
88
|
+
end
|
89
|
+
|
90
|
+
# Indicates whether the fragment has been changed or not
|
91
|
+
#
|
92
|
+
def changed?
|
93
|
+
@changed
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns all elements within this fragment
|
97
|
+
#
|
98
|
+
def elements
|
99
|
+
return @elements if @elements
|
100
|
+
@elements = []
|
101
|
+
@root_elements.each do |e|
|
102
|
+
all_child_elements(e, @elements)
|
103
|
+
end
|
104
|
+
@elements
|
105
|
+
end
|
106
|
+
|
107
|
+
# Returns the index of the element contained in this fragment.
|
108
|
+
#
|
109
|
+
def index
|
110
|
+
build_index unless @index
|
111
|
+
@index
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns all unresolved references within this fragment, i.e. references to MMProxy objects
|
115
|
+
#
|
116
|
+
def unresolved_refs
|
117
|
+
return @unresolved_refs if @unresolved_refs
|
118
|
+
@unresolved_refs = []
|
119
|
+
elements.each do |e|
|
120
|
+
each_reference_target(e) do |r, t|
|
121
|
+
if t.is_a?(RGen::MetamodelBuilder::MMProxy)
|
122
|
+
@unresolved_refs <<
|
123
|
+
RGen::Instantiator::ReferenceResolver::UnresolvedReference.new(e, r.name, t)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
@unresolved_refs
|
128
|
+
end
|
129
|
+
|
130
|
+
# Builds the index of all elements within this fragment having an identifier
|
131
|
+
# the index is an array of 2-element arrays holding the identifier and the element
|
132
|
+
#
|
133
|
+
def build_index
|
134
|
+
raise "cannot build index without an identifier provider" unless @identifier_provider
|
135
|
+
@index = elements.collect { |e|
|
136
|
+
ident = @identifier_provider.call(e, nil)
|
137
|
+
ident && !ident.empty? ? [ident, e] : nil
|
138
|
+
}.compact
|
139
|
+
end
|
140
|
+
|
141
|
+
# Resolves local references (within this fragment) as far as possible
|
142
|
+
#
|
143
|
+
# Options:
|
144
|
+
#
|
145
|
+
# :use_target_type:
|
146
|
+
# reference resolver uses the expected target type to narrow the set of possible targets
|
147
|
+
#
|
148
|
+
def resolve_local(options={})
|
149
|
+
resolver = RGen::Instantiator::ReferenceResolver.new
|
150
|
+
index.each do |i|
|
151
|
+
resolver.add_identifier(i[0], i[1])
|
152
|
+
end
|
153
|
+
@unresolved_refs = resolver.resolve(unresolved_refs, :use_target_type => options[:use_target_type])
|
154
|
+
end
|
155
|
+
|
156
|
+
# Resolves references to external fragments using the external_index provided.
|
157
|
+
# The external index must be a Hash mapping identifiers uniquely to model elements.
|
158
|
+
#
|
159
|
+
# Options:
|
160
|
+
#
|
161
|
+
# :fragment_provider:
|
162
|
+
# If a +fragment_provider+ is given, the resolve step can be reverted later on
|
163
|
+
# by a call to unresolve_external or unresolve_external_fragment. The fragment provider
|
164
|
+
# is a proc which receives a model element and must return the fragment in which it is
|
165
|
+
# contained.
|
166
|
+
#
|
167
|
+
# :use_target_type:
|
168
|
+
# reference resolver uses the expected target type to narrow the set of possible targets
|
169
|
+
#
|
170
|
+
#
|
171
|
+
def resolve_external(external_index, options)
|
172
|
+
fragment_provider = options[:fragment_provider]
|
173
|
+
resolver = RGen::Instantiator::ReferenceResolver.new(
|
174
|
+
:identifier_resolver => proc {|ident| external_index[ident] })
|
175
|
+
if fragment_provider
|
176
|
+
@resolved_refs = {} if @resolved_refs.nil? || @resolved_refs == :dirty
|
177
|
+
on_resolve = proc { |ur, target|
|
178
|
+
target_fragment = fragment_provider.call(target)
|
179
|
+
target_fragment ||= :unknown
|
180
|
+
raise "can not resolve local reference in resolve_external, call resolve_local first" \
|
181
|
+
if target_fragment == self
|
182
|
+
@resolved_refs[target_fragment] ||= []
|
183
|
+
@resolved_refs[target_fragment] << ResolvedReference.new(ur, target)
|
184
|
+
}
|
185
|
+
@unresolved_refs = resolver.resolve(unresolved_refs, :on_resolve => on_resolve, :use_target_type => options[:use_target_type])
|
186
|
+
else
|
187
|
+
@unresolved_refs = resolver.resolve(unresolved_refs, :use_target_type => options[:use_target_type])
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Unresolve outgoing references to all external fragments, i.e. references which used to
|
192
|
+
# be represented by an unresolved reference from within this fragment.
|
193
|
+
# Note, that there may be more references to external fragments due to references which
|
194
|
+
# were represented by unresolved references from within other fragments.
|
195
|
+
#
|
196
|
+
def unresolve_external
|
197
|
+
return if @resolved_refs.nil?
|
198
|
+
raise "can not unresolve, missing fragment information" if @resolved_refs == :dirty || @resolved_refs[:unknown]
|
199
|
+
rrefs = @resolved_refs.values.flatten
|
200
|
+
@resolved_refs = {}
|
201
|
+
unresolve_refs(rrefs)
|
202
|
+
end
|
203
|
+
|
204
|
+
# Like unresolve_external but only unresolve references to external fragment +fragment+
|
205
|
+
#
|
206
|
+
def unresolve_external_fragment(fragment)
|
207
|
+
return if @resolved_refs.nil?
|
208
|
+
raise "can not unresolve, missing fragment information" if @resolved_refs == :dirty || @resolved_refs[:unknown]
|
209
|
+
rrefs = @resolved_refs[fragment]
|
210
|
+
@resolved_refs.delete(fragment)
|
211
|
+
unresolve_refs(rrefs) if rrefs
|
212
|
+
end
|
213
|
+
|
214
|
+
private
|
215
|
+
|
216
|
+
# Turns resolved references +rrefs+ back into unresolved references
|
217
|
+
#
|
218
|
+
def unresolve_refs(rrefs)
|
219
|
+
rrefs.each do |rr|
|
220
|
+
ur = rr.uref
|
221
|
+
refs = ur.element.getGeneric(ur.feature_name)
|
222
|
+
if refs.is_a?(Array)
|
223
|
+
index = refs.index(rr.target)
|
224
|
+
ur.element.removeGeneric(ur.feature_name, rr.target)
|
225
|
+
ur.element.addGeneric(ur.feature_name, ur.proxy, index)
|
226
|
+
else
|
227
|
+
ur.element.setGeneric(ur.feature_name, ur.proxy)
|
228
|
+
end
|
229
|
+
@unresolved_refs << ur
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def each_reference_target(element)
|
234
|
+
non_containment_references(element.class).each do |r|
|
235
|
+
element.getGenericAsArray(r.name).each do |t|
|
236
|
+
yield(r, t)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def all_child_elements(element, childs)
|
242
|
+
containment_references(element.class).each do |r|
|
243
|
+
element.getGenericAsArray(r.name).each do |c|
|
244
|
+
childs << c
|
245
|
+
all_child_elements(c, childs)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def containment_references(clazz)
|
251
|
+
@@containment_references_cache ||= {}
|
252
|
+
@@containment_references_cache[clazz] ||=
|
253
|
+
clazz.ecore.eAllReferences.select{|r| r.containment}
|
254
|
+
end
|
255
|
+
|
256
|
+
def non_containment_references(clazz)
|
257
|
+
@@non_containment_references_cache ||= {}
|
258
|
+
@@non_containment_references_cache[clazz] ||=
|
259
|
+
clazz.ecore.eAllReferences.select{|r| !r.containment}
|
260
|
+
end
|
261
|
+
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
|
@@ -1,94 +1,66 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'xmlscan/namespace'
|
1
|
+
require 'nokogiri'
|
4
2
|
|
5
3
|
class AbstractXMLInstantiator
|
6
4
|
|
7
|
-
class
|
8
|
-
include XMLScan::NSVisitor
|
5
|
+
class Visitor < Nokogiri::XML::SAX::Document
|
9
6
|
|
10
7
|
def initialize(inst, gcSuspendCount)
|
11
|
-
@current_attributes = {}
|
12
8
|
@instantiator = inst
|
13
9
|
@gcSuspendCount = gcSuspendCount
|
10
|
+
@namespaces = {}
|
14
11
|
end
|
15
12
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
@
|
22
|
-
end
|
23
|
-
|
24
|
-
def split_qname(qname)
|
25
|
-
if qname =~ /^([^:]+):([^:]+)$/
|
26
|
-
prefix, tag = $1, $2
|
27
|
-
else
|
28
|
-
prefix, tag = nil, qname
|
29
|
-
end
|
30
|
-
return prefix, tag
|
13
|
+
def start_element_namespace(tag, attributes, prefix, uri, ns)
|
14
|
+
controlGC
|
15
|
+
ns.each{|n| @namespaces[n[0]] = n[1]}
|
16
|
+
attrs = attributes.collect{|a| [a.prefix ? a.prefix+":"+a.localname : a.localname, a.value]}
|
17
|
+
@instantiator.start_tag(prefix, tag, @namespaces, Hash[*(attrs.flatten)])
|
18
|
+
attrs.each { |pair| @instantiator.set_attribute(pair[0], pair[1]) }
|
31
19
|
end
|
32
20
|
|
33
|
-
def
|
34
|
-
|
35
|
-
prefix, tag = split_qname(qname)
|
36
|
-
@instantiator.start_tag(prefix, tag, namespaces, @current_attributes)
|
37
|
-
@current_attributes.each_pair { |k,v| @instantiator.set_attribute(k, v) }
|
38
|
-
@current_attributes = {}
|
21
|
+
def end_element_namespace(tag, prefix, uri)
|
22
|
+
@instantiator.end_tag(prefix, tag)
|
39
23
|
end
|
40
24
|
|
41
|
-
def
|
42
|
-
|
43
|
-
prefix, tag = split_qname(qname)
|
44
|
-
@instantiator.start_tag(prefix, tag, namespaces, @current_attributes)
|
45
|
-
@current_attributes.each_pair { |k,v| @instantiator.set_attribute(k, v) }
|
46
|
-
@current_attributes = {}
|
47
|
-
@instantiator.end_tag(prefix, tag)
|
25
|
+
def characters(str)
|
26
|
+
@instantiator.text(str)
|
48
27
|
end
|
49
28
|
|
50
|
-
def
|
51
|
-
|
52
|
-
@
|
29
|
+
def controlGC
|
30
|
+
return unless @gcSuspendCount > 0
|
31
|
+
@gcCounter ||= 0
|
32
|
+
@gcCounter += 1
|
33
|
+
if @gcCounter == @gcSuspendCount
|
34
|
+
@gcCounter = 0
|
35
|
+
GC.enable
|
36
|
+
ObjectSpace.garbage_collect
|
37
|
+
GC.disable
|
38
|
+
end
|
53
39
|
end
|
54
|
-
|
55
|
-
def on_chardata(str)
|
56
|
-
@instantiator.text(str)
|
57
|
-
end
|
58
|
-
|
59
|
-
def controlGC
|
60
|
-
return unless @gcSuspendCount > 0
|
61
|
-
@gcCounter ||= 0
|
62
|
-
@gcCounter += 1
|
63
|
-
if @gcCounter == @gcSuspendCount
|
64
|
-
@gcCounter = 0
|
65
|
-
GC.enable
|
66
|
-
ObjectSpace.garbage_collect
|
67
|
-
GC.disable
|
68
|
-
end
|
69
|
-
end
|
70
40
|
end
|
71
41
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
42
|
+
# Parses str and calls start_tag, end_tag, set_attribute and text methods of a subclass.
|
43
|
+
#
|
44
|
+
# If gcSuspendCount is specified, the garbage collector will be disabled for that
|
45
|
+
# number of start or end tags. After that period it will clean up and then be disabled again.
|
46
|
+
# A value of about 1000 can significantly improve overall performance.
|
47
|
+
# The memory usage normally does not increase.
|
48
|
+
# Depending on the work done for every xml tag the value might have to be adjusted.
|
49
|
+
#
|
80
50
|
def instantiate(str, gcSuspendCount=0)
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
51
|
+
gcDisabledBefore = GC.disable
|
52
|
+
gcSuspendCount = 0 if gcDisabledBefore
|
53
|
+
begin
|
54
|
+
visitor = Visitor.new(self, gcSuspendCount)
|
55
|
+
parser = Nokogiri::XML::SAX::Parser.new(visitor)
|
56
|
+
parser.parse(str) do |ctx|
|
57
|
+
@parserContext = ctx
|
58
|
+
end
|
59
|
+
ensure
|
60
|
+
GC.enable unless gcDisabledBefore
|
89
61
|
end
|
90
62
|
end
|
91
63
|
|
92
|
-
|
93
|
-
|
94
|
-
end
|
64
|
+
def text(str)
|
65
|
+
end
|
66
|
+
end
|
@@ -8,7 +8,7 @@ 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 NameHelper
|
11
|
+
include Util::NameHelper
|
12
12
|
|
13
13
|
NamespaceDescriptor = Struct.new(:prefix, :target)
|
14
14
|
|
@@ -114,4 +114,4 @@ end
|
|
114
114
|
|
115
115
|
end
|
116
116
|
|
117
|
-
end
|
117
|
+
end
|
@@ -14,6 +14,7 @@ class ECoreXMLInstantiator < AbstractXMLInstantiator
|
|
14
14
|
@env = env
|
15
15
|
@rolestack = []
|
16
16
|
@elementstack = []
|
17
|
+
@element_by_id = {}
|
17
18
|
@loglevel = loglevel
|
18
19
|
end
|
19
20
|
|
@@ -38,6 +39,10 @@ class ECoreXMLInstantiator < AbstractXMLInstantiator
|
|
38
39
|
eClass = RGen::ECore.ecore.eClassifiers.find{|c| c.name == class_name}
|
39
40
|
if eClass
|
40
41
|
obj = RGen::ECore.const_get(class_name).new
|
42
|
+
if attributes["xmi:id"]
|
43
|
+
@element_by_id[attributes["xmi:id"]] = obj
|
44
|
+
attributes.delete("xmi:id")
|
45
|
+
end
|
41
46
|
if eRef
|
42
47
|
if eRef.many
|
43
48
|
@elementstack.last.addGeneric(eRef.name, obj)
|
@@ -51,6 +56,10 @@ class ECoreXMLInstantiator < AbstractXMLInstantiator
|
|
51
56
|
log WARN, "Class not found: #{class_name}"
|
52
57
|
@elementstack.push nil
|
53
58
|
end
|
59
|
+
|
60
|
+
attributes.each_pair do |attr, value|
|
61
|
+
set_attribute_internal(attr, value)
|
62
|
+
end
|
54
63
|
end
|
55
64
|
|
56
65
|
def end_tag(prefix, tag)
|
@@ -60,6 +69,10 @@ class ECoreXMLInstantiator < AbstractXMLInstantiator
|
|
60
69
|
ResolverDescription = Struct.new(:object, :attribute, :value)
|
61
70
|
|
62
71
|
def set_attribute(attr, value)
|
72
|
+
# do nothing, already handled by start_tag/set_attribute_internal
|
73
|
+
end
|
74
|
+
|
75
|
+
def set_attribute_internal(attr, value)
|
63
76
|
return unless @elementstack.last
|
64
77
|
eFeat = eAllStructuralFeatures(@elementstack.last).find{|a| a.name == attr}
|
65
78
|
if eFeat.is_a?(EReference)
|
@@ -113,7 +126,9 @@ class ECoreXMLInstantiator < AbstractXMLInstantiator
|
|
113
126
|
|
114
127
|
def find_referenced(context, desc)
|
115
128
|
desc.split(/\s+/).collect do |r|
|
116
|
-
if r =~
|
129
|
+
if r =~ /^#([^\/]+)$/
|
130
|
+
@element_by_id[$1]
|
131
|
+
elsif r =~ /^#\/\d*\/([\w\/]+)/
|
117
132
|
find_in_context(context, $1.split('/'))
|
118
133
|
elsif r =~ /#\/\/(\w+)$/
|
119
134
|
case $1
|