rgen 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +20 -1
- data/MIT-LICENSE +1 -1
- data/README +12 -9
- data/lib/instantiators/ea_instantiator.rb +36 -0
- data/lib/metamodels/uml13_metamodel.rb +559 -0
- data/lib/metamodels/uml13_metamodel_ext.rb +26 -0
- data/lib/mmgen/metamodel_generator.rb +5 -5
- data/lib/mmgen/mm_ext/ecore_ext.rb +95 -0
- data/lib/mmgen/mmgen.rb +6 -4
- data/lib/mmgen/templates/annotations.tpl +37 -0
- data/lib/mmgen/templates/metamodel_generator.tpl +171 -0
- data/lib/rgen/ecore/ecore.rb +190 -0
- data/lib/rgen/ecore/ecore_instantiator.rb +25 -0
- data/lib/rgen/ecore/ecore_transformer.rb +85 -0
- data/lib/rgen/environment.rb +9 -24
- data/lib/rgen/find_helper.rb +68 -0
- data/lib/rgen/{instantiator.rb → instantiator/abstract_instantiator.rb} +6 -2
- data/lib/rgen/instantiator/abstract_xml_instantiator.rb +59 -0
- data/lib/rgen/instantiator/default_xml_instantiator.rb +117 -0
- data/lib/rgen/instantiator/ecore_xml_instantiator.rb +144 -0
- data/lib/rgen/instantiator/nodebased_xml_instantiator.rb +157 -0
- data/lib/rgen/instantiator/xmi11_instantiator.rb +164 -0
- data/lib/rgen/metamodel_builder.rb +103 -9
- data/lib/rgen/metamodel_builder/build_helper.rb +26 -4
- data/lib/rgen/metamodel_builder/builder_extensions.rb +285 -88
- data/lib/rgen/metamodel_builder/builder_runtime.rb +7 -1
- data/lib/rgen/metamodel_builder/data_types.rb +67 -0
- data/lib/rgen/metamodel_builder/intermediate/annotation.rb +30 -0
- data/lib/rgen/metamodel_builder/metamodel_description.rb +232 -0
- data/lib/rgen/metamodel_builder/mm_multiple.rb +23 -0
- data/lib/rgen/metamodel_builder/module_extension.rb +33 -0
- data/lib/rgen/model_comparator.rb +56 -0
- data/lib/rgen/model_dumper.rb +5 -5
- data/lib/rgen/name_helper.rb +17 -1
- data/lib/rgen/template_language.rb +148 -28
- data/lib/rgen/template_language/directory_template_container.rb +56 -38
- data/lib/rgen/template_language/output_handler.rb +93 -77
- data/lib/rgen/template_language/template_container.rb +186 -143
- data/lib/rgen/transformer.rb +19 -14
- data/lib/transformers/uml13_to_ecore.rb +75 -0
- data/redist/xmlscan/ChangeLog +1301 -0
- data/redist/xmlscan/README +34 -0
- data/redist/xmlscan/THANKS +11 -0
- data/redist/xmlscan/doc/changes.html +74 -0
- data/redist/xmlscan/doc/changes.rd +80 -0
- data/redist/xmlscan/doc/en/conformance.html +136 -0
- data/redist/xmlscan/doc/en/conformance.rd +152 -0
- data/redist/xmlscan/doc/en/manual.html +356 -0
- data/redist/xmlscan/doc/en/manual.rd +402 -0
- data/redist/xmlscan/doc/ja/conformance.ja.html +118 -0
- data/redist/xmlscan/doc/ja/conformance.ja.rd +134 -0
- data/redist/xmlscan/doc/ja/manual.ja.html +325 -0
- data/redist/xmlscan/doc/ja/manual.ja.rd +370 -0
- data/redist/xmlscan/doc/src/Makefile +41 -0
- data/redist/xmlscan/doc/src/conformance.rd.src +256 -0
- data/redist/xmlscan/doc/src/langsplit.rb +110 -0
- data/redist/xmlscan/doc/src/manual.rd.src +614 -0
- data/redist/xmlscan/install.rb +41 -0
- data/redist/xmlscan/lib/xmlscan/encoding.rb +311 -0
- data/redist/xmlscan/lib/xmlscan/htmlscan.rb +289 -0
- data/redist/xmlscan/lib/xmlscan/namespace.rb +352 -0
- data/redist/xmlscan/lib/xmlscan/parser.rb +299 -0
- data/redist/xmlscan/lib/xmlscan/scanner.rb +1109 -0
- data/redist/xmlscan/lib/xmlscan/version.rb +22 -0
- data/redist/xmlscan/lib/xmlscan/visitor.rb +158 -0
- data/redist/xmlscan/lib/xmlscan/xmlchar.rb +441 -0
- data/redist/xmlscan/memo/CONFORMANCE +1249 -0
- data/redist/xmlscan/memo/PRODUCTIONS +195 -0
- data/redist/xmlscan/memo/contentspec.ry +335 -0
- data/redist/xmlscan/samples/chibixml.rb +105 -0
- data/redist/xmlscan/samples/getxmlchar.rb +122 -0
- data/redist/xmlscan/samples/rexml.rb +159 -0
- data/redist/xmlscan/samples/xmlbench.rb +88 -0
- data/redist/xmlscan/samples/xmlbench/parser/chibixml.rb +22 -0
- data/redist/xmlscan/samples/xmlbench/parser/nqxml.rb +29 -0
- data/redist/xmlscan/samples/xmlbench/parser/rexml.rb +62 -0
- data/redist/xmlscan/samples/xmlbench/parser/xmlparser.rb +22 -0
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan-0.0.10.rb +62 -0
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan-chibixml.rb +22 -0
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan-rexml.rb +22 -0
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan.rb +99 -0
- data/redist/xmlscan/samples/xmlbench/xmlbench-lib.rb +116 -0
- data/redist/xmlscan/samples/xmlconftest.rb +200 -0
- data/redist/xmlscan/test.rb +7 -0
- data/redist/xmlscan/tests/deftestcase.rb +73 -0
- data/redist/xmlscan/tests/runtest.rb +47 -0
- data/redist/xmlscan/tests/testall.rb +14 -0
- data/redist/xmlscan/tests/testencoding.rb +438 -0
- data/redist/xmlscan/tests/testhtmlscan.rb +752 -0
- data/redist/xmlscan/tests/testnamespace.rb +457 -0
- data/redist/xmlscan/tests/testparser.rb +591 -0
- data/redist/xmlscan/tests/testscanner.rb +1749 -0
- data/redist/xmlscan/tests/testxmlchar.rb +143 -0
- data/redist/xmlscan/tests/visitor.rb +34 -0
- data/test/array_extensions_test.rb +2 -2
- data/test/ea_instantiator_test.rb +41 -0
- data/test/ecore_self_test.rb +53 -0
- data/test/environment_test.rb +11 -6
- data/test/metamodel_builder_test.rb +404 -245
- data/test/metamodel_roundtrip_test.rb +52 -0
- data/test/metamodel_roundtrip_test/TestModel.rb +65 -0
- data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +64 -0
- data/test/metamodel_roundtrip_test/houseMetamodel.ecore +32 -0
- data/test/metamodel_roundtrip_test/houseMetamodel_from_ecore.rb +39 -0
- data/test/rgen_test.rb +3 -3
- data/test/template_language_test.rb +65 -39
- data/test/template_language_test/expected_result.txt +24 -3
- data/test/template_language_test/templates/code/array.tpl +11 -0
- data/test/template_language_test/templates/content/author.tpl +7 -0
- data/test/template_language_test/templates/content/chapter.tpl +1 -1
- data/test/template_language_test/templates/root.tpl +17 -8
- data/test/template_language_test/testout.txt +24 -3
- data/test/testmodel/class_model_checker.rb +119 -0
- data/test/{xmi_instantiator_test/testmodel.eap → testmodel/ea_testmodel.eap} +0 -0
- data/test/{xmi_instantiator_test/testmodel.xml → testmodel/ea_testmodel.xml} +81 -14
- data/test/testmodel/ea_testmodel_partial.xml +317 -0
- data/test/testmodel/ecore_model_checker.rb +101 -0
- data/test/testmodel/manual_testmodel.xml +22 -0
- data/test/testmodel/object_model_checker.rb +67 -0
- data/test/transformer_test.rb +18 -10
- data/test/xml_instantiator_test.rb +81 -8
- data/test/xml_instantiator_test/simple_ecore_model_checker.rb +94 -0
- data/test/xml_instantiator_test/simple_xmi_ecore_instantiator.rb +53 -0
- data/test/xml_instantiator_test/simple_xmi_metamodel.rb +49 -0
- data/test/xml_instantiator_test/simple_xmi_to_ecore.rb +75 -0
- metadata +126 -28
- data/lib/ea/xmi_class_instantiator.rb +0 -46
- data/lib/ea/xmi_helper.rb +0 -26
- data/lib/ea/xmi_metamodel.rb +0 -34
- data/lib/ea/xmi_object_instantiator.rb +0 -46
- data/lib/ea/xmi_to_classmodel.rb +0 -78
- data/lib/ea/xmi_to_objectmodel.rb +0 -92
- data/lib/mmgen/mm_ext/uml_classmodel_ext.rb +0 -71
- data/lib/mmgen/templates/uml_classmodel.tpl +0 -63
- data/lib/rgen/xml_instantiator.rb +0 -132
- data/lib/uml/objectmodel_instantiator.rb +0 -53
- data/lib/uml/uml_classmodel.rb +0 -92
- data/lib/uml/uml_objectmodel.rb +0 -65
- data/test/metamodel_generator_test.rb +0 -44
- data/test/metamodel_generator_test/TestModel.rb +0 -40
- data/test/metamodel_generator_test/expected_result.txt +0 -40
- data/test/xmi_class_instantiator_test.rb +0 -24
- data/test/xmi_instantiator_test/class_model_checker.rb +0 -97
- data/test/xmi_object_instantiator_test.rb +0 -65
- 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
|
data/lib/rgen/environment.rb
CHANGED
@@ -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
|
-
#
|
19
|
-
#
|
20
|
-
|
21
|
-
|
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
|
-
|
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
|
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
|