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.
Files changed (125) hide show
  1. data/CHANGELOG +28 -0
  2. data/Rakefile +3 -4
  3. data/lib/ea_support/uml13_ea_metamodel.rb +3 -3
  4. data/lib/ea_support/uml13_ea_to_uml13.rb +33 -2
  5. data/lib/ea_support/uml13_to_uml13_ea.rb +7 -0
  6. data/lib/mmgen/mm_ext/ecore_mmgen_ext.rb +4 -4
  7. data/lib/mmgen/templates/metamodel_generator.tpl +143 -143
  8. data/lib/rgen/ecore/ecore.rb +11 -1
  9. data/lib/rgen/ecore/ecore_interface.rb +47 -0
  10. data/lib/rgen/ecore/ecore_to_ruby.rb +166 -0
  11. data/lib/rgen/ecore/{ecore_transformer.rb → ruby_to_ecore.rb} +11 -11
  12. data/lib/rgen/environment.rb +15 -2
  13. data/lib/rgen/fragment/dump_file_cache.rb +63 -0
  14. data/lib/rgen/fragment/fragmented_model.rb +139 -0
  15. data/lib/rgen/fragment/model_fragment.rb +268 -0
  16. data/lib/rgen/instantiator/abstract_xml_instantiator.rb +44 -72
  17. data/lib/rgen/instantiator/default_xml_instantiator.rb +2 -2
  18. data/lib/rgen/instantiator/ecore_xml_instantiator.rb +16 -1
  19. data/lib/rgen/instantiator/json_instantiator.rb +16 -2
  20. data/lib/rgen/instantiator/nodebased_xml_instantiator.rb +118 -138
  21. data/lib/rgen/instantiator/qualified_name_resolver.rb +5 -1
  22. data/lib/rgen/instantiator/reference_resolver.rb +126 -24
  23. data/lib/rgen/instantiator/xmi11_instantiator.rb +6 -2
  24. data/lib/rgen/metamodel_builder.rb +18 -6
  25. data/lib/rgen/metamodel_builder/builder_extensions.rb +431 -407
  26. data/lib/rgen/metamodel_builder/builder_runtime.rb +8 -8
  27. data/lib/rgen/metamodel_builder/constant_order_helper.rb +4 -4
  28. data/lib/rgen/metamodel_builder/data_types.rb +5 -1
  29. data/lib/rgen/metamodel_builder/intermediate/feature.rb +167 -0
  30. data/lib/rgen/metamodel_builder/module_extension.rb +2 -2
  31. data/lib/rgen/model_builder.rb +10 -5
  32. data/lib/rgen/model_builder/builder_context.rb +17 -1
  33. data/lib/rgen/serializer/opposite_reference_filter.rb +18 -0
  34. data/lib/rgen/serializer/qualified_name_provider.rb +45 -0
  35. data/lib/rgen/template_language/template_container.rb +3 -1
  36. data/lib/rgen/{auto_class_creator.rb → util/auto_class_creator.rb} +6 -1
  37. data/lib/rgen/util/cached_glob.rb +67 -0
  38. data/lib/rgen/util/file_cache_map.rb +104 -0
  39. data/lib/rgen/util/file_change_detector.rb +78 -0
  40. data/lib/rgen/{method_delegation.rb → util/method_delegation.rb} +18 -3
  41. data/lib/rgen/{model_comparator.rb → util/model_comparator.rb} +17 -5
  42. data/lib/rgen/{model_comparator_base.rb → util/model_comparator_base.rb} +6 -1
  43. data/lib/rgen/{model_dumper.rb → util/model_dumper.rb} +6 -1
  44. data/lib/rgen/{name_helper.rb → util/name_helper.rb} +6 -1
  45. data/lib/rgen/util/pattern_matcher.rb +329 -0
  46. data/lib/transformers/uml13_to_ecore.rb +103 -60
  47. data/test/ecore_self_test.rb +43 -42
  48. data/test/json_test.rb +15 -0
  49. data/test/metamodel_builder_test.rb +361 -206
  50. data/test/metamodel_from_ecore_test.rb +45 -0
  51. data/test/metamodel_order_test.rb +10 -4
  52. data/test/metamodel_roundtrip_test.rb +2 -2
  53. data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +1 -1
  54. data/test/metamodel_roundtrip_test/houseMetamodel_Regenerated.ecore +50 -50
  55. data/test/method_delegation_test.rb +9 -9
  56. data/test/model_builder/ecore_internal.rb +19 -9
  57. data/test/model_builder/serializer_test.rb +1 -1
  58. data/test/reference_resolver_test.rb +79 -12
  59. data/test/rgen_test.rb +2 -0
  60. data/test/template_language_test.rb +7 -0
  61. data/test/template_language_test/templates/callback_indent_test/a.tpl +12 -0
  62. data/test/template_language_test/templates/callback_indent_test/b.tpl +5 -0
  63. data/test/testmodel/ea_testmodel_regenerated.xml +588 -583
  64. data/test/transformer_test.rb +3 -3
  65. data/test/util/file_cache_map_test.rb +91 -0
  66. data/test/util/file_cache_map_test/testdir/fileA +1 -0
  67. data/test/util_test.rb +4 -0
  68. data/test/xml_instantiator_test.rb +139 -135
  69. metadata +49 -104
  70. data/lib/rgen/ecore/ecore_instantiator.rb +0 -31
  71. data/lib/rgen/metamodel_builder/metamodel_description.rb +0 -232
  72. data/redist/xmlscan/ChangeLog +0 -1301
  73. data/redist/xmlscan/README +0 -34
  74. data/redist/xmlscan/THANKS +0 -11
  75. data/redist/xmlscan/doc/changes.html +0 -74
  76. data/redist/xmlscan/doc/changes.rd +0 -80
  77. data/redist/xmlscan/doc/en/conformance.html +0 -136
  78. data/redist/xmlscan/doc/en/conformance.rd +0 -152
  79. data/redist/xmlscan/doc/en/manual.html +0 -356
  80. data/redist/xmlscan/doc/en/manual.rd +0 -402
  81. data/redist/xmlscan/doc/ja/conformance.ja.html +0 -118
  82. data/redist/xmlscan/doc/ja/conformance.ja.rd +0 -134
  83. data/redist/xmlscan/doc/ja/manual.ja.html +0 -325
  84. data/redist/xmlscan/doc/ja/manual.ja.rd +0 -370
  85. data/redist/xmlscan/doc/src/Makefile +0 -41
  86. data/redist/xmlscan/doc/src/conformance.rd.src +0 -256
  87. data/redist/xmlscan/doc/src/langsplit.rb +0 -110
  88. data/redist/xmlscan/doc/src/manual.rd.src +0 -614
  89. data/redist/xmlscan/install.rb +0 -41
  90. data/redist/xmlscan/lib/xmlscan/encoding.rb +0 -311
  91. data/redist/xmlscan/lib/xmlscan/htmlscan.rb +0 -289
  92. data/redist/xmlscan/lib/xmlscan/namespace.rb +0 -352
  93. data/redist/xmlscan/lib/xmlscan/parser.rb +0 -299
  94. data/redist/xmlscan/lib/xmlscan/scanner.rb +0 -1109
  95. data/redist/xmlscan/lib/xmlscan/version.rb +0 -22
  96. data/redist/xmlscan/lib/xmlscan/visitor.rb +0 -158
  97. data/redist/xmlscan/lib/xmlscan/xmlchar.rb +0 -441
  98. data/redist/xmlscan/memo/CONFORMANCE +0 -1249
  99. data/redist/xmlscan/memo/PRODUCTIONS +0 -195
  100. data/redist/xmlscan/memo/contentspec.ry +0 -335
  101. data/redist/xmlscan/samples/chibixml.rb +0 -105
  102. data/redist/xmlscan/samples/getxmlchar.rb +0 -122
  103. data/redist/xmlscan/samples/rexml.rb +0 -159
  104. data/redist/xmlscan/samples/xmlbench.rb +0 -88
  105. data/redist/xmlscan/samples/xmlbench/parser/chibixml.rb +0 -22
  106. data/redist/xmlscan/samples/xmlbench/parser/nqxml.rb +0 -29
  107. data/redist/xmlscan/samples/xmlbench/parser/rexml.rb +0 -62
  108. data/redist/xmlscan/samples/xmlbench/parser/xmlparser.rb +0 -22
  109. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-0.0.10.rb +0 -62
  110. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-chibixml.rb +0 -22
  111. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-rexml.rb +0 -22
  112. data/redist/xmlscan/samples/xmlbench/parser/xmlscan.rb +0 -99
  113. data/redist/xmlscan/samples/xmlbench/xmlbench-lib.rb +0 -116
  114. data/redist/xmlscan/samples/xmlconftest.rb +0 -200
  115. data/redist/xmlscan/test.rb +0 -7
  116. data/redist/xmlscan/tests/deftestcase.rb +0 -73
  117. data/redist/xmlscan/tests/runtest.rb +0 -47
  118. data/redist/xmlscan/tests/testall.rb +0 -14
  119. data/redist/xmlscan/tests/testencoding.rb +0 -438
  120. data/redist/xmlscan/tests/testhtmlscan.rb +0 -752
  121. data/redist/xmlscan/tests/testnamespace.rb +0 -457
  122. data/redist/xmlscan/tests/testparser.rb +0 -591
  123. data/redist/xmlscan/tests/testscanner.rb +0 -1749
  124. data/redist/xmlscan/tests/testxmlchar.rb +0 -143
  125. 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
