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
|
@@ -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
|