rgen 0.3.0 → 0.4.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 (145) hide show
  1. data/CHANGELOG +20 -1
  2. data/MIT-LICENSE +1 -1
  3. data/README +12 -9
  4. data/lib/instantiators/ea_instantiator.rb +36 -0
  5. data/lib/metamodels/uml13_metamodel.rb +559 -0
  6. data/lib/metamodels/uml13_metamodel_ext.rb +26 -0
  7. data/lib/mmgen/metamodel_generator.rb +5 -5
  8. data/lib/mmgen/mm_ext/ecore_ext.rb +95 -0
  9. data/lib/mmgen/mmgen.rb +6 -4
  10. data/lib/mmgen/templates/annotations.tpl +37 -0
  11. data/lib/mmgen/templates/metamodel_generator.tpl +171 -0
  12. data/lib/rgen/ecore/ecore.rb +190 -0
  13. data/lib/rgen/ecore/ecore_instantiator.rb +25 -0
  14. data/lib/rgen/ecore/ecore_transformer.rb +85 -0
  15. data/lib/rgen/environment.rb +9 -24
  16. data/lib/rgen/find_helper.rb +68 -0
  17. data/lib/rgen/{instantiator.rb → instantiator/abstract_instantiator.rb} +6 -2
  18. data/lib/rgen/instantiator/abstract_xml_instantiator.rb +59 -0
  19. data/lib/rgen/instantiator/default_xml_instantiator.rb +117 -0
  20. data/lib/rgen/instantiator/ecore_xml_instantiator.rb +144 -0
  21. data/lib/rgen/instantiator/nodebased_xml_instantiator.rb +157 -0
  22. data/lib/rgen/instantiator/xmi11_instantiator.rb +164 -0
  23. data/lib/rgen/metamodel_builder.rb +103 -9
  24. data/lib/rgen/metamodel_builder/build_helper.rb +26 -4
  25. data/lib/rgen/metamodel_builder/builder_extensions.rb +285 -88
  26. data/lib/rgen/metamodel_builder/builder_runtime.rb +7 -1
  27. data/lib/rgen/metamodel_builder/data_types.rb +67 -0
  28. data/lib/rgen/metamodel_builder/intermediate/annotation.rb +30 -0
  29. data/lib/rgen/metamodel_builder/metamodel_description.rb +232 -0
  30. data/lib/rgen/metamodel_builder/mm_multiple.rb +23 -0
  31. data/lib/rgen/metamodel_builder/module_extension.rb +33 -0
  32. data/lib/rgen/model_comparator.rb +56 -0
  33. data/lib/rgen/model_dumper.rb +5 -5
  34. data/lib/rgen/name_helper.rb +17 -1
  35. data/lib/rgen/template_language.rb +148 -28
  36. data/lib/rgen/template_language/directory_template_container.rb +56 -38
  37. data/lib/rgen/template_language/output_handler.rb +93 -77
  38. data/lib/rgen/template_language/template_container.rb +186 -143
  39. data/lib/rgen/transformer.rb +19 -14
  40. data/lib/transformers/uml13_to_ecore.rb +75 -0
  41. data/redist/xmlscan/ChangeLog +1301 -0
  42. data/redist/xmlscan/README +34 -0
  43. data/redist/xmlscan/THANKS +11 -0
  44. data/redist/xmlscan/doc/changes.html +74 -0
  45. data/redist/xmlscan/doc/changes.rd +80 -0
  46. data/redist/xmlscan/doc/en/conformance.html +136 -0
  47. data/redist/xmlscan/doc/en/conformance.rd +152 -0
  48. data/redist/xmlscan/doc/en/manual.html +356 -0
  49. data/redist/xmlscan/doc/en/manual.rd +402 -0
  50. data/redist/xmlscan/doc/ja/conformance.ja.html +118 -0
  51. data/redist/xmlscan/doc/ja/conformance.ja.rd +134 -0
  52. data/redist/xmlscan/doc/ja/manual.ja.html +325 -0
  53. data/redist/xmlscan/doc/ja/manual.ja.rd +370 -0
  54. data/redist/xmlscan/doc/src/Makefile +41 -0
  55. data/redist/xmlscan/doc/src/conformance.rd.src +256 -0
  56. data/redist/xmlscan/doc/src/langsplit.rb +110 -0
  57. data/redist/xmlscan/doc/src/manual.rd.src +614 -0
  58. data/redist/xmlscan/install.rb +41 -0
  59. data/redist/xmlscan/lib/xmlscan/encoding.rb +311 -0
  60. data/redist/xmlscan/lib/xmlscan/htmlscan.rb +289 -0
  61. data/redist/xmlscan/lib/xmlscan/namespace.rb +352 -0
  62. data/redist/xmlscan/lib/xmlscan/parser.rb +299 -0
  63. data/redist/xmlscan/lib/xmlscan/scanner.rb +1109 -0
  64. data/redist/xmlscan/lib/xmlscan/version.rb +22 -0
  65. data/redist/xmlscan/lib/xmlscan/visitor.rb +158 -0
  66. data/redist/xmlscan/lib/xmlscan/xmlchar.rb +441 -0
  67. data/redist/xmlscan/memo/CONFORMANCE +1249 -0
  68. data/redist/xmlscan/memo/PRODUCTIONS +195 -0
  69. data/redist/xmlscan/memo/contentspec.ry +335 -0
  70. data/redist/xmlscan/samples/chibixml.rb +105 -0
  71. data/redist/xmlscan/samples/getxmlchar.rb +122 -0
  72. data/redist/xmlscan/samples/rexml.rb +159 -0
  73. data/redist/xmlscan/samples/xmlbench.rb +88 -0
  74. data/redist/xmlscan/samples/xmlbench/parser/chibixml.rb +22 -0
  75. data/redist/xmlscan/samples/xmlbench/parser/nqxml.rb +29 -0
  76. data/redist/xmlscan/samples/xmlbench/parser/rexml.rb +62 -0
  77. data/redist/xmlscan/samples/xmlbench/parser/xmlparser.rb +22 -0
  78. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-0.0.10.rb +62 -0
  79. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-chibixml.rb +22 -0
  80. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-rexml.rb +22 -0
  81. data/redist/xmlscan/samples/xmlbench/parser/xmlscan.rb +99 -0
  82. data/redist/xmlscan/samples/xmlbench/xmlbench-lib.rb +116 -0
  83. data/redist/xmlscan/samples/xmlconftest.rb +200 -0
  84. data/redist/xmlscan/test.rb +7 -0
  85. data/redist/xmlscan/tests/deftestcase.rb +73 -0
  86. data/redist/xmlscan/tests/runtest.rb +47 -0
  87. data/redist/xmlscan/tests/testall.rb +14 -0
  88. data/redist/xmlscan/tests/testencoding.rb +438 -0
  89. data/redist/xmlscan/tests/testhtmlscan.rb +752 -0
  90. data/redist/xmlscan/tests/testnamespace.rb +457 -0
  91. data/redist/xmlscan/tests/testparser.rb +591 -0
  92. data/redist/xmlscan/tests/testscanner.rb +1749 -0
  93. data/redist/xmlscan/tests/testxmlchar.rb +143 -0
  94. data/redist/xmlscan/tests/visitor.rb +34 -0
  95. data/test/array_extensions_test.rb +2 -2
  96. data/test/ea_instantiator_test.rb +41 -0
  97. data/test/ecore_self_test.rb +53 -0
  98. data/test/environment_test.rb +11 -6
  99. data/test/metamodel_builder_test.rb +404 -245
  100. data/test/metamodel_roundtrip_test.rb +52 -0
  101. data/test/metamodel_roundtrip_test/TestModel.rb +65 -0
  102. data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +64 -0
  103. data/test/metamodel_roundtrip_test/houseMetamodel.ecore +32 -0
  104. data/test/metamodel_roundtrip_test/houseMetamodel_from_ecore.rb +39 -0
  105. data/test/rgen_test.rb +3 -3
  106. data/test/template_language_test.rb +65 -39
  107. data/test/template_language_test/expected_result.txt +24 -3
  108. data/test/template_language_test/templates/code/array.tpl +11 -0
  109. data/test/template_language_test/templates/content/author.tpl +7 -0
  110. data/test/template_language_test/templates/content/chapter.tpl +1 -1
  111. data/test/template_language_test/templates/root.tpl +17 -8
  112. data/test/template_language_test/testout.txt +24 -3
  113. data/test/testmodel/class_model_checker.rb +119 -0
  114. data/test/{xmi_instantiator_test/testmodel.eap → testmodel/ea_testmodel.eap} +0 -0
  115. data/test/{xmi_instantiator_test/testmodel.xml → testmodel/ea_testmodel.xml} +81 -14
  116. data/test/testmodel/ea_testmodel_partial.xml +317 -0
  117. data/test/testmodel/ecore_model_checker.rb +101 -0
  118. data/test/testmodel/manual_testmodel.xml +22 -0
  119. data/test/testmodel/object_model_checker.rb +67 -0
  120. data/test/transformer_test.rb +18 -10
  121. data/test/xml_instantiator_test.rb +81 -8
  122. data/test/xml_instantiator_test/simple_ecore_model_checker.rb +94 -0
  123. data/test/xml_instantiator_test/simple_xmi_ecore_instantiator.rb +53 -0
  124. data/test/xml_instantiator_test/simple_xmi_metamodel.rb +49 -0
  125. data/test/xml_instantiator_test/simple_xmi_to_ecore.rb +75 -0
  126. metadata +126 -28
  127. data/lib/ea/xmi_class_instantiator.rb +0 -46
  128. data/lib/ea/xmi_helper.rb +0 -26
  129. data/lib/ea/xmi_metamodel.rb +0 -34
  130. data/lib/ea/xmi_object_instantiator.rb +0 -46
  131. data/lib/ea/xmi_to_classmodel.rb +0 -78
  132. data/lib/ea/xmi_to_objectmodel.rb +0 -92
  133. data/lib/mmgen/mm_ext/uml_classmodel_ext.rb +0 -71
  134. data/lib/mmgen/templates/uml_classmodel.tpl +0 -63
  135. data/lib/rgen/xml_instantiator.rb +0 -132
  136. data/lib/uml/objectmodel_instantiator.rb +0 -53
  137. data/lib/uml/uml_classmodel.rb +0 -92
  138. data/lib/uml/uml_objectmodel.rb +0 -65
  139. data/test/metamodel_generator_test.rb +0 -44
  140. data/test/metamodel_generator_test/TestModel.rb +0 -40
  141. data/test/metamodel_generator_test/expected_result.txt +0 -40
  142. data/test/xmi_class_instantiator_test.rb +0 -24
  143. data/test/xmi_instantiator_test/class_model_checker.rb +0 -97
  144. data/test/xmi_object_instantiator_test.rb +0 -65
  145. data/test/xml_instantiator_test/testmodel.xml +0 -7