- $:.unshift File.join(File.dirname(__FILE__),"..","..","..","redist","xmlscan","lib")
2
-
3
- require 'xmlscan/namespace'
1
+ require 'nokogiri'
4
2
 
5
3
  class AbstractXMLInstantiator
6
4
 
7
- class XMLScanVisitor
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 on_attribute_ns(qname, prefix, localpart)
17
- @current_attr_name = qname
18
- end
19
-
20
- def on_attr_value(str)
21
- @current_attributes[@current_attr_name] = str
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 on_stag_end_ns(qname, namespaces)
34
- controlGC
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 on_stag_end_empty_ns(qname, namespaces)
42
- controlGC
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 on_etag(qname)
51
- prefix, tag = split_qname(qname)
52
- @instantiator.end_tag(prefix, tag)
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
- # Parses str and calls start_tag, end_tag, set_attribute and text methods of a subclass.
73
- #
74
- # If gcSuspendCount is specified, the garbage collector will be disabled for that
75
- # number of start or end tags. After that period it will clean up and then be disabled again.
76
- # A value of about 1000 can significantly improve overall performance.
77
- # The memory usage normally does not increase.
78
- # Depending on the work done for every xml tag the value might have to be adjusted.
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
- gcDisabledBefore = GC.disable
82
- gcSuspendCount = 0 if gcDisabledBefore
83
- begin
84
- visitor = XMLScanVisitor.new(self, gcSuspendCount)
85
- parser = XMLScan::XMLParserNS.new(visitor)
86
- parser.parse(str)
87
- ensure
88
- GC.enable unless gcDisabledBefore
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
- def text(str)
93
- end
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 =~ /^#\/\d*\/([\w\/]+)/
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