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.
Files changed (145) hide show
  1. data/CHANGELOG +20 -1
  2. data/MIT-LICENSE +1 -1
  3. data/README +12 -9
  4. data/lib/instantiators/ea_instantiator.rb +36 -0
  5. data/lib/metamodels/uml13_metamodel.rb +559 -0
  6. data/lib/metamodels/uml13_metamodel_ext.rb +26 -0
  7. data/lib/mmgen/metamodel_generator.rb +5 -5
  8. data/lib/mmgen/mm_ext/ecore_ext.rb +95 -0
  9. data/lib/mmgen/mmgen.rb +6 -4
  10. data/lib/mmgen/templates/annotations.tpl +37 -0
  11. data/lib/mmgen/templates/metamodel_generator.tpl +171 -0
  12. data/lib/rgen/ecore/ecore.rb +190 -0
  13. data/lib/rgen/ecore/ecore_instantiator.rb +25 -0
  14. data/lib/rgen/ecore/ecore_transformer.rb +85 -0
  15. data/lib/rgen/environment.rb +9 -24
  16. data/lib/rgen/find_helper.rb +68 -0
  17. data/lib/rgen/{instantiator.rb → instantiator/abstract_instantiator.rb} +6 -2
  18. data/lib/rgen/instantiator/abstract_xml_instantiator.rb +59 -0
  19. data/lib/rgen/instantiator/default_xml_instantiator.rb +117 -0
  20. data/lib/rgen/instantiator/ecore_xml_instantiator.rb +144 -0
  21. data/lib/rgen/instantiator/nodebased_xml_instantiator.rb +157 -0
  22. data/lib/rgen/instantiator/xmi11_instantiator.rb +164 -0
  23. data/lib/rgen/metamodel_builder.rb +103 -9
  24. data/lib/rgen/metamodel_builder/build_helper.rb +26 -4
  25. data/lib/rgen/metamodel_builder/builder_extensions.rb +285 -88
  26. data/lib/rgen/metamodel_builder/builder_runtime.rb +7 -1
  27. data/lib/rgen/metamodel_builder/data_types.rb +67 -0
  28. data/lib/rgen/metamodel_builder/intermediate/annotation.rb +30 -0
  29. data/lib/rgen/metamodel_builder/metamodel_description.rb +232 -0
  30. data/lib/rgen/metamodel_builder/mm_multiple.rb +23 -0
  31. data/lib/rgen/metamodel_builder/module_extension.rb +33 -0
  32. data/lib/rgen/model_comparator.rb +56 -0
  33. data/lib/rgen/model_dumper.rb +5 -5
  34. data/lib/rgen/name_helper.rb +17 -1
  35. data/lib/rgen/template_language.rb +148 -28
  36. data/lib/rgen/template_language/directory_template_container.rb +56 -38
  37. data/lib/rgen/template_language/output_handler.rb +93 -77
  38. data/lib/rgen/template_language/template_container.rb +186 -143
  39. data/lib/rgen/transformer.rb +19 -14
  40. data/lib/transformers/uml13_to_ecore.rb +75 -0
  41. data/redist/xmlscan/ChangeLog +1301 -0
  42. data/redist/xmlscan/README +34 -0
  43. data/redist/xmlscan/THANKS +11 -0
  44. data/redist/xmlscan/doc/changes.html +74 -0
  45. data/redist/xmlscan/doc/changes.rd +80 -0
  46. data/redist/xmlscan/doc/en/conformance.html +136 -0
  47. data/redist/xmlscan/doc/en/conformance.rd +152 -0
  48. data/redist/xmlscan/doc/en/manual.html +356 -0
  49. data/redist/xmlscan/doc/en/manual.rd +402 -0
  50. data/redist/xmlscan/doc/ja/conformance.ja.html +118 -0
  51. data/redist/xmlscan/doc/ja/conformance.ja.rd +134 -0
  52. data/redist/xmlscan/doc/ja/manual.ja.html +325 -0
  53. data/redist/xmlscan/doc/ja/manual.ja.rd +370 -0
  54. data/redist/xmlscan/doc/src/Makefile +41 -0
  55. data/redist/xmlscan/doc/src/conformance.rd.src +256 -0
  56. data/redist/xmlscan/doc/src/langsplit.rb +110 -0
  57. data/redist/xmlscan/doc/src/manual.rd.src +614 -0
  58. data/redist/xmlscan/install.rb +41 -0
  59. data/redist/xmlscan/lib/xmlscan/encoding.rb +311 -0
  60. data/redist/xmlscan/lib/xmlscan/htmlscan.rb +289 -0
  61. data/redist/xmlscan/lib/xmlscan/namespace.rb +352 -0
  62. data/redist/xmlscan/lib/xmlscan/parser.rb +299 -0
  63. data/redist/xmlscan/lib/xmlscan/scanner.rb +1109 -0
  64. data/redist/xmlscan/lib/xmlscan/version.rb +22 -0
  65. data/redist/xmlscan/lib/xmlscan/visitor.rb +158 -0
  66. data/redist/xmlscan/lib/xmlscan/xmlchar.rb +441 -0
  67. data/redist/xmlscan/memo/CONFORMANCE +1249 -0
  68. data/redist/xmlscan/memo/PRODUCTIONS +195 -0
  69. data/redist/xmlscan/memo/contentspec.ry +335 -0
  70. data/redist/xmlscan/samples/chibixml.rb +105 -0
  71. data/redist/xmlscan/samples/getxmlchar.rb +122 -0
  72. data/redist/xmlscan/samples/rexml.rb +159 -0
  73. data/redist/xmlscan/samples/xmlbench.rb +88 -0
  74. data/redist/xmlscan/samples/xmlbench/parser/chibixml.rb +22 -0
  75. data/redist/xmlscan/samples/xmlbench/parser/nqxml.rb +29 -0
  76. data/redist/xmlscan/samples/xmlbench/parser/rexml.rb +62 -0
  77. data/redist/xmlscan/samples/xmlbench/parser/xmlparser.rb +22 -0
  78. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-0.0.10.rb +62 -0
  79. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-chibixml.rb +22 -0
  80. data/redist/xmlscan/samples/xmlbench/parser/xmlscan-rexml.rb +22 -0
  81. data/redist/xmlscan/samples/xmlbench/parser/xmlscan.rb +99 -0
  82. data/redist/xmlscan/samples/xmlbench/xmlbench-lib.rb +116 -0
  83. data/redist/xmlscan/samples/xmlconftest.rb +200 -0
  84. data/redist/xmlscan/test.rb +7 -0
  85. data/redist/xmlscan/tests/deftestcase.rb +73 -0
  86. data/redist/xmlscan/tests/runtest.rb +47 -0
  87. data/redist/xmlscan/tests/testall.rb +14 -0
  88. data/redist/xmlscan/tests/testencoding.rb +438 -0
  89. data/redist/xmlscan/tests/testhtmlscan.rb +752 -0
  90. data/redist/xmlscan/tests/testnamespace.rb +457 -0
  91. data/redist/xmlscan/tests/testparser.rb +591 -0
  92. data/redist/xmlscan/tests/testscanner.rb +1749 -0
  93. data/redist/xmlscan/tests/testxmlchar.rb +143 -0
  94. data/redist/xmlscan/tests/visitor.rb +34 -0
  95. data/test/array_extensions_test.rb +2 -2
  96. data/test/ea_instantiator_test.rb +41 -0
  97. data/test/ecore_self_test.rb +53 -0
  98. data/test/environment_test.rb +11 -6
  99. data/test/metamodel_builder_test.rb +404 -245
  100. data/test/metamodel_roundtrip_test.rb +52 -0
  101. data/test/metamodel_roundtrip_test/TestModel.rb +65 -0
  102. data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +64 -0
  103. data/test/metamodel_roundtrip_test/houseMetamodel.ecore +32 -0
  104. data/test/metamodel_roundtrip_test/houseMetamodel_from_ecore.rb +39 -0
  105. data/test/rgen_test.rb +3 -3
  106. data/test/template_language_test.rb +65 -39
  107. data/test/template_language_test/expected_result.txt +24 -3
  108. data/test/template_language_test/templates/code/array.tpl +11 -0
  109. data/test/template_language_test/templates/content/author.tpl +7 -0
  110. data/test/template_language_test/templates/content/chapter.tpl +1 -1
  111. data/test/template_language_test/templates/root.tpl +17 -8
  112. data/test/template_language_test/testout.txt +24 -3
  113. data/test/testmodel/class_model_checker.rb +119 -0
  114. data/test/{xmi_instantiator_test/testmodel.eap → testmodel/ea_testmodel.eap} +0 -0
  115. data/test/{xmi_instantiator_test/testmodel.xml → testmodel/ea_testmodel.xml} +81 -14
  116. data/test/testmodel/ea_testmodel_partial.xml +317 -0
  117. data/test/testmodel/ecore_model_checker.rb +101 -0
  118. data/test/testmodel/manual_testmodel.xml +22 -0
  119. data/test/testmodel/object_model_checker.rb +67 -0
  120. data/test/transformer_test.rb +18 -10
  121. data/test/xml_instantiator_test.rb +81 -8
  122. data/test/xml_instantiator_test/simple_ecore_model_checker.rb +94 -0
  123. data/test/xml_instantiator_test/simple_xmi_ecore_instantiator.rb +53 -0
  124. data/test/xml_instantiator_test/simple_xmi_metamodel.rb +49 -0
  125. data/test/xml_instantiator_test/simple_xmi_to_ecore.rb +75 -0
  126. metadata +126 -28
  127. data/lib/ea/xmi_class_instantiator.rb +0 -46
  128. data/lib/ea/xmi_helper.rb +0 -26
  129. data/lib/ea/xmi_metamodel.rb +0 -34
  130. data/lib/ea/xmi_object_instantiator.rb +0 -46
  131. data/lib/ea/xmi_to_classmodel.rb +0 -78
  132. data/lib/ea/xmi_to_objectmodel.rb +0 -92
  133. data/lib/mmgen/mm_ext/uml_classmodel_ext.rb +0 -71
  134. data/lib/mmgen/templates/uml_classmodel.tpl +0 -63
  135. data/lib/rgen/xml_instantiator.rb +0 -132
  136. data/lib/uml/objectmodel_instantiator.rb +0 -53
  137. data/lib/uml/uml_classmodel.rb +0 -92
  138. data/lib/uml/uml_objectmodel.rb +0 -65
  139. data/test/metamodel_generator_test.rb +0 -44
  140. data/test/metamodel_generator_test/TestModel.rb +0 -40
  141. data/test/metamodel_generator_test/expected_result.txt +0 -40
  142. data/test/xmi_class_instantiator_test.rb +0 -24
  143. data/test/xmi_instantiator_test/class_model_checker.rb +0 -97
  144. data/test/xmi_object_instantiator_test.rb +0 -65
  145. data/test/xml_instantiator_test/testmodel.xml +0 -7
