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