@@ -0,0 +1,25 @@
1
+ module RGen
2
+
3
+ module ECore
4
+
5
+ # Mixin to provide access to the ECore model describing a Ruby class or module
6
+ # built using MetamodelBuilder.
7
+ # The module should be used to +extend+ a class or module, i.e. to make its
8
+ # methods class methods.
9
+ #
10
+ module ECoreInstantiator
11
+
12
+ # This method will lazily build to ECore model element belonging to the calling
13
+ # class or module using ECoreTransformer.
14
+ #
15
+ def ecore
16
+ require 'rgen/ecore/ecore_transformer'
17
+ @@transformer ||= ECoreTransformer.new
18
+ @@transformer.trans(self)
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,85 @@
1
+ require 'rgen/transformer'
2
+ require 'rgen/ecore/ecore'
3
+
4
+ module RGen
5
+
6
+ module ECore
7
+
8
+ # This transformer creates an ECore model from Ruby classes built
9
+ # by RGen::MetamodelBuilder.
10
+ #
11
+ class ECoreTransformer < Transformer
12
+
13
+ transform Class, :to => EClass, :if => :convert? do
14
+ { :name => name.gsub(/.*::(\w+)$/,'\1'),
15
+ :abstract => false,
16
+ :interface => false,
17
+ :eStructuralFeatures => trans(_metamodel_description),
18
+ :ePackage => trans(name =~ /(.*)::\w+$/ ? eval($1) : nil),
19
+ :eSuperTypes => trans(superclasses),
20
+ :instanceClassName => name,
21
+ :eAnnotations => trans(_annotations)
22
+ }
23
+ end
24
+
25
+ method :superclasses do
26
+ if superclass.respond_to?(:multiple_superclasses) && superclass.multiple_superclasses
27
+ superclass.multiple_superclasses
28
+ else
29
+ [ superclass ]
30
+ end
31
+ end
32
+
33
+ transform Module, :to => EPackage, :if => :convert? do
34
+ { :name => name.gsub(/.*::(\w+)$/,'\1'),
35
+ :eClassifiers => trans(constants.collect{|c| const_get(c)}.select{|c| c.is_a?(Class)}),
36
+ :eSuperPackage => trans(name =~ /(.*)::\w+$/ ? eval($1) : nil),
37
+ :eSubpackages => trans(constants.collect{|c| const_get(c)}.select{|c| c.is_a?(Module) && !c.is_a?(Class)}),
38
+ :eAnnotations => trans(_annotations)
39
+ }
40
+ end
41
+
42
+ method :convert? do
43
+ @current_object.respond_to?(:ecore) && @current_object != RGen::MetamodelBuilder::MMBase
44
+ end
45
+
46
+ transform MetamodelBuilder::AttributeDescription, :to => EAttribute do
47
+ Hash[*MetamodelBuilder::AttributeDescription.propertySet.collect{|p| [p, value(p)]}.flatten].merge({
48
+ :eType => (etype == :EEnumerable ? trans(impl_type) : RGen::ECore.const_get(etype)),
49
+ :eAnnotations => trans(annotations)
50
+ })
51
+ end
52
+
53
+ transform MetamodelBuilder::ReferenceDescription, :to => EReference do
54
+ Hash[*MetamodelBuilder::ReferenceDescription.propertySet.collect{|p| [p, value(p)]}.flatten].merge({
55
+ :eType => trans(impl_type),
56
+ :eOpposite => trans(opposite),
57
+ :eAnnotations => trans(annotations)
58
+ })
59
+ end
60
+
61
+ transform MetamodelBuilder::Intermediate::Annotation, :to => EAnnotation do
62
+ { :source => source,
63
+ :details => details.keys.collect do |k|
64
+ e = EStringToStringMapEntry.new
65
+ e.key = k
66
+ e.value = details[k]
67
+ e
68
+ end
69
+ }
70
+ end
71
+
72
+ transform MetamodelBuilder::DataTypes::Enum, :to => EEnum do
73
+ { :name => name,
74
+ :eLiterals => literals.collect do |l|
75
+ lit = EEnumLiteral.new
76
+ lit.name = l.to_s
77
+ lit
78
+ end }
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+
85
+ end
@@ -1,8 +1,11 @@
1
+ require 'rgen/find_helper'
2
+
1
3
  module RGen
