rgen 0.3.0 → 0.4.0

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