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.
- 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
|