@@ -11,16 +11,38 @@ class BuildHelper
11
11
  include NameHelper
12
12
 
13
13
  def self.build(mod,bnd,tpl)
14
- mod.module_eval ERB.new(tpl).result(BuildHelper.new(bnd).bnd)
14
+ mod.module_eval ERB.new(tpl).result(BuildHelper.new(mod, bnd).bnd)
15
15
  end
16
- def initialize(bnd)
16
+ def initialize(mod, bnd)
17
17
  @outer_binding = bnd
18
+ @mod = mod
18
19
  end
19
20
  def bnd
20
21
  binding
21
22
  end
22
- def method_missing(m)
23
- eval("#{m}",@outer_binding)
23
+ def method_missing(m, *args)
24
+ if args.empty?
25
+ eval("#{m}",@outer_binding)
26
+ else
27
+ @mod.instance_eval do
28
+ send(m,*args)
29
+ end
30
+ end
31
+ end
32
+ def type_check_code(varname, props)
33
+ code = ""
34
+ if props.impl_type.is_a?(Class)
35
+ code << "unless #{varname}.nil? or #{varname}.is_a? #{props.impl_type}\n"
36
+ expected = props.impl_type.to_s
37
+ elsif props.impl_type.is_a?(RGen::MetamodelBuilder::DataTypes::Enum)
38
+ code << "unless #{varname}.nil? or [#{props.impl_type.literals_as_strings.join(',')}].include?(#{varname})\n"
39
+ expected = "["+props.impl_type.literals_as_strings.join(',')+"]"
40
+ else
41
+ raise StandardError.new("Unkown type "+props.impl_type.to_s)
42
+ end
43
+ code << "raise _assignmentTypeError(self,#{varname},\"#{expected}\")\n"
44
+ code << "end"
45
+ code
24
46
  end