2
4
 
3
5
  # An Environment is used to hold model elements.
4
6
  #
5
7
  class Environment
8
+ include RGen::FindHelper
6
9
 
7
10
  def initialize
8
11
  @elements = []
@@ -15,28 +18,10 @@ class Environment
15
18
  self
16
19
  end
17
20
 
18
- # Finds and returns model elements in the environment.
19
- #
20
- # The search description argument must be a hash specifying attribute/value pairs.
21
- # Only model elements are returned which respond to the specified attribute methods
22
- # and return the specified values as result of these attribute methods.
23
- #
24
- # As a special hash key :class can be used to look for model elements of a specific
25
- # class. In this case an array of possible classes can optionally be given.
26
- #
27
- def find(desc)
28
- result = []
29
- classes = desc[:class] if desc[:class] and desc[:class].is_a?(Array)
30
- classes = [ desc[:class] ] if !classes and desc[:class]
31
- elements.each {|e|
32
- failed = false
33
- failed = true if classes and !classes.any?{ |c| e.is_a?(c) }
34
- desc.each_pair { |k,v|
35
- failed = true if k != :class and ( !e.respond_to?(k) or e.send(k) != v )
36
- }
37
- result << e unless failed
38
- }
39
- result
21
+ # Iterates each element
22
+ #
23
+ def each(&b)
24
+ @elements.each(&b)
40
25
  end
