rgen 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -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
- # has_one 'name', String
27
- # has_one 'age', Integer
30
+ # has_attr 'name', String
31
+ # has_attr 'age', Integer
28
32
  # end
29
33
  #
30
34
  # class House < RGen::MetamodelBuilder::MMBase
31
- # has_one 'address'
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, just leave away the
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
- # _Unidirectional_ associations can be thought of as attributes as shown above. This means
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