25
47
  end
26
48
 
@@ -3,6 +3,7 @@
3
3
 
4
4
  require 'erb'
5
5
  require 'rgen/metamodel_builder/build_helper'
6
+ require 'rgen/metamodel_builder/metamodel_description.rb'
6
7
 
7
8
  module RGen
8
9
 
@@ -16,19 +17,50 @@ module MetamodelBuilder
16
17
  # See MetamodelBuilder for an example.
17
18
  #
18
19
  module BuilderExtensions
20
+ include NameHelper
19
21
 
22
+ class FeatureBlockEvaluator
23
+ def self.eval(block, props1, props2=nil)
24
+ return unless block
25
+ e = self.new(props1, props2)
26
+ e.instance_eval(&block)
27
+ end
28
+ def initialize(props1, props2)
29
+ @props1, @props2 = props1, props2
30
+ end
31
+ def annotation(hash)
32
+ @props1.annotations << Intermediate::Annotation.new(hash)
33
+ end
34
+ def opposite_annotation(hash)
35
+ raise "No opposite available" unless @props2
36
+ @props2.annotations << Intermediate::Annotation.new(hash)
37
+ end
38
+ end
39
+
40
+ def has_attr(role, target_class=nil, raw_props={}, &block)
41
+ props = AttributeDescription.new(target_class, _ownProps(raw_props).merge({
42
+ :name=>role, :upperBound=>1}))
43
+ raise "No opposite available" unless _oppositeProps(raw_props).empty?
44
+ FeatureBlockEvaluator.eval(block, props)
45
+ _build_internal(props)
46
+ end
47
+
20
48
  # Add a single attribute or unidirectional association.