41
26
 
42
27
  # Return the elements of the environment as an array
@@ -48,8 +33,8 @@ class Environment
48
33
  # This method can be used to instantiate a class and automatically put it into
49
34
  # the environment. The new instance is returned.
50
35
  #
51
- def new(clazz)
52
- @elements << clazz.new
36
+ def new(clazz, *args)
37
+ @elements << clazz.new(*args)
53
38
  @elements[-1]
54
39
  end
55
40
  end
@@ -0,0 +1,68 @@
1
+ module RGen
2
+
3
+ module FindHelper
4
+
5
+ # Finds and returns model elements in the environment.
6
+ #
7
+ # The search description argument must be a hash specifying attribute/value pairs.
8
+ # Only model elements are returned which respond to the specified attribute methods
9
+ # and return the specified values as result of these attribute methods.
10
+ #
11
+ # As a special hash key :class can be used to look for model elements of a specific
12
+ # class. In this case an array of possible classes can optionally be given.
13
+ #
14
+ def find(desc)
15
+ result = []
16
+ classes = desc[:class] if desc[:class] and desc[:class].is_a?(Array)
17
+ classes = [ desc[:class] ] if !classes and desc[:class]
18
+ each {|e|
19
+ failed = false
20
+ failed = true if classes and !classes.any?{ |c| e.is_a?(c) }
21
+ desc.each_pair { |k,v|
22
+ failed = true if k != :class and ( !e.respond_to?(k) or e.send(k) != v )
23
+ }
24
+ result << e unless failed
25
+ }
26
+ result
27
+ end
28
+
29
+ def findIndex(index_method)
30
+ index = FindIndex.new(index_method)
31
+ each { |e|
32
+ index.add(e)
33
+ }
34
+ index
35
+ end
36
+
37
+ class FindIndex
38
+
39
+ def initialize(index_method)
40
+ @index_method = index_method.to_sym
41
+ @index = {}
42
+ @non_indexed = [].extend(FindHelper)
43
+ end
44
+
45
+ def add(element)
46
+ if element.respond_to?(@index_method)
47
+ val = element.send(@index_method)
48
+ @index[val] ||= [].extend(FindHelper)
49
+ @index[val] << element
50
+ end
51
+ @non_indexed << element
52
+ end
53
+
54
+ def find(desc)
55
+ if (desc.keys.include?(@index_method))
56
+ val = desc.delete(@index_method)
57
+ return [] unless @index[val]
58
+ return @index[val].find(desc)
59
+ else
60
+ return @non_indexed.find(desc)
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+ end
@@ -1,6 +1,8 @@
1
1
  module RGen
