rgen 0.5.4 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +28 -0
- data/Rakefile +3 -4
- data/lib/ea_support/uml13_ea_metamodel.rb +3 -3
- data/lib/ea_support/uml13_ea_to_uml13.rb +33 -2
- data/lib/ea_support/uml13_to_uml13_ea.rb +7 -0
- data/lib/mmgen/mm_ext/ecore_mmgen_ext.rb +4 -4
- data/lib/mmgen/templates/metamodel_generator.tpl +143 -143
- data/lib/rgen/ecore/ecore.rb +11 -1
- data/lib/rgen/ecore/ecore_interface.rb +47 -0
- data/lib/rgen/ecore/ecore_to_ruby.rb +166 -0
- data/lib/rgen/ecore/{ecore_transformer.rb → ruby_to_ecore.rb} +11 -11
- data/lib/rgen/environment.rb +15 -2
- data/lib/rgen/fragment/dump_file_cache.rb +63 -0
- data/lib/rgen/fragment/fragmented_model.rb +139 -0
- data/lib/rgen/fragment/model_fragment.rb +268 -0
- data/lib/rgen/instantiator/abstract_xml_instantiator.rb +44 -72
- data/lib/rgen/instantiator/default_xml_instantiator.rb +2 -2
- data/lib/rgen/instantiator/ecore_xml_instantiator.rb +16 -1
- data/lib/rgen/instantiator/json_instantiator.rb +16 -2
- data/lib/rgen/instantiator/nodebased_xml_instantiator.rb +118 -138
- data/lib/rgen/instantiator/qualified_name_resolver.rb +5 -1
- data/lib/rgen/instantiator/reference_resolver.rb +126 -24
- data/lib/rgen/instantiator/xmi11_instantiator.rb +6 -2
- data/lib/rgen/metamodel_builder.rb +18 -6
- data/lib/rgen/metamodel_builder/builder_extensions.rb +431 -407
- data/lib/rgen/metamodel_builder/builder_runtime.rb +8 -8
- data/lib/rgen/metamodel_builder/constant_order_helper.rb +4 -4
- data/lib/rgen/metamodel_builder/data_types.rb +5 -1
- data/lib/rgen/metamodel_builder/intermediate/feature.rb +167 -0
- data/lib/rgen/metamodel_builder/module_extension.rb +2 -2
- data/lib/rgen/model_builder.rb +10 -5
- data/lib/rgen/model_builder/builder_context.rb +17 -1
- data/lib/rgen/serializer/opposite_reference_filter.rb +18 -0
- data/lib/rgen/serializer/qualified_name_provider.rb +45 -0
- data/lib/rgen/template_language/template_container.rb +3 -1
- data/lib/rgen/{auto_class_creator.rb → util/auto_class_creator.rb} +6 -1
- data/lib/rgen/util/cached_glob.rb +67 -0
- data/lib/rgen/util/file_cache_map.rb +104 -0
- data/lib/rgen/util/file_change_detector.rb +78 -0
- data/lib/rgen/{method_delegation.rb → util/method_delegation.rb} +18 -3
- data/lib/rgen/{model_comparator.rb → util/model_comparator.rb} +17 -5
- data/lib/rgen/{model_comparator_base.rb → util/model_comparator_base.rb} +6 -1
- data/lib/rgen/{model_dumper.rb → util/model_dumper.rb} +6 -1
- data/lib/rgen/{name_helper.rb → util/name_helper.rb} +6 -1
- data/lib/rgen/util/pattern_matcher.rb +329 -0
- data/lib/transformers/uml13_to_ecore.rb +103 -60
- data/test/ecore_self_test.rb +43 -42
- data/test/json_test.rb +15 -0
- data/test/metamodel_builder_test.rb +361 -206
- data/test/metamodel_from_ecore_test.rb +45 -0
- data/test/metamodel_order_test.rb +10 -4
- data/test/metamodel_roundtrip_test.rb +2 -2
- data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +1 -1
- data/test/metamodel_roundtrip_test/houseMetamodel_Regenerated.ecore +50 -50
- data/test/method_delegation_test.rb +9 -9
- data/test/model_builder/ecore_internal.rb +19 -9
- data/test/model_builder/serializer_test.rb +1 -1
- data/test/reference_resolver_test.rb +79 -12
- data/test/rgen_test.rb +2 -0
- data/test/template_language_test.rb +7 -0
- data/test/template_language_test/templates/callback_indent_test/a.tpl +12 -0
- data/test/template_language_test/templates/callback_indent_test/b.tpl +5 -0
- data/test/testmodel/ea_testmodel_regenerated.xml +588 -583
- data/test/transformer_test.rb +3 -3
- data/test/util/file_cache_map_test.rb +91 -0
- data/test/util/file_cache_map_test/testdir/fileA +1 -0
- data/test/util_test.rb +4 -0
- data/test/xml_instantiator_test.rb +139 -135
- metadata +49 -104
- data/lib/rgen/ecore/ecore_instantiator.rb +0 -31
- data/lib/rgen/metamodel_builder/metamodel_description.rb +0 -232
- data/redist/xmlscan/ChangeLog +0 -1301
- data/redist/xmlscan/README +0 -34
- data/redist/xmlscan/THANKS +0 -11
- data/redist/xmlscan/doc/changes.html +0 -74
- data/redist/xmlscan/doc/changes.rd +0 -80
- data/redist/xmlscan/doc/en/conformance.html +0 -136
- data/redist/xmlscan/doc/en/conformance.rd +0 -152
- data/redist/xmlscan/doc/en/manual.html +0 -356
- data/redist/xmlscan/doc/en/manual.rd +0 -402
- data/redist/xmlscan/doc/ja/conformance.ja.html +0 -118
- data/redist/xmlscan/doc/ja/conformance.ja.rd +0 -134
- data/redist/xmlscan/doc/ja/manual.ja.html +0 -325
- data/redist/xmlscan/doc/ja/manual.ja.rd +0 -370
- data/redist/xmlscan/doc/src/Makefile +0 -41
- data/redist/xmlscan/doc/src/conformance.rd.src +0 -256
- data/redist/xmlscan/doc/src/langsplit.rb +0 -110
- data/redist/xmlscan/doc/src/manual.rd.src +0 -614
- data/redist/xmlscan/install.rb +0 -41
- data/redist/xmlscan/lib/xmlscan/encoding.rb +0 -311
- data/redist/xmlscan/lib/xmlscan/htmlscan.rb +0 -289
- data/redist/xmlscan/lib/xmlscan/namespace.rb +0 -352
- data/redist/xmlscan/lib/xmlscan/parser.rb +0 -299
- data/redist/xmlscan/lib/xmlscan/scanner.rb +0 -1109
- data/redist/xmlscan/lib/xmlscan/version.rb +0 -22
- data/redist/xmlscan/lib/xmlscan/visitor.rb +0 -158
- data/redist/xmlscan/lib/xmlscan/xmlchar.rb +0 -441
- data/redist/xmlscan/memo/CONFORMANCE +0 -1249
- data/redist/xmlscan/memo/PRODUCTIONS +0 -195
- data/redist/xmlscan/memo/contentspec.ry +0 -335
- data/redist/xmlscan/samples/chibixml.rb +0 -105
- data/redist/xmlscan/samples/getxmlchar.rb +0 -122
- data/redist/xmlscan/samples/rexml.rb +0 -159
- data/redist/xmlscan/samples/xmlbench.rb +0 -88
- data/redist/xmlscan/samples/xmlbench/parser/chibixml.rb +0 -22
- data/redist/xmlscan/samples/xmlbench/parser/nqxml.rb +0 -29
- data/redist/xmlscan/samples/xmlbench/parser/rexml.rb +0 -62
- data/redist/xmlscan/samples/xmlbench/parser/xmlparser.rb +0 -22
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan-0.0.10.rb +0 -62
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan-chibixml.rb +0 -22
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan-rexml.rb +0 -22
- data/redist/xmlscan/samples/xmlbench/parser/xmlscan.rb +0 -99
- data/redist/xmlscan/samples/xmlbench/xmlbench-lib.rb +0 -116
- data/redist/xmlscan/samples/xmlconftest.rb +0 -200
- data/redist/xmlscan/test.rb +0 -7
- data/redist/xmlscan/tests/deftestcase.rb +0 -73
- data/redist/xmlscan/tests/runtest.rb +0 -47
- data/redist/xmlscan/tests/testall.rb +0 -14
- data/redist/xmlscan/tests/testencoding.rb +0 -438
- data/redist/xmlscan/tests/testhtmlscan.rb +0 -752
- data/redist/xmlscan/tests/testnamespace.rb +0 -457
- data/redist/xmlscan/tests/testparser.rb +0 -591
- data/redist/xmlscan/tests/testscanner.rb +0 -1749
- data/redist/xmlscan/tests/testxmlchar.rb +0 -143
- data/redist/xmlscan/tests/visitor.rb +0 -34
@@ -36,7 +36,11 @@ class XMI11Instantiator < AbstractXMLInstantiator
|
|
36
36
|
newval = @element_by_id[rd.value]
|
37
37
|
end
|
38
38
|
log WARN, "Could not resolve reference #{rd.attribute} on #{rd.object}" unless newval
|
39
|
-
|
39
|
+
begin
|
40
|
+
rd.object.setGeneric(rd.attribute,newval)
|
41
|
+
rescue Exception
|
42
|
+
log WARN, "Could not set reference #{rd.attribute} on #{rd.object}"
|
43
|
+
end
|
40
44
|
end
|
41
45
|
end
|
42
46
|
|
@@ -161,4 +165,4 @@ class XMI11Instantiator < AbstractXMLInstantiator
|
|
161
165
|
@eAllStructuralFeatures[element.class] ||= element.class.ecore.eAllStructuralFeatures
|
162
166
|
end
|
163
167
|
|
164
|
-
end
|
168
|
+
end
|
@@ -7,7 +7,7 @@ require 'rgen/metamodel_builder/builder_extensions'
|
|
7
7
|
require 'rgen/metamodel_builder/module_extension'
|
8
8
|
require 'rgen/metamodel_builder/data_types'
|
9
9
|
require 'rgen/metamodel_builder/mm_multiple'
|
10
|
-
require 'rgen/ecore/
|
10
|
+
require 'rgen/ecore/ecore_interface'
|
11
11
|
|
12
12
|
module RGen
|
13
13
|
|
@@ -182,25 +182,37 @@ module MetamodelBuilder
|
|
182
182
|
include DataTypes
|
183
183
|
extend BuilderExtensions
|
184
184
|
extend ModuleExtension
|
185
|
-
extend RGen::ECore::
|
185
|
+
extend RGen::ECore::ECoreInterface
|
186
186
|
|
187
187
|
def initialize(arg=nil)
|
188
|
+
raise StandardError.new("Class #{self.class} is abstract") if self.class._abstract_class
|
188
189
|
arg.each_pair { |k,v| setGeneric(k, v) } if arg.is_a?(Hash)
|
189
190
|
end
|
191
|
+
|
192
|
+
# Object#inspect causes problems on most models
|
193
|
+
def inspect
|
194
|
+
self.class.name
|
195
|
+
end
|
190
196
|
|
191
197
|
def self.method_added(m)
|
192
198
|
raise "Do not add methods to model classes directly, add them to the ClassModule instead"
|
193
199
|
end
|
194
200
|
end
|
195
201
|
|
196
|
-
# Instances of
|
197
|
-
|
198
|
-
|
202
|
+
# Instances of MMGeneric can be used as values of any attribute are reference
|
203
|
+
class MMGeneric
|
204
|
+
end
|
205
|
+
|
206
|
+
# MMProxy objects can be used instead of real target elements in case references should be resolved later on
|
207
|
+
class MMProxy < MMGeneric
|
199
208
|
# The +targetIdentifer+ is an object identifying the element the proxy represents
|
200
209
|
attr_accessor :targetIdentifier
|
210
|
+
# +data+ is optional additional information to be associated with the proxy
|
211
|
+
attr_accessor :data
|
201
212
|
|
202
|
-
def initialize(ident=nil)
|
213
|
+
def initialize(ident=nil, data=nil)
|
203
214
|
@targetIdentifier = ident
|
215
|
+
@data = data
|
204
216
|
end
|
205
217
|
end
|
206
218
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# (c) Martin Thiede, 2006
|
3
3
|
|
4
4
|
require 'erb'
|
5
|
-
require 'rgen/metamodel_builder/
|
5
|
+
require 'rgen/metamodel_builder/intermediate/feature'
|
6
6
|
|
7
7
|
module RGen
|
8
8
|
|
@@ -16,240 +16,240 @@ module MetamodelBuilder
|
|
16
16
|
# See MetamodelBuilder for an example.
|
17
17
|
#
|
18
18
|
module BuilderExtensions
|
19
|
-
|
19
|
+
include Util::NameHelper
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
def annotation(hash)
|
31
|
-
@props1.annotations << Intermediate::Annotation.new(hash)
|
32
|
-
end
|
33
|
-
def opposite_annotation(hash)
|
34
|
-
raise "No opposite available" unless @props2
|
35
|
-
@props2.annotations << Intermediate::Annotation.new(hash)
|
36
|
-
end
|
21
|
+
class FeatureBlockEvaluator
|
22
|
+
def self.eval(block, props1, props2=nil)
|
23
|
+
return unless block
|
24
|
+
e = self.new(props1, props2)
|
25
|
+
e.instance_eval(&block)
|
26
|
+
end
|
27
|
+
def initialize(props1, props2)
|
28
|
+
@props1, @props2 = props1, props2
|
37
29
|
end
|
30
|
+
def annotation(hash)
|
31
|
+
@props1.annotations << Intermediate::Annotation.new(hash)
|
32
|
+
end
|
33
|
+
def opposite_annotation(hash)
|
34
|
+
raise "No opposite available" unless @props2
|
35
|
+
@props2.annotations << Intermediate::Annotation.new(hash)
|
36
|
+
end
|
37
|
+
end
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
39
|
+
# Add an attribute which can hold a single value.
|
40
|
+
# 'role' specifies the name which is used to access the attribute.
|
41
|
+
# 'target_class' specifies the type of objects which can be held by this attribute.
|
42
|
+
# If no target class is given, String will be default.
|
43
|
+
#
|
44
|
+
# This class method adds the following instance methods, where 'role' is to be
|
45
|
+
# replaced by the given role name:
|
46
|
+
# class#role # getter
|
47
|
+
# class#role=(value) # setter
|
48
|
+
def has_attr(role, target_class=nil, raw_props={}, &block)
|
49
|
+
props = Intermediate::Attribute.new(target_class, _ownProps(raw_props).merge({
|
50
|
+
:name=>role, :upperBound=>1}))
|
51
|
+
raise "No opposite available" unless _oppositeProps(raw_props).empty?
|
52
|
+
FeatureBlockEvaluator.eval(block, props)
|
53
|
+
_build_internal(props)
|
54
|
+
end
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
56
|
+
# Add an attribute which can hold multiple values.
|
57
|
+
# 'role' specifies the name which is used to access the attribute.
|
58
|
+
# 'target_class' specifies the type of objects which can be held by this attribute.
|
59
|
+
# If no target class is given, String will be default.
|
60
|
+
#
|
61
|
+
# This class method adds the following instance methods, where 'role' is to be
|
62
|
+
# replaced by the given role name:
|
63
|
+
# class#addRole(value, index=-1)
|
64
|
+
# class#removeRole(value)
|
65
|
+
# class#role # getter, returns an array
|
66
|
+
# class#role= # setter, sets multiple values at once
|
67
|
+
# Note that the first letter of the role name is turned into an uppercase
|
68
|
+
# for the add and remove methods.
|
69
|
+
def has_many_attr(role, target_class=nil, raw_props={}, &block)
|
70
|
+
props = Intermediate::Attribute.new(target_class, _setManyUpperBound(_ownProps(raw_props).merge({
|
71
|
+
:name=>role})))
|
72
|
+
raise "No opposite available" unless _oppositeProps(raw_props).empty?
|
73
|
+
FeatureBlockEvaluator.eval(block, props)
|
74
|
+
_build_internal(props)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Add a single unidirectional association.
|
78
|
+
# 'role' specifies the name which is used to access the association.
|
79
|
+
# 'target_class' specifies the type of objects which can be held by this association.
|
80
|
+
#
|
81
|
+
# This class method adds the following instance methods, where 'role' is to be
|
82
|
+
# replaced by the given role name:
|
83
|
+
# class#role # getter
|
84
|
+
# class#role=(value) # setter
|
85
|
+
#
|
86
|
+
def has_one(role, target_class=nil, raw_props={}, &block)
|
87
|
+
props = Intermediate::Reference.new(target_class, _ownProps(raw_props).merge({
|
88
|
+
:name=>role, :upperBound=>1, :containment=>false}))
|
89
|
+
raise "No opposite available" unless _oppositeProps(raw_props).empty?
|
90
|
+
FeatureBlockEvaluator.eval(block, props)
|
91
|
+
_build_internal(props)
|
92
|
+
end
|
93
93
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
94
|
+
# Add an unidirectional _many_ association.
|
95
|
+
# 'role' specifies the name which is used to access the attribute.
|
96
|
+
# 'target_class' is optional and can be used to fix the type of objects which
|
97
|
+
# can be referenced by this association.
|
98
|
+
#
|
99
|
+
# This class method adds the following instance methods, where 'role' is to be
|
100
|
+
# replaced by the given role name:
|
101
|
+
# class#addRole(value, index=-1)
|
102
|
+
# class#removeRole(value)
|
103
|
+
# class#role # getter, returns an array
|
104
|
+
# Note that the first letter of the role name is turned into an uppercase
|
105
|
+
# for the add and remove methods.
|
106
|
+
#
|
107
|
+
def has_many(role, target_class=nil, raw_props={}, &block)
|
108
|
+
props = Intermediate::Reference.new(target_class, _setManyUpperBound(_ownProps(raw_props).merge({
|
109
|
+
:name=>role, :containment=>false})))
|
110
|
+
raise "No opposite available" unless _oppositeProps(raw_props).empty?
|
111
|
+
FeatureBlockEvaluator.eval(block, props)
|
112
|
+
_build_internal(props)
|
113
|
+
end
|
114
|
+
|
115
|
+
def contains_one_uni(role, target_class=nil, raw_props={}, &block)
|
116
|
+
props = Intermediate::Reference.new(target_class, _ownProps(raw_props).merge({
|
117
|
+
:name=>role, :upperBound=>1, :containment=>true}))
|
118
|
+
raise "No opposite available" unless _oppositeProps(raw_props).empty?
|
119
|
+
FeatureBlockEvaluator.eval(block, props)
|
120
|
+
_build_internal(props)
|
121
|
+
end
|
122
122
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
123
|
+
def contains_many_uni(role, target_class=nil, raw_props={}, &block)
|
124
|
+
props = Intermediate::Reference.new(target_class, _setManyUpperBound(_ownProps(raw_props).merge({
|
125
|
+
:name=>role, :containment=>true})))
|
126
|
+
raise "No opposite available" unless _oppositeProps(raw_props).empty?
|
127
|
+
FeatureBlockEvaluator.eval(block, props)
|
128
|
+
_build_internal(props)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Add a bidirectional one-to-many association between two classes.
|
132
|
+
# The class this method is called on is refered to as _own_class_ in
|
133
|
+
# the following.
|
134
|
+
#
|
135
|
+
# Instances of own_class can use 'own_role' to access _many_ associated instances
|
136
|
+
# of type 'target_class'. Instances of 'target_class' can use 'target_role' to
|
137
|
+
# access _one_ associated instance of own_class.
|
138
|
+
#
|
139
|
+
# This class method adds the following instance methods where 'ownRole' and
|
140
|
+
# 'targetRole' are to be replaced by the given role names:
|
141
|
+
# own_class#addOwnRole(value, index=-1)
|
142
|
+
# own_class#removeOwnRole(value)
|
143
|
+
# own_class#ownRole
|
144
|
+
# target_class#targetRole
|
145
|
+
# target_class#targetRole=(value)
|
146
|
+
# Note that the first letter of the role name is turned into an uppercase
|
147
|
+
# for the add and remove methods.
|
148
|
+
#
|
149
|
+
# When an element is added/set on either side, this element also receives the element
|
150
|
+
# is is added to as a new element.
|
151
|
+
#
|
152
|
+
def one_to_many(target_role, target_class, own_role, raw_props={}, &block)
|
153
|
+
props1 = Intermediate::Reference.new(target_class, _setManyUpperBound(_ownProps(raw_props).merge({
|
154
|
+
:name=>target_role, :containment=>false})))
|
155
|
+
props2 = Intermediate::Reference.new(self, _oppositeProps(raw_props).merge({
|
156
|
+
:name=>own_role, :upperBound=>1, :containment=>false}))
|
157
|
+
FeatureBlockEvaluator.eval(block, props1, props2)
|
158
|
+
_build_internal(props1, props2)
|
159
|
+
end
|
160
160
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
161
|
+
def contains_many(target_role, target_class, own_role, raw_props={}, &block)
|
162
|
+
props1 = Intermediate::Reference.new(target_class, _setManyUpperBound(_ownProps(raw_props).merge({
|
163
|
+
:name=>target_role, :containment=>true})))
|
164
|
+
props2 = Intermediate::Reference.new(self, _oppositeProps(raw_props).merge({
|
165
|
+
:name=>own_role, :upperBound=>1, :containment=>false}))
|
166
|
+
FeatureBlockEvaluator.eval(block, props1, props2)
|
167
|
+
_build_internal(props1, props2)
|
168
|
+
end
|
169
|
+
|
170
|
+
# This is the inverse of one_to_many provided for convenience.
|
171
|
+
def many_to_one(target_role, target_class, own_role, raw_props={}, &block)
|
172
|
+
props1 = Intermediate::Reference.new(target_class, _ownProps(raw_props).merge({
|
173
|
+
:name=>target_role, :upperBound=>1, :containment=>false}))
|
174
|
+
props2 = Intermediate::Reference.new(self, _setManyUpperBound(_oppositeProps(raw_props).merge({
|
175
|
+
:name=>own_role, :containment=>false})))
|
176
|
+
FeatureBlockEvaluator.eval(block, props1, props2)
|
177
|
+
_build_internal(props1, props2)
|
178
|
+
end
|
179
|
+
|
180
|
+
# Add a bidirectional many-to-many association between two classes.
|
181
|
+
# The class this method is called on is refered to as _own_class_ in
|
182
|
+
# the following.
|
183
|
+
#
|
184
|
+
# Instances of own_class can use 'own_role' to access _many_ associated instances
|
185
|
+
# of type 'target_class'. Instances of 'target_class' can use 'target_role' to
|
186
|
+
# access _many_ associated instances of own_class.
|
187
|
+
#
|
188
|
+
# This class method adds the following instance methods where 'ownRole' and
|
189
|
+
# 'targetRole' are to be replaced by the given role names:
|
190
|
+
# own_class#addOwnRole(value, index=-1)
|
191
|
+
# own_class#removeOwnRole(value)
|
192
|
+
# own_class#ownRole
|
193
|
+
# target_class#addTargetRole
|
194
|
+
# target_class#removeTargetRole=(value)
|
195
|
+
# target_class#targetRole
|
196
|
+
# Note that the first letter of the role name is turned into an uppercase
|
197
|
+
# for the add and remove methods.
|
198
|
+
#
|
199
|
+
# When an element is added on either side, this element also receives the element
|
200
|
+
# is is added to as a new element.
|
201
|
+
#
|
202
|
+
def many_to_many(target_role, target_class, own_role, raw_props={}, &block)
|
203
|
+
props1 = Intermediate::Reference.new(target_class, _setManyUpperBound(_ownProps(raw_props).merge({
|
204
|
+
:name=>target_role, :containment=>false})))
|
205
|
+
props2 = Intermediate::Reference.new(self, _setManyUpperBound(_oppositeProps(raw_props).merge({
|
206
|
+
:name=>own_role, :containment=>false})))
|
207
|
+
FeatureBlockEvaluator.eval(block, props1, props2)
|
208
|
+
_build_internal(props1, props2)
|
209
|
+
end
|
210
|
+
|
211
|
+
# Add a bidirectional one-to-one association between two classes.
|
212
|
+
# The class this method is called on is refered to as _own_class_ in
|
213
|
+
# the following.
|
214
|
+
#
|
215
|
+
# Instances of own_class can use 'own_role' to access _one_ associated instance
|
216
|
+
# of type 'target_class'. Instances of 'target_class' can use 'target_role' to
|
217
|
+
# access _one_ associated instance of own_class.
|
218
|
+
#
|
219
|
+
# This class method adds the following instance methods where 'ownRole' and
|
220
|
+
# 'targetRole' are to be replaced by the given role names:
|
221
|
+
# own_class#ownRole
|
222
|
+
# own_class#ownRole=(value)
|
223
|
+
# target_class#targetRole
|
224
|
+
# target_class#targetRole=(value)
|
225
|
+
#
|
226
|
+
# When an element is set on either side, this element also receives the element
|
227
|
+
# is is added to as the new element.
|
228
|
+
#
|
229
|
+
def one_to_one(target_role, target_class, own_role, raw_props={}, &block)
|
230
|
+
props1 = Intermediate::Reference.new(target_class, _ownProps(raw_props).merge({
|
231
|
+
:name=>target_role, :upperBound=>1, :containment=>false}))
|
232
|
+
props2 = Intermediate::Reference.new(self, _oppositeProps(raw_props).merge({
|
233
|
+
:name=>own_role, :upperBound=>1, :containment=>false}))
|
234
|
+
FeatureBlockEvaluator.eval(block, props1, props2)
|
235
|
+
_build_internal(props1, props2)
|
236
|
+
end
|
237
|
+
|
238
|
+
def contains_one(target_role, target_class, own_role, raw_props={}, &block)
|
239
|
+
props1 = Intermediate::Reference.new(target_class, _ownProps(raw_props).merge({
|
240
|
+
:name=>target_role, :upperBound=>1, :containment=>true}))
|
241
|
+
props2 = Intermediate::Reference.new(self, _oppositeProps(raw_props).merge({
|
242
|
+
:name=>own_role, :upperBound=>1, :containment=>false}))
|
243
|
+
FeatureBlockEvaluator.eval(block, props1, props2)
|
244
|
+
_build_internal(props1, props2)
|
245
|
+
end
|
246
|
+
|
247
|
+
def _metamodel_description # :nodoc:
|
248
|
+
@metamodel_description ||= []
|
249
249
|
end
|
250
250
|
|
251
251
|
def _add_metamodel_description(desc) # :nodoc
|
252
|
-
|
252
|
+
@metamodel_description ||= []
|
253
253
|
@metamodelDescriptionByName ||= {}
|
254
254
|
@metamodel_description.delete(@metamodelDescriptionByName[desc.value(:name)])
|
255
255
|
@metamodel_description << desc
|
@@ -263,146 +263,147 @@ module BuilderExtensions
|
|
263
263
|
def _abstract_class
|
264
264
|
@abstract || false
|
265
265
|
end
|
266
|
-
|
267
|
-
|
268
|
-
|
266
|
+
|
267
|
+
def inherited(c)
|
268
|
+
c.send(:include, c.const_set(:ClassModule, Module.new))
|
269
269
|
MetamodelBuilder::ConstantOrderHelper.classCreated(c)
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
270
|
+
end
|
271
|
+
|
272
|
+
protected
|
273
|
+
|
274
|
+
# Central builder method
|
275
|
+
#
|
276
|
+
def _build_internal(props1, props2=nil)
|
277
|
+
_add_metamodel_description(props1)
|
278
|
+
if props1.many?
|
279
|
+
_build_many_methods(props1, props2)
|
280
|
+
else
|
281
|
+
_build_one_methods(props1, props2)
|
282
|
+
end
|
283
|
+
if props2
|
284
|
+
# this is a bidirectional reference
|
285
|
+
props1.opposite, props2.opposite = props2, props1
|
286
|
+
other_class = props1.impl_type
|
287
|
+
other_class._add_metamodel_description(props2)
|
288
|
+
raise "Internal error: second description must be a reference description" \
|
289
|
+
unless props2.reference?
|
290
|
+
if props2.many?
|
291
|
+
other_class._build_many_methods(props2, props1)
|
292
|
+
else
|
293
|
+
other_class._build_one_methods(props2, props1)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
# To-One association methods
|
299
|
+
#
|
300
|
+
def _build_one_methods(props, other_props=nil)
|
301
|
+
name = props.value(:name)
|
302
|
+
other_role = other_props && other_props.value(:name)
|
303
303
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
304
|
+
if props.value(:derived)
|
305
|
+
build_derived_method(name, props, :one)
|
306
|
+
else
|
307
|
+
@@one_read_builder ||= ERB.new <<-CODE
|
308
|
+
|
309
|
+
def <%= name %>
|
310
|
+
<% if !props.reference? && props.value(:defaultValueLiteral) %>
|
311
|
+
<% defVal = props.value(:defaultValueLiteral) %>
|
312
|
+
<% check_default_value_literal(defVal, props) %>
|
313
|
+
<% defVal = '"'+defVal+'"' if props.impl_type == String %>
|
314
|
+
<% defVal = ':'+defVal if props.impl_type.is_a?(DataTypes::Enum) && props.impl_type != DataTypes::Boolean %>
|
315
|
+
@<%= name %>.nil? ? <%= defVal %> : @<%= name %>
|
316
|
+
<% else %>
|
317
|
+
@<%= name %>
|
318
|
+
<% end %>
|
319
|
+
end
|
320
|
+
alias get<%= firstToUpper(name) %> <%= name %>
|
320
321
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
322
|
+
CODE
|
323
|
+
self::ClassModule.module_eval(@@one_read_builder.result(binding))
|
324
|
+
end
|
325
|
+
|
326
|
+
if props.value(:changeable)
|
327
|
+
@@one_write_builder ||= ERB.new <<-CODE
|
328
|
+
|
329
|
+
def <%= name %>=(val)
|
330
|
+
return if val == @<%= name %>
|
331
|
+
<%= type_check_code("val", props) %>
|
332
|
+
oldval = @<%= name %>
|
333
|
+
@<%= name %> = val
|
334
|
+
<% if other_role %>
|
335
|
+
oldval._unregister<%= firstToUpper(other_role) %>(self) unless oldval.nil? || oldval.is_a?(MMGeneric)
|
336
|
+
val._register<%= firstToUpper(other_role) %>(self) unless val.nil? || val.is_a?(MMGeneric)
|
337
|
+
<% end %>
|
338
|
+
end
|
339
|
+
alias set<%= firstToUpper(name) %> <%= name %>=
|
339
340
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
341
|
+
def _register<%= firstToUpper(name) %>(val)
|
342
|
+
<% if other_role %>
|
343
|
+
@<%= name %>._unregister<%= firstToUpper(other_role) %>(self) unless @<%= name %>.nil? || @<%= name %>.is_a?(MMGeneric)
|
344
|
+
<% end %>
|
345
|
+
@<%= name %> = val
|
346
|
+
end
|
346
347
|
|
347
|
-
|
348
|
-
|
349
|
-
|
348
|
+
def _unregister<%= firstToUpper(name) %>(val)
|
349
|
+
@<%= name %> = nil
|
350
|
+
end
|
350
351
|
|
351
|
-
|
352
|
-
|
352
|
+
CODE
|
353
|
+
self::ClassModule.module_eval(@@one_write_builder.result(binding))
|
353
354
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
# To-Many association methods
|
359
|
+
#
|
360
|
+
def _build_many_methods(props, other_props=nil)
|
361
|
+
name = props.value(:name)
|
362
|
+
other_role = other_props && other_props.value(:name)
|
362
363
|
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
364
|
+
if props.value(:derived)
|
365
|
+
build_derived_method(name, props, :many)
|
366
|
+
else
|
367
|
+
@@many_read_builder ||= ERB.new <<-CODE
|
368
|
+
|
369
|
+
def <%= name %>
|
370
|
+
( @<%= name %> ? @<%= name %>.dup : [] )
|
371
|
+
end
|
372
|
+
alias get<%= firstToUpper(name) %> <%= name %>
|
373
|
+
|
374
|
+
CODE
|
375
|
+
self::ClassModule.module_eval(@@many_read_builder.result(binding))
|
376
|
+
end
|
377
|
+
|
378
|
+
if props.value(:changeable)
|
379
|
+
@@many_write_builder ||= ERB.new <<-CODE
|
380
|
+
|
381
|
+
def add<%= firstToUpper(name) %>(val, index=-1)
|
382
|
+
@<%= name %> = [] unless @<%= name %>
|
383
|
+
return if val.nil? || (@<%= name %>.any?{|e| e.object_id == val.object_id} && (val.is_a?(MMBase) || val.is_a?(MMGeneric)))
|
384
|
+
<%= type_check_code("val", props) %>
|
385
|
+
@<%= name %>.insert(index, val)
|
386
|
+
<% if other_role %>
|
387
|
+
val._register<%= firstToUpper(other_role) %>(self) unless val.is_a?(MMGeneric)
|
388
|
+
<% end %>
|
389
|
+
end
|
390
|
+
|
391
|
+
def remove<%= firstToUpper(name) %>(val)
|
392
|
+
@<%= name %> = [] unless @<%= name %>
|
393
|
+
@<%= name %>.each_with_index do |e,i|
|
394
|
+
if e.object_id == val.object_id
|
395
|
+
@<%= name %>.delete_at(i)
|
396
|
+
<% if other_role %>
|
397
|
+
val._unregister<%= firstToUpper(other_role) %>(self) unless val.is_a?(MMGeneric)
|
398
|
+
<% end %>
|
399
|
+
return
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|
402
403
|
|
403
404
|
def <%= name %>=(val)
|
404
405
|
return if val.nil?
|
405
|
-
raise _assignmentTypeError(self, val,
|
406
|
+
raise _assignmentTypeError(self, val, Enumerable) unless val.is_a? Enumerable
|
406
407
|
get<%= firstToUpper(name) %>.each {|e|
|
407
408
|
remove<%= firstToUpper(name) %>(e)
|
408
409
|
}
|
@@ -410,7 +411,7 @@ module BuilderExtensions
|
|
410
411
|
add<%= firstToUpper(name) %>(v)
|
411
412
|
}
|
412
413
|
end
|
413
|
-
|
414
|
+
alias set<%= firstToUpper(name) %> <%= name %>=
|
414
415
|
|
415
416
|
def _register<%= firstToUpper(name) %>(val)
|
416
417
|
@<%= name %> = [] unless @<%= name %>
|
@@ -421,63 +422,86 @@ module BuilderExtensions
|
|
421
422
|
@<%= name %>.delete val
|
422
423
|
end
|
423
424
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
425
|
+
CODE
|
426
|
+
self::ClassModule.module_eval(@@many_write_builder.result(binding))
|
427
|
+
end
|
428
|
+
|
429
|
+
end
|
429
430
|
|
430
|
-
|
431
|
+
private
|
432
|
+
|
433
|
+
def build_derived_method(name, props, kind)
|
434
|
+
raise "Implement method #{name}_derived instead of method #{name}" \
|
435
|
+
if (public_instance_methods+protected_instance_methods+private_instance_methods).include?(name)
|
436
|
+
@@derived_builder ||= ERB.new <<-CODE
|
437
|
+
|
438
|
+
def <%= name %>
|
439
|
+
raise "Derived feature requires public implementation of method <%= name %>_derived" \
|
440
|
+
unless respond_to?(:<%= name+"_derived" %>)
|
441
|
+
val = <%= name %>_derived
|
442
|
+
<% if kind == :many %>
|
443
|
+
raise _assignmentTypeError(self,val,Enumerable) unless val && val.is_a?(Enumerable)
|
444
|
+
val.each do |v|
|
445
|
+
<%= type_check_code("v", props) %>
|
446
|
+
end
|
447
|
+
<% else %>
|
448
|
+
<%= type_check_code("val", props) %>
|
449
|
+
<% end %>
|
450
|
+
val
|
451
|
+
end
|
452
|
+
alias get<%= firstToUpper(name) %> <%= name %>
|
453
|
+
#TODO final_method :<%= name %>
|
454
|
+
|
455
|
+
CODE
|
456
|
+
self::ClassModule.module_eval(@@derived_builder.result(binding))
|
457
|
+
end
|
431
458
|
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
def _ownProps(props)
|
475
|
-
Hash[*(props.select{|k,v| !(k.to_s =~ /^opposite_/)}.flatten)]
|
459
|
+
def check_default_value_literal(literal, props)
|
460
|
+
return if literal.nil? || props.impl_type == String
|
461
|
+
if props.impl_type == Integer
|
462
|
+
unless literal =~ /^\d+$/
|
463
|
+
raise StandardError.new("Property #{props.value(:name)} can not take value #{literal}, expected an Integer")
|
464
|
+
end
|
465
|
+
elsif props.impl_type == Float
|
466
|
+
unless literal =~ /^\d+\.\d+$/
|
467
|
+
raise StandardError.new("Property #{props.value(:name)} can not take value #{literal}, expected a Float")
|
468
|
+
end
|
469
|
+
elsif props.impl_type == RGen::MetamodelBuilder::DataTypes::Boolean
|
470
|
+
unless ["true", "false"].include?(literal)
|
471
|
+
raise StandardError.new("Property #{props.value(:name)} can not take value #{literal}, expected true or false")
|
472
|
+
end
|
473
|
+
elsif props.impl_type.is_a?(RGen::MetamodelBuilder::DataTypes::Enum)
|
474
|
+
unless props.impl_type.literals.include?(literal.to_sym)
|
475
|
+
raise StandardError.new("Property #{props.value(:name)} can not take value #{literal}, expected one of #{props.impl_type.literals_as_strings.join(', ')}")
|
476
|
+
end
|
477
|
+
else
|
478
|
+
raise StandardError.new("Unkown type "+props.impl_type.to_s)
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
def type_check_code(varname, props)
|
483
|
+
code = ""
|
484
|
+
if props.impl_type.is_a?(Class)
|
485
|
+
code << "unless #{varname}.nil? || #{varname}.is_a?(#{props.impl_type}) || #{varname}.is_a?(MMGeneric)\n"
|
486
|
+
expected = props.impl_type.to_s
|
487
|
+
elsif props.impl_type.is_a?(RGen::MetamodelBuilder::DataTypes::Enum)
|
488
|
+
code << "unless #{varname}.nil? || [#{props.impl_type.literals_as_strings.join(',')}].include?(#{varname}) || #{varname}.is_a?(MMGeneric)\n"
|
489
|
+
expected = "["+props.impl_type.literals_as_strings.join(',')+"]"
|
490
|
+
else
|
491
|
+
raise StandardError.new("Unkown type "+props.impl_type.to_s)
|
492
|
+
end
|
493
|
+
code << "raise _assignmentTypeError(self,#{varname},\"#{expected}\")\n"
|
494
|
+
code << "end"
|
495
|
+
code
|
496
|
+
end
|
497
|
+
|
498
|
+
def _ownProps(props)
|
499
|
+
Hash[*(props.select{|k,v| !(k.to_s =~ /^opposite_/)}.flatten)]
|
476
500
|
end
|
477
501
|
|
478
|
-
|
502
|
+
def _oppositeProps(props)
|
479
503
|
r = {}
|
480
|
-
|
504
|
+
props.each_pair do |k,v|
|
481
505
|
if k.to_s =~ /^opposite_(.*)$/
|
482
506
|
r[$1.to_sym] = v
|
483
507
|
end
|