rgen 0.5.4 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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