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