21
49
  # 'role' specifies the name which is used to access the attribute.
22
- # 'target_class' is optional and can be used to fix the type of objects which
23
- # can be held by this attribute.
50
+ # 'target_class' specifies the type of objects which can be held by this attribute.
51
+ # If no target class is given, String will be default.
24
52
  #
25
53
  # This class method adds the following instance methods, where 'role' is to be
26
54
  # replaced by the given role name:
27
55
  # class#role # getter
28
56
  # class#role=(value) # setter
29
57
  #
30
- def has_one(role, target_class=nil)
31
- has_one_internal(role, target_class)
58
+ def has_one(role, target_class=nil, raw_props={}, &block)
59
+ props = ReferenceDescription.new(target_class, _ownProps(raw_props).merge({
60
+ :name=>role, :upperBound=>1, :containment=>false}))
61
+ raise "No opposite available" unless _oppositeProps(raw_props).empty?
62
+ FeatureBlockEvaluator.eval(block, props)
63
+ _build_internal(props)
32
64
  end
33
65
 
34
66
  # Add an unidirectional _many_ association.
@@ -44,8 +76,28 @@ module BuilderExtensions
44
76
  # Note that the first letter of the role name is turned into an uppercase
45
77
  # for the add and remove methods.
46
78
  #
47
- def has_many(role, target_class=nil)
48
- has_many_internal(role, target_class)
79
+ def has_many(role, target_class=nil, raw_props={}, &block)
80
+ props = ReferenceDescription.new(target_class, _ownProps(raw_props).merge({
81
+ :name=>role, :upperBound=>-1, :containment=>false}))
82
+ raise "No opposite available" unless _oppositeProps(raw_props).empty?
83
+ FeatureBlockEvaluator.eval(block, props)
84
+ _build_internal(props)
85
+ end
86
+
87
+ def contains_one_uni(role, target_class=nil, raw_props={}, &block)
88
+ props = ReferenceDescription.new(target_class, _ownProps(raw_props).merge({
89
+ :name=>role, :upperBound=>1, :containment=>true}))
90
+ raise "No opposite available" unless _oppositeProps(raw_props).empty?
91
+ FeatureBlockEvaluator.eval(block, props)
92
+ _build_internal(props)
93
+ end
94
+
95
+ def contains_many_uni(role, target_class=nil, raw_props={}, &block)
96
+ props = ReferenceDescription.new(target_class, _ownProps(raw_props).merge({
97
+ :name=>role, :upperBound=>-1, :containment=>true}))
98
+ raise "No opposite available" unless _oppositeProps(raw_props).empty?
99
+ FeatureBlockEvaluator.eval(block, props)
100
+ _build_internal(props)
49
101
  end
