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,157 @@
|
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),"..","..","..","redist","xmlscan","lib")
|
|
2
|
+
|
|
3
|
+
require 'rgen/metamodel_builder'
|
|
4
|
+
require 'rgen/instantiator/abstract_instantiator'
|
|
5
|
+
require 'xmlscan/namespace'
|
|
6
|
+
|
|
7
|
+
module RGen
|
|
8
|
+
|
|
9
|
+
module Instantiator
|
|
10
|
+
|
|
11
|
+
class NodebasedXMLInstantiator < AbstractInstantiator
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
|
|
15
|
+
# The prune level is the number of parent/children associations which
|
|
16
|
+
# is kept when the instantiator ascents the XML tree.
|
|
17
|
+
# If the level is 2, information for the node's children and the childrens'
|
|
18
|
+
# children will be available as an XMLNodeDescriptor object.
|
|
19
|
+
# If the level is 0 no pruning will take place, i.e. the whole information
|
|
20
|
+
# is kept until the end of the instantiation process. 0 is default.
|
|
21
|
+
def set_prune_level(level)
|
|
22
|
+
@prune_level = level
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def prune_level # :nodoc:
|
|
26
|
+
@prune_level ||= 0
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class XMLNodeDescriptor
|
|
32
|
+
attr_reader :namespace, :qtag, :prefix, :tag, :parent, :attributes, :chardata
|
|
33
|
+
attr_accessor :object, :children
|
|
34
|
+
|
|
35
|
+
def initialize(ns, qtag, prefix, tag, parent, children, attributes)
|
|
36
|
+
@namespace, @qtag, @prefix, @tag, @parent, @children, @attributes =
|
|
37
|
+
ns, qtag, prefix, tag, parent, children, attributes
|
|
38
|
+
@parent.children << self if @parent
|
|
39
|
+
@chardata = []
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class XMLScanVisitor
|
|
44
|
+
attr_reader :namespaces
|
|
45
|
+
|
|
46
|
+
include XMLScan::NSVisitor
|
|
47
|
+
|
|
48
|
+
def initialize(inst)
|
|
49
|
+
@current_attributes = {}
|
|
50
|
+
@instantiator = inst
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def on_attribute_ns(qname, prefix, localpart)
|
|
54
|
+
@current_attr_name = qname
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def on_attr_value(str)
|
|
58
|
+
@current_attributes[@current_attr_name] = str
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def on_stag_end_ns(qname, namespaces)
|
|
62
|
+
@namespaces = namespaces
|
|
63
|
+
if qname =~ /^([^:]+):([^:]+)$/
|
|
64
|
+
prefix, tag = $1, $2
|
|
65
|
+
else
|
|
66
|
+
prefix, tag = nil, qname
|
|
67
|
+
end
|
|
68
|
+
@instantiator.start_element(namespaces[prefix], qname, prefix, tag, @current_attributes)
|
|
69
|
+
@current_attributes = {}
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def on_stag_end_empty_ns(qname, namespaces)
|
|
73
|
+
on_stag_end_ns(qname, namespaces)
|
|
74
|
+
@instantiator.end_element
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def on_etag(name)
|
|
78
|
+
@instantiator.end_element
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def on_chardata(str)
|
|
82
|
+
@instantiator.on_chardata(str)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def initialize(env)
|
|
87
|
+
super
|
|
88
|
+
@env = env
|
|
89
|
+
@stack = []
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def instantiate_file(file)
|
|
93
|
+
File.open(file) { |f| parse(f.read)}
|
|
94
|
+
resolve
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def instantiate(text)
|
|
98
|
+
parse(text)
|
|
99
|
+
resolve
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def parse(src)
|
|
103
|
+
@visitor = XMLScanVisitor.new(self)
|
|
104
|
+
parser = XMLScan::XMLParserNS.new(@visitor)
|
|
105
|
+
parser.parse(src)
|
|
106
|
+
@visitor = nil
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def start_element(ns, qtag, prefix, tag, attributes)
|
|
110
|
+
node = XMLNodeDescriptor.new(ns, qtag, prefix, tag, @stack[-1], [], attributes)
|
|
111
|
+
@stack.push node
|
|
112
|
+
on_descent(node)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def end_element
|
|
116
|
+
node = @stack.pop
|
|
117
|
+
on_ascent(node)
|
|
118
|
+
prune_children(node, self.class.prune_level - 1) if self.class.prune_level > 0
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def on_chardata(str)
|
|
122
|
+
node = @stack.last
|
|
123
|
+
node.chardata << str
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# This method is called when the XML parser goes down the tree.
|
|
127
|
+
# An XMLNodeDescriptor +node+ describes the current node.
|
|
128
|
+
# Implementing classes must overwrite this method.
|
|
129
|
+
def on_descent(node)
|
|
130
|
+
raise "Overwrite this method !"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# This method is called when the XML parser goes up the tree.
|
|
134
|
+
# An XMLNodeDescriptor +node+ describes the current node.
|
|
135
|
+
# Implementing classes must overwrite this method.
|
|
136
|
+
def on_ascent(node)
|
|
137
|
+
raise "Overwrite this method !"
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def namespaces
|
|
141
|
+
@visitor.namespaces if @visitor
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
private
|
|
145
|
+
|
|
146
|
+
def prune_children(node, level)
|
|
147
|
+
if level == 0
|
|
148
|
+
node.children = nil
|
|
149
|
+
else
|
|
150
|
+
node.children.each { |c| prune_children(c, level-1) }
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
end
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
require 'rgen/ecore/ecore'
|
|
2
|
+
require 'rgen/instantiator/abstract_xml_instantiator'
|
|
3
|
+
require 'rgen/array_extensions'
|
|
4
|
+
|
|
5
|
+
class XMI11Instantiator < AbstractXMLInstantiator
|
|
6
|
+
|
|
7
|
+
include RGen::ECore
|
|
8
|
+
|
|
9
|
+
ResolverDescription = Struct.new(:object, :attribute, :value, :many)
|
|
10
|
+
|
|
11
|
+
INFO = 0
|
|
12
|
+
WARN = 1
|
|
13
|
+
ERROR = 2
|
|
14
|
+
|
|
15
|
+
def initialize(env, fix_map={}, loglevel=ERROR)
|
|
16
|
+
@env = env
|
|
17
|
+
@fix_map = fix_map
|
|
18
|
+
@loglevel = loglevel
|
|
19
|
+
@rolestack = []
|
|
20
|
+
@elementstack = []
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def add_metamodel(ns, mod)
|
|
24
|
+
@ns_module_map ||={}
|
|
25
|
+
@ns_module_map[ns] = mod
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def instantiate(str)
|
|
29
|
+
@resolver_descs = []
|
|
30
|
+
@element_by_id = {}
|
|
31
|
+
super(str)
|
|
32
|
+
@resolver_descs.each do |rd|
|
|
33
|
+
if rd.many
|
|
34
|
+
newval = rd.value.split(" ").collect{|v| @element_by_id[v]}
|
|
35
|
+
else
|
|
36
|
+
newval = @element_by_id[rd.value]
|
|
37
|
+
end
|
|
38
|
+
log WARN, "Could not resolve reference #{rd.attribute} on #{rd.object}" unless newval
|
|
39
|
+
rd.object.setGeneric(rd.attribute,newval)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def start_tag(prefix, tag, namespaces, attributes)
|
|
44
|
+
if tag =~ /\w+\.(\w+)/
|
|
45
|
+
# XMI role
|
|
46
|
+
role_name = map_feature_name($1) || $1
|
|
47
|
+
eRef = @elementstack.last && eAllReferences(@elementstack.last).find{|r|r.name == role_name}
|
|
48
|
+
log WARN, "No reference found for #{role_name} on #{@elementstack.last}" unless eRef
|
|
49
|
+
@rolestack.push eRef
|
|
50
|
+
elsif attributes["xmi.idref"]
|
|
51
|
+
# reference
|
|
52
|
+
rd = ResolverDescription.new
|
|
53
|
+
rd.object = @elementstack.last
|
|
54
|
+
rd.attribute = @rolestack.last.name
|
|
55
|
+
rd.value = attributes["xmi.idref"]
|
|
56
|
+
rd.many = @rolestack.last.many
|
|
57
|
+
@resolver_descs << rd
|
|
58
|
+
@elementstack.push nil
|
|
59
|
+
else
|
|
60
|
+
# model element
|
|
61
|
+
value = map_tag(tag, attributes) || tag
|
|
62
|
+
if value.is_a?(String)
|
|
63
|
+
mod = @ns_module_map[namespaces[prefix]]
|
|
64
|
+
unless mod
|
|
65
|
+
log WARN, "Ignoring tag #{tag}"
|
|
66
|
+
return
|
|
67
|
+
end
|
|
68
|
+
value = mod.const_get(value).new
|
|
69
|
+
end
|
|
70
|
+
@env << value
|
|
71
|
+
eRef = @rolestack.last
|
|
72
|
+
if eRef && eRef.many
|
|
73
|
+
@elementstack.last.addGeneric(eRef.name, value)
|
|
74
|
+
elsif eRef
|
|
75
|
+
@elementstack.last.setGeneric(eRef.name, value)
|
|
76
|
+
end
|
|
77
|
+
@elementstack.push value
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def end_tag(prefix, tag)
|
|
82
|
+
if tag =~ /\w+\.(\w+)/
|
|
83
|
+
@rolestack.pop
|
|
84
|
+
else
|
|
85
|
+
@elementstack.pop
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def set_attribute(attr, value)
|
|
90
|
+
return unless @elementstack.last
|
|
91
|
+
if attr == "xmi.id"
|
|
92
|
+
@element_by_id[value] = @elementstack.last
|
|
93
|
+
else
|
|
94
|
+
attr_name = map_feature_name(attr) || attr
|
|
95
|
+
eFeat = eAllStructuralFeatures(@elementstack.last).find{|a| a.name == attr_name}
|
|
96
|
+
unless eFeat
|
|
97
|
+
log WARN, "No structural feature found for #{attr_name} on #{@elementstack.last}"
|
|
98
|
+
return
|
|
99
|
+
end
|
|
100
|
+
if eFeat.is_a?(RGen::ECore::EReference)
|
|
101
|
+
if map_feature_value(attr_name, value).is_a?(eFeat.eType.instanceClass)
|
|
102
|
+
@elementstack.last.setGeneric(attr_name, map_feature_value(attr_name, value))
|
|
103
|
+
else
|
|
104
|
+
rd = ResolverDescription.new
|
|
105
|
+
rd.object = @elementstack.last
|
|
106
|
+
rd.attribute = attr_name
|
|
107
|
+
rd.value = value
|
|
108
|
+
rd.many = eFeat.many
|
|
109
|
+
@resolver_descs << rd
|
|
110
|
+
end
|
|
111
|
+
else
|
|
112
|
+
value = map_feature_value(attr_name, value) || value
|
|
113
|
+
value = true if value == "true" && eFeat.eType == EBoolean
|
|
114
|
+
value = false if value == "false" && eFeat.eType == EBoolean
|
|
115
|
+
value = value.to_i if eFeat.eType == EInt
|
|
116
|
+
value = value.to_f if eFeat.eType == EFloat
|
|
117
|
+
value = value.to_sym if eFeat.eType.is_a?(EEnum)
|
|
118
|
+
@elementstack.last.setGeneric(attr_name, value)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
private
|
|
124
|
+
|
|
125
|
+
def map_tag(tag, attributes)
|
|
126
|
+
tag_map = @fix_map[:tags] || {}
|
|
127
|
+
value = tag_map[tag]
|
|
128
|
+
if value.is_a?(Proc)
|
|
129
|
+
value.call(tag, attributes)
|
|
130
|
+
else
|
|
131
|
+
value
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def map_feature_name(name)
|
|
136
|
+
name_map = @fix_map[:feature_names] || {}
|
|
137
|
+
name_map[name]
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def map_feature_value(attr_name, value)
|
|
141
|
+
value_map = @fix_map[:feature_values] || {}
|
|
142
|
+
map = value_map[attr_name]
|
|
143
|
+
if map.is_a?(Hash)
|
|
144
|
+
map[value]
|
|
145
|
+
elsif map.is_a?(Proc)
|
|
146
|
+
map.call(value)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def log(level, msg)
|
|
151
|
+
puts %w(INFO WARN ERROR)[level] + ": " + msg if level >= @loglevel
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def eAllReferences(element)
|
|
155
|
+
@eAllReferences ||= {}
|
|
156
|
+
@eAllReferences[element.class] ||= element.class.ecore.eAllReferences
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def eAllStructuralFeatures(element)
|
|
160
|
+
@eAllStructuralFeatures ||= {}
|
|
161
|
+
@eAllStructuralFeatures[element.class] ||= element.class.ecore.eAllStructuralFeatures
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
end
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
require 'rgen/metamodel_builder/builder_runtime'
|
|
5
5
|
require 'rgen/metamodel_builder/builder_extensions'
|
|
6
|
+
require 'rgen/metamodel_builder/module_extension'
|
|
7
|
+
require 'rgen/metamodel_builder/data_types'
|
|
8
|
+
require 'rgen/metamodel_builder/mm_multiple'
|
|
9
|
+
require 'rgen/ecore/ecore_instantiator'
|
|
6
10
|
|
|
7
11
|
module RGen
|
|
8
12
|
|
|
@@ -23,12 +27,12 @@ module RGen
|
|
|
23
27
|
# Here is an example:
|
|
24
28
|
#
|
|
25
29
|
# class Person < RGen::MetamodelBuilder::MMBase
|
|
26
|
-
#
|
|
27
|
-
#
|
|
30
|
+
# has_attr 'name', String
|
|
31
|
+
# has_attr 'age', Integer
|
|
28
32
|
# end
|
|
29
33
|
#
|
|
30
34
|
# class House < RGen::MetamodelBuilder::MMBase
|
|
31
|
-
#
|
|
35
|
+
# has_attr 'address' # String is default
|
|
32
36
|
# end
|
|
33
37
|
#
|
|
34
38
|
# Person.many_to_many 'homes', House, 'inhabitants'
|
|
@@ -53,8 +57,7 @@ module RGen
|
|
|
53
57
|
#
|
|
54
58
|
# p.name = :myName # => exception: can not put a Symbol where a String is expected
|
|
55
59
|
#
|
|
56
|
-
# If the type of an attribute should be left undefined,
|
|
57
|
-
# second argument of 'has_one' as show at the attribute 'address' for House.
|
|
60
|
+
# If the type of an attribute should be left undefined, use Object as type.
|
|
58
61
|
#
|
|
59
62
|
# =Associations
|
|
60
63
|
#
|
|
@@ -81,11 +84,92 @@ module RGen
|
|
|
81
84
|
# exception:
|
|
82
85
|
#
|
|
83
86
|
# p.addHomes(:justASymbol) # => exception: can not put a Symbol where a House is expected
|
|
87
|
+
#
|
|
88
|
+
# =ECore Metamodel description
|
|
89
|
+
#
|
|
90
|
+
# The class methods described above are used to create a Ruby representation of the metamodel
|
|
91
|
+
# we have in mind in a very simple and easy way. We don't have to care about all the details
|
|
92
|
+
# of a metamodel at this point (e.g. multiplicities, changeability, etc).
|
|
93
|
+
#
|
|
94
|
+
# At the same time however, an instance of the ECore metametamodel (i.e. a ECore based
|
|
95
|
+
# description of our metamodel) is provided for all the Ruby classes and modules we create.
|
|
96
|
+
# Since we did not provide the nitty-gritty details of the metamodel, defaults are used to
|
|
97
|
+
# fully complete the ECore metamodel description.
|
|
98
|
+
#
|
|
99
|
+
# In order to access the ECore metamodel description, just call the +ecore+ method on a
|
|
100
|
+
# Ruby class or module object belonging to your metamodel.
|
|
101
|
+
#
|
|
102
|
+
# Here is the example continued from above:
|
|
103
|
+
#
|
|
104
|
+
# Person.ecore.eAttributes.name # => ["name", "age"]
|
|
105
|
+
# h2pRef = House.ecore.eReferences.first
|
|
106
|
+
# h2pRef.eType # => Person
|
|
107
|
+
# h2pRef.eOpposite.eType # => House
|
|
108
|
+
# h2pRef.lowerBound # => 0
|
|
109
|
+
# h2pRef.upperBound # => -1
|
|
110
|
+
# h2pRef.many # => true
|
|
111
|
+
# h2pRef.containment # => false
|
|
112
|
+
#
|
|
113
|
+
# Note that the use of array_extensions.rb is assumed here to make model navigation convenient.
|
|
114
|
+
#
|
|
115
|
+
# The following metamodel builder methods are supported, see individual method description
|
|
116
|
+
# for details:
|
|
117
|
+
#
|
|
118
|
+
# Attributes:
|
|
119
|
+
# * BuilderExtensions#has_attr
|
|
120
|
+
#
|
|
121
|
+
# Unidirectional references:
|
|
122
|
+
# * BuilderExtensions#has_one
|
|
123
|
+
# * BuilderExtensions#has_many
|
|
124
|
+
# * BuilderExtensions#contains_one_uni
|
|
125
|
+
# * BuilderExtensions#contains_many_uni
|
|
126
|
+
#
|
|
127
|
+
# Bidirectional references:
|
|
128
|
+
# * BuilderExtensions#one_to_one
|
|
129
|
+
# * BuilderExtensions#one_to_many
|
|
130
|
+
# * BuilderExtensions#many_to_one
|
|
131
|
+
# * BuilderExtensions#many_to_many
|
|
132
|
+
# * BuilderExtensions#contains_one
|
|
133
|
+
# * BuilderExtensions#contains_many
|
|
134
|
+
#
|
|
135
|
+
# Every builder command can optionally take a specification of further ECore properties.
|
|
136
|
+
# Additional properties for Attributes and References are (with defaults in brackets):
|
|
137
|
+
# * :ordered (true),
|
|
138
|
+
# * :unique (true),
|
|
139
|
+
# * :changeable (true),
|
|
140
|
+
# * :volatile (false),
|
|
141
|
+
# * :transient (false),
|
|
142
|
+
# * :unsettable (false),
|
|
143
|
+
# * :derived (false),
|
|
144
|
+
# * :lowerBound (0),
|
|
145
|
+
# * :resolveProxies (true) <i>references only</i>,
|
|
146
|
+
#
|
|
147
|
+
# Using these additional properties, the above example can be refined as follows:
|
|
148
|
+
#
|
|
149
|
+
# class Person < RGen::MetamodelBuilder::MMBase
|
|
150
|
+
# has_attr 'name', String, :lowerBound => 1
|
|
151
|
+
# has_attr 'yearOfBirth', Integer,
|
|
152
|
+
# has_attr 'age', Integer, :derived => true
|
|
153
|
+
# def age_derived
|
|
154
|
+
# Time.now.year - yearOfBirth
|
|
155
|
+
# end
|
|
156
|
+
# end
|
|
84
157
|
#
|
|
85
|
-
#
|
|
86
|
-
# that 'has_one' or 'has_many' can be used to define such associations. Again, the
|
|
87
|
-
# type of the attribute/association can be specified as a second argument.
|
|
158
|
+
# Person.many_to_many 'homes', House, 'inhabitants', :upperBound => 5
|
|
88
159
|
#
|
|
160
|
+
# Person.ecore.eReferences.find{|r| r.name == 'homes'}.upperBound # => 5
|
|
161
|
+
#
|
|
162
|
+
# This way we state that there must be a name for each person, we introduce a new attribute
|
|
163
|
+
# 'yearOfBirth' and make 'age' a derived attribute. We also say that a person can
|
|
164
|
+
# have at most 5 houses in our metamodel.
|
|
165
|
+
#
|
|
166
|
+
# ==Derived attributes and references
|
|
167
|
+
#
|
|
168
|
+
# If the attribute 'derived' of an attribute or reference is set to true, a method +attributeName_derived+
|
|
169
|
+
# has to be provided. This method is called whenever the original attribute is accessed. The
|
|
170
|
+
# original attribute can not be written if it is derived.
|
|
171
|
+
#
|
|
172
|
+
#
|
|
89
173
|
module MetamodelBuilder
|
|
90
174
|
|
|
91
175
|
# Use this class as a start for new metamodel elements (i.e. Ruby classes)
|
|
@@ -94,9 +178,19 @@ module MetamodelBuilder
|
|
|
94
178
|
# See MetamodelBuilder for an example.
|
|
95
179
|
class MMBase
|
|
96
180
|
include BuilderRuntime
|
|
181
|
+
include DataTypes
|
|
97
182
|
extend BuilderExtensions
|
|
183
|
+
extend ModuleExtension
|
|
184
|
+
extend RGen::ECore::ECoreInstantiator
|
|
185
|
+
|
|
186
|
+
def initialize(arg=nil)
|
|
187
|
+
arg.each_pair { |k,v| setGeneric(k, v) } if arg.is_a?(Hash)
|
|
188
|
+
end
|
|
189
|
+
def self.method_added(m)
|
|
190
|
+
raise "Do not add methods to model classes directly, add them to the ClassModule instead"
|
|
191
|
+
end
|
|
98
192
|
end
|
|
99
|
-
|
|
193
|
+
|
|
100
194
|
end
|
|
101
195
|
|
|
102
196
|
end
|