2
2
 
3
- class Instantiator
3
+ module Instantiator
4
+
5
+ class AbstractInstantiator
4
6
 
5
7
  ResolverDescription = Struct.new(:from, :attribute, :block) # :nodoc:
6
8
 
@@ -8,7 +10,7 @@ class Instantiator
8
10
  attr_accessor :resolver_descs
9
11
  end
10
12
 
11
- def initialize(env, mod)
13
+ def initialize(env)
12
14
  @env = env
13
15
  end
14
16
 
@@ -59,4 +61,6 @@ class Instantiator
59
61
 
60
62
  end
61
63
 
64
+ end
65
+
62
66
  end
@@ -0,0 +1,59 @@
1
+ $:.unshift File.join(File.dirname(__FILE__),"..","..","..","redist","xmlscan","lib")
2
+
3
+ require 'xmlscan/namespace'
4
+
5
+ class AbstractXMLInstantiator
6
+
7
+ class XMLScanVisitor
8
+ include XMLScan::NSVisitor
9
+
10
+ def initialize(inst)
11
+ @current_attributes = {}
12
+ @instantiator = inst
13
+ end
14
+
15
+ def on_attribute_ns(qname, prefix, localpart)
16
+ @current_attr_name = qname
17
+ end
18
+
19
+ def on_attr_value(str)
20
+ @current_attributes[@current_attr_name] = str
21
+ end
22
+
23
+ def split_qname(qname)
24
+ if qname =~ /^([^:]+):([^:]+)$/
25
+ prefix, tag = $1, $2
26
+ else
27
+ prefix, tag = nil, qname
28
+ end
29
+ return prefix, tag
30
+ end
31
+
32
+ def on_stag_end_ns(qname, namespaces)
33
+ prefix, tag = split_qname(qname)
34
+ @instantiator.start_tag(prefix, tag, namespaces, @current_attributes)
35
+ @current_attributes.each_pair { |k,v| @instantiator.set_attribute(k, v) }
36
+ @current_attributes = {}
37
+ end
38
+
39
+ def on_stag_end_empty_ns(qname, namespaces)
40
+ prefix, tag = split_qname(qname)
41
+ @instantiator.start_tag(prefix, tag, namespaces, @current_attributes)
42
+ @current_attributes.each_pair { |k,v| @instantiator.set_attribute(k, v) }
43
+ @current_attributes = {}
44
+ @instantiator.end_tag(prefix, tag)
45
+ end
46
+
47
+ def on_etag(qname)
48
+ prefix, tag = split_qname(qname)
49
+ @instantiator.end_tag(prefix, tag)
50
+ end
51
+ end
52
+
53
+ def instantiate(str)
54
+ visitor = XMLScanVisitor.new(self)
55
+ parser = XMLScan::XMLParserNS.new(visitor)
56
+ parser.parse(str)
57
+ end
58
+
59
+ end
@@ -0,0 +1,117 @@
1
+ require 'rgen/instantiator/nodebased_xml_instantiator'
2
+
3
+ module RGen
4
+
5
+ module Instantiator
6
+
7
+ # A default XML instantiator.
8
+ # Derive your own instantiator from this class or use it as is.
9
+ #
10
+ class DefaultXMLInstantiator < NodebasedXMLInstantiator
11
+ include NameHelper
12
+
13
+ NamespaceDescriptor = Struct.new(:prefix, :target)
14
+
15
+ class << self
16
+
17
+ def map_tag_ns(from, to, prefix="")
18
+ tag_ns_map[from] = NamespaceDescriptor.new(prefix, to)
19
+ end
20
+
21
+ def tag_ns_map # :nodoc:
22
+ @tag_ns_map ||={}
23
+ @tag_ns_map
24
+ end
25
+
26
+ end
27
+
28
+ def initialize(env, default_module, create_mm=false)
29
+ super(env)
30
+ @default_module = default_module
31
+ @create_mm = create_mm
32
+ end
33
+
34
+ def on_descent(node)
35
+ obj = new_object(node)
36
+ @env << obj unless obj.nil?
37
+ node.object = obj
38
+ node.attributes.each_pair { |k,v| set_attribute(node, k, v) }
39
+ end
40
+
41
+ def on_ascent(node)
42
+ node.children.each { |c| assoc_p2c(node, c) }
43
+ node.object.class.has_attr 'chardata', Object unless node.object.respond_to?(:chardata)
44
+ set_attribute(node, "chardata", node.chardata)
45
+ end
46
+
47
+ def class_name(str)
48
+ saneClassName(str)
49
+ end
50
+
51
+ def new_object(node)
52
+ ns_desc = self.class.tag_ns_map[node.namespace]
53
+ class_name = class_name(ns_desc.nil? ? node.qtag : ns_desc.prefix+node.tag)
54
+ mod = (ns_desc && ns_desc.target) || @default_module
55
+ build_on_error(NameError, :build_class, class_name, mod) do
56
+ mod.const_get(class_name).new
57
+ end
58
+ end
59
+
60
+ def build_class(name, mod)
61
+ mod.const_set(name, Class.new(RGen::MetamodelBuilder::MMBase))
62
+ end
63
+
64
+ def method_name(str)
65
+ saneMethodName(str)
66
+ end
67
+
68
+ def assoc_p2c(parent, child)
69
+ return unless parent.object && child.object
70
+ method_name = method_name(className(child.object))
71
+ build_on_error(NoMethodError, :build_p2c_assoc, parent, child, method_name) do
72
+ parent.object.addGeneric(method_name, child.object)
73
+ child.object.setGeneric("parent", parent.object)
74
+ end
75
+ end
76
+
77
+ def build_p2c_assoc(parent, child, method_name)
78
+ parent.object.class.has_many(method_name, child.object.class)
79
+ child.object.class.has_one("parent", RGen::MetamodelBuilder::MMBase)
80
+ end
81
+
82
+ def set_attribute(node, attr, value)
83
+ return unless node.object
84
+ build_on_error(NoMethodError, :build_attribute, node, attr, value) do
85
+ node.object.setGeneric(method_name(attr), value)
86
+ end
87
+ end
88
+
89
+ def build_attribute(node, attr, value)
90
+ node.object.class.has_attr(method_name(attr))
91
+ end
92
+
93
+ protected
94
+
95
+ # Helper method for implementing classes.
96
+ # This method yields the given block.
97
+ # If the metamodel should be create automatically (see constructor)
98
+ # rescues +error+ and calls +builder_method+ with +args+, then
99
+ # yields the block again.
100
+ def build_on_error(error, builder_method, *args)
101
+ begin
102
+ yield
103
+ rescue error
104
+ if @create_mm
105
+ send(builder_method, *args)
106
+ yield
107
+ else
108
+ raise
109
+ end
110
+ end
111
+ end
112
+
113
+ end
114
+
115
+ end
116
+
117
+ end
@@ -0,0 +1,144 @@
1
+ require 'rgen/ecore/ecore'
2
+ require 'rgen/instantiator/abstract_xml_instantiator'
3
+ require 'rgen/array_extensions'
4
+
5
+ class ECoreXMLInstantiator < AbstractXMLInstantiator
6
+
7
+ include RGen::ECore
8
+
9
+ INFO = 0
10
+ WARN = 1
11
+ ERROR = 2
12
+
13
+ def initialize(env, loglevel=ERROR)
14
+ @env = env
15
+ @rolestack = []
16
+ @elementstack = []
17
+ @loglevel = loglevel
18
+ end
19
+
20
+ def start_tag(prefix, tag, namespaces, attributes)
21
+ eRef = nil
22
+ if @elementstack.last
23
+ eRef = eAllReferences(@elementstack.last).find{|r|r.name == tag}
24
+ if eRef
25
+ if attributes["xsi:type"] && attributes["xsi:type"] =~ /ecore:(\w+)/
26
+ class_name = $1
27
+ attributes.delete("xsi:type")
28
+ else
29
+ class_name = eRef.eType.name
30
+ end
31
+ else
32
+ raise "Reference not found: #{tag} on #{@elementstack.last}"
33
+ end
34
+ else
35
+ class_name = tag
36
+ end
37
+
38
+ eClass = RGen::ECore.ecore.eClassifiers.find{|c| c.name == class_name}
39
+ if eClass
40
+ obj = RGen::ECore.const_get(class_name).new
41
+ if eRef
42
+ if eRef.many
43
+ @elementstack.last.addGeneric(eRef.name, obj)
44
+ else
45
+ @elementstack.last.setGeneric(eRef.name, obj)
46
+ end
47
+ end
48
+ @env << obj
49
+ @elementstack.push obj
50
+ else
51
+ log WARN, "Class not found: #{class_name}"
52
+ @elementstack.push nil
53
+ end
54
+ end
55
+
56
+ def end_tag(prefix, tag)
57
+ @elementstack.pop
58
+ end
59
+
60
+ ResolverDescription = Struct.new(:object, :attribute, :value)
61
+
62
+ def set_attribute(attr, value)
63
+ return unless @elementstack.last
64
+ eFeat = eAllStructuralFeatures(@elementstack.last).find{|a| a.name == attr}
65
+ if eFeat.is_a?(EReference)
66
+ rd = ResolverDescription.new
67
+ rd.object = @elementstack.last
68
+ rd.attribute = attr
69
+ rd.value = value
70
+ @resolver_descs << rd
71
+ elsif eFeat
72
+ value = true if value == "true" && eFeat.eType == EBoolean
73
+ value = false if value == "false" && eFeat.eType == EBoolean
74
+ value = value.to_i if eFeat.eType == EInt
75
+ @elementstack.last.setGeneric(attr, value)
76
+ else
77
+ log WARN, "Feature not found: #{attr} on #{@elementstack.last}"
78
+ end
79
+ end
80
+
81
+ def instantiate(str)
82
+ @resolver_descs = []
83
+ # puts "Instantiating ..."
84
+ super
85
+ rootpackage = @env.find(:class => EPackage).first
86
+ # puts "Resolving ..."
87
+ @resolver_descs.each do |rd|
88
+ refed = find_referenced(rootpackage, rd.value)
89
+ feature = eAllStructuralFeatures(rd.object).find{|f| f.name == rd.attribute}
90
+ raise StandardError.new("StructuralFeature not found: #{rd.attribute}") unless feature
91
+ if feature.many
92
+ rd.object.setGeneric(feature.name, refed)
93
+ else
94
+ rd.object.setGeneric(feature.name, refed.first)
95
+ end
96
+ end
97
+ end
98
+
99
+ def eAllReferences(element)
100
+ @eAllReferences ||= {}
101
+ @eAllReferences[element.class] ||= element.class.ecore.eAllReferences
102
+ end
103
+
104
+ def eAllAttributes(element)
105
+ @eAllAttributes ||= {}
106
+ @eAllAttributes[element.class] ||= element.class.ecore.eAllAttributes
107
+ end
108
+
109
+ def eAllStructuralFeatures(element)
110
+ @eAllStructuralFeatures ||= {}
111
+ @eAllStructuralFeatures[element.class] ||= element.class.ecore.eAllStructuralFeatures
112
+ end
113
+
114
+ def find_referenced(context, desc)
115
+ desc.split(/\s+/).collect do |r|
116
+ if r =~ /^#\/\d*\/([\w\/]+)/
117
+ find_in_context(context, $1.split('/'))
118
+ end
119
+ end.compact
120
+ end
121
+
122
+ def find_in_context(context, desc_elements)
123
+ if context.is_a?(EPackage)
124
+ r = (context.eClassifiers + context.eSubpackages).find{|c| c.name == desc_elements.first}
125
+ elsif context.is_a?(EClass)
126
+ r = context.eStructuralFeatures.find{|s| s.name == desc_elements.first}
127
+ else
128
+ raise StandardError.new("Don't know how to find #{desc_elements.join('/')} in context #{context}")
129
+ end
130
+ if r
131
+ if desc_elements.size > 1
132
+ find_in_context(r, desc_elements[1..-1])
133
+ else
134
+ r
135
+ end
136
+ else
137
+ log WARN, "Can not follow path, element #{desc_elements.first} not found within #{context}(#{context.name})"
138
+ end
139
+ end
140
+
141
+ def log(level, msg)
142
+ puts %w(INFO WARN ERROR)[level] + ": " + msg if level >= @loglevel
143
+ end
144
+ end