50
102
 
51
103
  # Add a bidirectional one-to-many association between two classes.
@@ -69,15 +121,32 @@ module BuilderExtensions
69
121
  # When an element is added/set on either side, this element also receives the element
70
122
  # is is added to as a new element.
71
123
  #
72
- def one_to_many(own_role, target_class, target_role)
73
- has_many_internal(own_role,target_class,target_role,:one)
74
- target_class.has_one_internal(target_role,self,own_role,:many)
124
+ def one_to_many(target_role, target_class, own_role, raw_props={}, &block)
125
+ props1 = ReferenceDescription.new(target_class, _ownProps(raw_props).merge({
126
+ :name=>target_role, :upperBound=>-1, :containment=>false}))
127
+ props2 = ReferenceDescription.new(self, _oppositeProps(raw_props).merge({
128
+ :name=>own_role, :upperBound=>1, :containment=>false}))
129
+ FeatureBlockEvaluator.eval(block, props1, props2)
130
+ _build_internal(props1, props2)
131
+ end
132
+
133
+ def contains_many(target_role, target_class, own_role, raw_props={}, &block)
134
+ props1 = ReferenceDescription.new(target_class, _ownProps(raw_props).merge({
135
+ :name=>target_role, :upperBound=>-1, :containment=>true}))
136
+ props2 = ReferenceDescription.new(self, _oppositeProps(raw_props).merge({
137
+ :name=>own_role, :upperBound=>1, :containment=>false}))
138
+ FeatureBlockEvaluator.eval(block, props1, props2)
139
+ _build_internal(props1, props2)
75
140
  end
76
141
 
77
142
  # This is the inverse of one_to_many provided for convenience.
78
- def many_to_one(own_role, target_class, target_role)
79
- has_one_internal(own_role,target_class,target_role,:many)
80
- target_class.has_many_internal(target_role,self,own_role,:one)
143
+ def many_to_one(target_role, target_class, own_role, raw_props={}, &block)
144
+ props1 = ReferenceDescription.new(target_class, _ownProps(raw_props).merge({
145
+ :name=>target_role, :upperBound=>1, :containment=>false}))
146
+ props2 = ReferenceDescription.new(self, _oppositeProps(raw_props).merge({
147
+ :name=>own_role, :upperBound=>-1, :containment=>false}))
148
+ FeatureBlockEvaluator.eval(block, props1, props2)
149
+ _build_internal(props1, props2)
81
150
  end
82
151
 
83
152
  # Add a bidirectional many-to-many association between two classes.
@@ -102,9 +171,13 @@ module BuilderExtensions
102
171
  # When an element is added on either side, this element also receives the element
103
172
  # is is added to as a new element.
104
173
  #
105
- def many_to_many(own_role, target_class, target_role)
106
- has_many_internal(own_role,target_class,target_role,:many)
107
- target_class.has_many_internal(target_role,self,own_role,:many)
174
+ def many_to_many(target_role, target_class, own_role, raw_props={}, &block)
175
+ props1 = ReferenceDescription.new(target_class, _ownProps(raw_props).merge({
176
+ :name=>target_role, :upperBound=>-1, :containment=>false}))
177
+ props2 = ReferenceDescription.new(self, _oppositeProps(raw_props).merge({
178
+ :name=>own_role, :upperBound=>-1, :containment=>false}))
179
+ FeatureBlockEvaluator.eval(block, props1, props2)
180
+ _build_internal(props1, props2)
108
181
  end
109
182
 
110
183
  # Add a bidirectional one-to-one association between two classes.
@@ -125,93 +198,217 @@ module BuilderExtensions
125
198
  # When an element is set on either side, this element also receives the element
126
199
  # is is added to as the new element.
127
200
  #
128
- def one_to_one(own_role, target_class, target_role)
129
- has_one_internal(own_role,target_class,target_role,:one)
130
- target_class.has_one_internal(target_role,self,own_role,:one)
201
+ def one_to_one(target_role, target_class, own_role, raw_props={}, &block)
202
+ props1 = ReferenceDescription.new(target_class, _ownProps(raw_props).merge({
203
+ :name=>target_role, :upperBound=>1, :containment=>false}))
204
+ props2 = ReferenceDescription.new(self, _oppositeProps(raw_props).merge({
205
+ :name=>own_role, :upperBound=>1, :containment=>false}))
206
+ FeatureBlockEvaluator.eval(block, props1, props2)
207
+ _build_internal(props1, props2)
131
208
  end
132
209
 
133
- # Returns the names of the classes attributes pointing to a single object.
134
- # The result includes this kind of attributes of the superclass.
135
- def one_attributes
136
- @one_attributes ||= []
137
- result = @one_attributes.dup
138
- result += superclass.one_attributes if superclass.respond_to?(:one_attributes)
139
- result
210
+ def contains_one(target_role, target_class, own_role, raw_props={}, &block)
211
+ props1 = ReferenceDescription.new(target_class, _ownProps(raw_props).merge({
212
+ :name=>target_role, :upperBound=>1, :containment=>true}))
213
+ props2 = ReferenceDescription.new(self, _oppositeProps(raw_props).merge({
214
+ :name=>own_role, :upperBound=>1, :containment=>false}))
215
+ FeatureBlockEvaluator.eval(block, props1, props2)
216
+ _build_internal(props1, props2)
140
217
  end
141
-
142
- # Returns the names of the classes attributes pointing to many other objects
143
- # The result includes this kind of attributes of the superclass.
144
- def many_attributes
145
- @many_attributes ||= []
146
- result = @many_attributes.dup
147
- result += superclass.many_attributes if superclass.respond_to?(:many_attributes)
148
- result
218
+
219
+ def _metamodel_description # :nodoc:
220
+ @metamodel_description ||= []
149
221
  end
150
222
 
223
+ def inherited(c)
224
+ c._class_module
225
+ end
226
+
227
+ def _class_module # :nodoc:
228
+ unless const_defined?(:ClassModule)
229
+ const_set(:ClassModule, Module.new)
230
+ include const_get(:ClassModule)
231
+ end
232
+ const_get(:ClassModule)
233
+ end
234
+
151
235
  protected
152
-
153
- def has_one_internal(name, cls=nil, role=nil, kind=nil)
154
- @one_attributes ||= []
155
- return if @one_attributes.include?(name)
156
- @one_attributes << name
157
- BuildHelper.build self, binding, <<-CODE
158
- def #{name}=(val)
159
- return if val == @#{name}
160
- <% if cls %>
161
- raise _assignmentTypeError(self,val,#{cls}) unless val.nil? or val.is_a? #{cls}
162
- <% end %>
163
- oldval = @#{name}
164
- @#{name} = val
165
- _unregister(self,oldval,"#{role}","#{kind}")
166
- _register(self,val,"#{role}","#{kind}")
167
- end
168
- def #{name}
169
- @#{name}
236
+
237
+ # Central builder method
238
+ #
239
+ def _build_internal(props1, props2=nil)
240
+ _metamodel_description << props1
241
+ if props1.is_a?(ReferenceDescription) && props1.many?
242
+ _build_many_methods(props1, props2)
243
+ else
244
+ _build_one_methods(props1, props2)
245
+ end
246
+ if props2
247
+ # this is a bidirectional reference
248
+ props1.opposite, props2.opposite = props2, props1
249
+ other_class = props1.impl_type
250
+ other_class._metamodel_description << props2
251
+ raise "Internal error: second description must be a ReferenceDescription" \
252
+ unless props2.is_a?(ReferenceDescription)
253
+ if props2.many?
254
+ other_class._build_many_methods(props2, props1)
255
+ else
256
+ other_class._build_one_methods(props2, props1)
170
257
  end
171
- alias get<%= firstToUpper(name) %> #{name}
172
- alias set<%= firstToUpper(name) %> #{name}=
173
- CODE
258
+ end
174
259
  end
175
260
 
176
- def has_many_internal(name, cls=nil, role=nil, kind = nil)
177
- @many_attributes ||= []
178
- return if @many_attributes.include?(name)
179
- @many_attributes << name
180
- BuildHelper.build self, binding, <<-CODE
181
- def add<%= firstToUpper(name) %>(val)
182
- @#{name} = [] unless @#{name}
183
- return if val.nil? or @#{name}.include?(val)
184
- <% if cls %>
185
- raise _assignmentTypeError(self,val,#{cls}) unless val.nil? or val.is_a? #{cls}
186
- <% end %>
187
- @#{name}.push val
188
- _register(self, val, "#{role}", "#{kind}")
189
- end
190
- def remove<%= firstToUpper(name) %>(val)
191
- @#{name} = [] unless @#{name}
192
- return unless @#{name}.include?(val)
193
- @#{name}.delete val
194
- _unregister(self, val, "#{role}", "#{kind}")
195
- end
261
+ # To-One association methods
262
+ #
263
+ def _build_one_methods(props, other_props=nil)
264
+ name = props.value(:name)
265
+ other_role = other_props && other_props.value(:name)
266
+ other_kind = other_props && ( other_props.many? ? :many : :one )
267
+
268
+ if props.value(:derived)
269
+ build_derived_method(name, props, :one)
270
+ else
271
+ BuildHelper.build _class_module, binding, <<-CODE
272
+
273
+ def #{name}
274
+ <% if props.is_a?(AttributeDescription) && props.value(:defaultValueLiteral) %>
275
+ <% defVal = props.value(:defaultValueLiteral) %>
276
+ <% defVal = '"'+defVal+'"' if props.impl_type == String %>
277
+ <% defVal = ':'+defVal if props.impl_type.is_a?(DataTypes::Enum) %>
278
+ @#{name}.nil? ? <%= defVal %> : @#{name}
279
+ <% else %>
280
+ @#{name}
281
+ <% end %>
282
+ end
283
+ alias get<%= firstToUpper(name) %> #{name}
284
+
285
+ CODE
286
+ end
287
+
288
+ if props.value(:changeable)
289
+ BuildHelper.build _class_module, binding, <<-CODE
290
+
291
+ def #{name}=(val)
292
+ return if val == @#{name}
293
+ <%= type_check_code("val", props) %>
294
+ oldval = @#{name}
295
+ @#{name} = val
296
+ <% if other_role && other_kind %>
297
+ _unregister(self,oldval,"#{other_role}","#{other_kind}")
298
+ _register(self,val,"#{other_role}","#{other_kind}")
299
+ <% end %>
300
+ end
301
+ alias set<%= firstToUpper(name) %> #{name}=
302
+
303
+ CODE
304
+
305
+ end
306
+ end
307
+
308
+ # To-Many association methods
309
+ #
310
+ def _build_many_methods(props, other_props=nil)
311
+ name = props.value(:name)
312
+ other_role = other_props && other_props.value(:name)
313
+ other_kind = other_props && ( other_props.many? ? :many : :one )
314
+
315
+ if props.value(:derived)
316
+ build_derived_method(name, props, :many)
317
+ else
318
+ BuildHelper.build _class_module, binding, <<-CODE
319
+
320
+ def #{name}
321
+ ( @#{name} ? @#{name}.dup : [] )
322
+ end
323
+ alias get<%= firstToUpper(name) %> #{name}
324
+
325
+ CODE
326
+ end
327
+
328
+ if props.value(:changeable)
329
+ BuildHelper.build _class_module, binding, <<-CODE
330
+
331
+ def add<%= firstToUpper(name) %>(val)
332
+ @#{name} = [] unless @#{name}
333
+ return if val.nil? or @#{name}.include?(val)
334
+ <%= type_check_code("val", props) %>
335
+ @#{name}.push val
336
+ <% if other_role && other_kind %>
337
+ _register(self, val, "#{other_role}", "#{other_kind}")
338
+ <% end %>
339
+ end
340
+
341
+ def remove<%= firstToUpper(name) %>(val)
342
+ @#{name} = [] unless @#{name}
343
+ return unless @#{name}.include?(val)
344
+ @#{name}.delete val
345
+ <% if other_role && other_kind %>
346
+ _unregister(self, val, "#{other_role}", "#{other_kind}")
347
+ <% end %>
348
+ end
349
+
350
+ def #{name}=(val)
351
+ return if val.nil?
352
+ raise _assignmentTypeError(self, val, Array) unless val.is_a? Array
353
+ getGeneric(:#{name}).each {|e|
354
+ remove<%= firstToUpper(name) %>(e)
355
+ }
356
+ val.each {|v|
357
+ add<%= firstToUpper(name) %>(v)
358
+ }
359
+ end
360
+ alias set<%= firstToUpper(name) %> #{name}=
361
+
362
+ CODE
363
+ end
364
+
365
+ end
366
+
367
+ private
368
+
369
+ def build_derived_method(name, props, kind)
370
+ raise "Implement method #{name}_derived instead of method #{name}" \
371
+ if (public_instance_methods+protected_instance_methods+private_instance_methods).include?(name)
372
+ BuildHelper.build _class_module, binding, <<-CODE
373
+
196
374
  def #{name}
197
- ( @#{name} ? @#{name}.dup : [] )
375
+ raise "Derived feature requires public implementation of method #{name}_derived" \
376
+ unless respond_to?(:#{name+"_derived"})
377
+ val = #{name}_derived
378
+ <% if kind == :many %>
379
+ raise _assignmentTypeError(self,val,Array) unless val && val.is_a?(Array)
380
+ val.each do |v|
381
+ <%= type_check_code("v", props) %>
382
+ end
383
+ <% else %>
384
+ <%= type_check_code("val", props) %>
385
+ <% end %>
386
+ val
198
387
  end
199
- def #{name}=(val)
200
- return if val.nil?
201
- raise _assignmentTypeError(self, val, Array) unless val.is_a? Array
202
- #{name}.each {|e|
203
- remove<%= firstToUpper(name) %>(e)
204
- }
205
- val.each {|v|
206
- add<%= firstToUpper(name) %>(v)
207
- }
208
- end
209
- alias get<%= firstToUpper(name) %> #{name}
210
- alias set<%= firstToUpper(name) %> #{name}=
388
+ alias get#{firstToUpper(name)} #{name}
389
+ #TODO final_method :#{name}
390
+
211
391
  CODE
212
- end
392
+ end
393
+
394
+ private
395
+
396
+ def _ownProps(props)
397
+ Hash[*(props.select{|k,v| !(k.to_s =~ /^opposite_/)}.flatten)]
398
+ end
213
399
 
400
+ def _oppositeProps(props)
401
+ r = {}
402
+ props.each_pair do |k,v|
403
+ if k.to_s =~ /^opposite_(.*)$/
404
+ r[$1.to_sym] = v
405
+ end
406
+ end
407
+ r
408
+ end
409
+
214
410
  end
411
+
215
412
  end
216
413
 
217
414
  end