rgen 0.2.0 → 0.3.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.
- data/CHANGELOG +9 -0
- data/lib/ea/xmi_class_instantiator.rb +17 -16
- data/lib/ea/xmi_helper.rb +1 -1
- data/lib/ea/xmi_metamodel.rb +25 -10
- data/lib/ea/xmi_object_instantiator.rb +16 -12
- data/lib/ea/xmi_to_classmodel.rb +19 -19
- data/lib/ea/xmi_to_objectmodel.rb +17 -14
- data/lib/mmgen/mmgen.rb +12 -7
- data/lib/rgen/instantiator.rb +62 -0
- data/lib/rgen/metamodel_builder/builder_extensions.rb +30 -4
- data/lib/rgen/model_dumper.rb +24 -0
- data/lib/rgen/name_helper.rb +4 -1
- data/lib/rgen/transformer.rb +20 -2
- data/lib/rgen/xml_instantiator.rb +132 -0
- data/test/metamodel_builder_test.rb +86 -0
- data/test/metamodel_generator_test.rb +1 -2
- data/test/rgen_test.rb +1 -0
- data/test/transformer_test.rb +27 -0
- data/test/xmi_class_instantiator_test.rb +8 -91
- data/test/xmi_instantiator_test/class_model_checker.rb +97 -0
- data/test/xmi_object_instantiator_test.rb +3 -3
- data/test/xml_instantiator_test/testmodel.xml +7 -0
- data/test/xml_instantiator_test.rb +83 -0
- metadata +9 -6
- data/lib/rgen/xml_instantiator/dependency_resolver.rb +0 -23
- data/lib/rgen/xml_instantiator/xml_instantiator.rb +0 -78
- data/lib/rgen/xml_instantiator/xml_parser.rb +0 -39
data/CHANGELOG
CHANGED
@@ -7,3 +7,12 @@
|
|
7
7
|
* Added model transformation language (Transformer)
|
8
8
|
* Now RGen is distributed as a gem
|
9
9
|
* More complete documentation
|
10
|
+
|
11
|
+
=0.3.0 (October 9th, 2006)
|
12
|
+
|
13
|
+
* Improved XML Instantiator (Namespaces, Resolver, Customization)
|
14
|
+
* Added many_to_one builder method
|
15
|
+
* Added attribute reflection to MMBase (one_attributes, many_attributes)
|
16
|
+
* Added +copy+ method to Transformer
|
17
|
+
* Added simple model dumper module
|
18
|
+
* Fixed mmgen/mmgen.rb
|
@@ -1,18 +1,15 @@
|
|
1
|
-
require 'rgen/xml_instantiator
|
1
|
+
require 'rgen/xml_instantiator'
|
2
2
|
require 'rgen/environment'
|
3
3
|
require 'uml/uml_classmodel'
|
4
4
|
require 'ea/xmi_metamodel'
|
5
5
|
|
6
6
|
# This module can be used to instantiate an UMLClassModel from an XMI description.
|
7
|
-
# It should be mixed into the using class.
|
8
7
|
#
|
9
8
|
# Here is an example:
|
10
9
|
#
|
11
|
-
# include XMIClassInstantiator
|
12
|
-
#
|
13
10
|
# envUML = RGen::Environment.new
|
14
11
|
# File.open(MODEL_DIR+"/testmodel.xml") { |f|
|
15
|
-
# instantiateUMLClassModel(envUML, f.read)
|
12
|
+
# XMIClassInstantiator.new.instantiateUMLClassModel(envUML, f.read)
|
16
13
|
# }
|
17
14
|
#
|
18
15
|
# # now use the newly created UML model
|
@@ -22,24 +19,28 @@ require 'ea/xmi_metamodel'
|
|
22
19
|
#
|
23
20
|
# This module relies on XmiToClassmodel to do the actual transformation.
|
24
21
|
#
|
25
|
-
|
22
|
+
class XMIClassInstantiator < RGen::XMLInstantiator
|
26
23
|
|
27
24
|
include UMLClassModel
|
25
|
+
|
26
|
+
map_tag_ns "omg.org/UML1.3", XMIMetaModel::UML
|
27
|
+
|
28
|
+
resolve_by_id :typeClass, :src => :type, :id => :xmi_id
|
29
|
+
resolve_by_id :subtypeClass, :src => :subtype, :id => :xmi_id
|
30
|
+
resolve_by_id :supertypeClass, :src => :supertype, :id => :xmi_id
|
28
31
|
|
32
|
+
def initialize
|
33
|
+
@envXMI = RGen::Environment.new
|
34
|
+
super(@envXMI, XMIMetaModel, true)
|
35
|
+
end
|
36
|
+
|
29
37
|
# This method does the actual work.
|
30
38
|
def instantiateUMLClassModel(envOut, str)
|
31
|
-
|
32
|
-
|
33
|
-
i.resolveById("xmi_id","subtype")
|
34
|
-
i.resolveById("xmi_id","supertype")
|
35
|
-
end
|
36
|
-
|
37
|
-
envXMI = RGen::Environment.new
|
38
|
-
inst.instantiate(envXMI, str)
|
39
|
-
|
39
|
+
instantiate(str)
|
40
|
+
|
40
41
|
require 'ea/xmi_to_classmodel'
|
41
42
|
|
42
|
-
XmiToClassmodel.new(envXMI,envOut).transform
|
43
|
+
XmiToClassmodel.new(@envXMI,envOut).transform
|
43
44
|
end
|
44
45
|
|
45
46
|
end
|
data/lib/ea/xmi_helper.rb
CHANGED
data/lib/ea/xmi_metamodel.rb
CHANGED
@@ -1,19 +1,34 @@
|
|
1
|
+
module XMIMetaModel
|
1
2
|
|
2
|
-
module
|
3
|
+
module UML
|
4
|
+
|
3
5
|
include RGen::MetamodelBuilder
|
4
|
-
class
|
6
|
+
class Classifier_feature < MMBase
|
7
|
+
has_many 'operation'
|
8
|
+
end
|
9
|
+
class ClassifierRole < MMBase
|
10
|
+
end
|
11
|
+
class Clazz < ClassifierRole
|
12
|
+
has_many 'modelElement_stereotype'
|
5
13
|
end
|
6
|
-
class
|
14
|
+
class Operation < MMBase
|
15
|
+
has_one 'parent'
|
7
16
|
end
|
8
|
-
class
|
17
|
+
class Generalization < MMBase
|
9
18
|
end
|
10
|
-
class
|
19
|
+
class ModelElement_stereotype < MMBase
|
20
|
+
has_one 'parent'
|
11
21
|
end
|
12
|
-
class
|
22
|
+
class AssociationEnd < MMBase
|
13
23
|
end
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
24
|
+
class AssociationEndRole < MMBase
|
25
|
+
end
|
26
|
+
ClassifierRole.one_to_many 'associationEnds', AssociationEnd, 'typeClass'
|
27
|
+
ClassifierRole.one_to_many 'associationEndRoles', AssociationEndRole, 'typeClass'
|
28
|
+
Clazz.one_to_many 'generalizationsAsSubtype', Generalization, 'subtypeClass'
|
29
|
+
Clazz.one_to_many 'generalizationsAsSupertype', Generalization, 'supertypeClass'
|
30
|
+
|
18
31
|
end
|
32
|
+
|
33
|
+
end
|
19
34
|
|
@@ -1,10 +1,9 @@
|
|
1
|
-
require 'rgen/xml_instantiator
|
1
|
+
require 'rgen/xml_instantiator'
|
2
2
|
require 'rgen/environment'
|
3
3
|
require 'uml/uml_objectmodel'
|
4
4
|
require 'ea/xmi_metamodel'
|
5
5
|
|
6
6
|
# This module can be used to instantiate an UMLObjectModel from an XMI description.
|
7
|
-
# It should be mixed into the using class.
|
8
7
|
#
|
9
8
|
# Here is an example:
|
10
9
|
#
|
@@ -12,7 +11,7 @@ require 'ea/xmi_metamodel'
|
|
12
11
|
#
|
13
12
|
# envUML = RGen::Environment.new
|
14
13
|
# File.open(MODEL_DIR+"/testmodel.xml") { |f|
|
15
|
-
# instantiateUMLObjectModel(envUML, f.read)
|
14
|
+
# XMIClassInstantiator.new.instantiateUMLObjectModel(envUML, f.read)
|
16
15
|
# }
|
17
16
|
#
|
18
17
|
# # now use the newly created UML model
|
@@ -22,21 +21,26 @@ require 'ea/xmi_metamodel'
|
|
22
21
|
#
|
23
22
|
# This module relies on XmiToObjectmodel to do the actual transformation.
|
24
23
|
#
|
25
|
-
|
24
|
+
class XMIObjectInstantiator < RGen::XMLInstantiator
|
26
25
|
|
27
26
|
include UMLObjectModel
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
envXMI = RGen::Environment.new
|
35
|
-
inst.instantiate(envXMI, str)
|
28
|
+
map_tag_ns "omg.org/UML1.3", XMIMetaModel::UML
|
29
|
+
|
30
|
+
resolve_by_id :typeClass, :src => :type, :id => :xmi_id
|
36
31
|
|
32
|
+
def initialize
|
33
|
+
@envXMI = RGen::Environment.new
|
34
|
+
super(@envXMI, XMIMetaModel, true)
|
35
|
+
end
|
36
|
+
|
37
|
+
# This method does the actual work.
|
38
|
+
def instantiateUMLObjectModel(envOut, str)
|
39
|
+
instantiate(str)
|
40
|
+
|
37
41
|
require 'ea/xmi_to_objectmodel'
|
38
42
|
|
39
|
-
XmiToObjectmodel.new(envXMI,envOut).transform
|
43
|
+
XmiToObjectmodel.new(@envXMI,envOut).transform
|
40
44
|
end
|
41
45
|
|
42
46
|
end
|
data/lib/ea/xmi_to_classmodel.rb
CHANGED
@@ -17,45 +17,45 @@ class XmiToClassmodel < RGen::Transformer
|
|
17
17
|
# Do the actual transformation.
|
18
18
|
# Input and output environment have to be provided to the transformer constructor.
|
19
19
|
def transform
|
20
|
-
trans(:class => XMIMetaModel::
|
20
|
+
trans(:class => XMIMetaModel::UML::Clazz)
|
21
21
|
end
|
22
22
|
|
23
|
-
transform XMIMetaModel::
|
23
|
+
transform XMIMetaModel::UML::Package, :to => UMLPackage do
|
24
24
|
{ :name => name,
|
25
|
-
:superpackage => trans(
|
25
|
+
:superpackage => trans(parent.parent.is_a?(XMIMetaModel::UML::Package) ? parent.parent : nil) }
|
26
26
|
end
|
27
27
|
|
28
|
-
transform XMIMetaModel::
|
28
|
+
transform XMIMetaModel::UML::Attribute, :to => UMLAttribute do
|
29
29
|
tv = TaggedValueHelper.new(@current_object)
|
30
30
|
{ :name => name, :type => tv['type'] }
|
31
31
|
end
|
32
32
|
|
33
|
-
transform XMIMetaModel::
|
33
|
+
transform XMIMetaModel::UML::Operation, :to => UMLOperation do
|
34
34
|
{ :name => name }
|
35
35
|
end
|
36
36
|
|
37
|
-
transform XMIMetaModel::
|
37
|
+
transform XMIMetaModel::UML::TaggedValue, :to => UMLTaggedValue do
|
38
38
|
{ :tag => tag, :value => value }
|
39
39
|
end
|
40
40
|
|
41
|
-
transform XMIMetaModel::
|
41
|
+
transform XMIMetaModel::UML::Clazz, :to => UMLClass do
|
42
42
|
{ :name => name,
|
43
|
-
:package => trans(
|
44
|
-
:attributes => trans(
|
45
|
-
:operations => trans(
|
46
|
-
:taggedvalues => trans(
|
47
|
-
:stereotypes =>
|
48
|
-
:subclasses => trans(
|
49
|
-
:assocEnds => trans(
|
43
|
+
:package => trans(parent.parent.is_a?(XMIMetaModel::UML::Package) ? parent.parent : nil),
|
44
|
+
:attributes => trans(classifier_feature.attribute),
|
45
|
+
:operations => trans(classifier_feature.operation),
|
46
|
+
:taggedvalues => trans(modelElement_taggedValue.taggedValue),
|
47
|
+
:stereotypes => modelElement_stereotype.stereotype.name,
|
48
|
+
:subclasses => trans(generalizationsAsSupertype.subtypeClass),
|
49
|
+
:assocEnds => trans(associationEnds)}
|
50
50
|
end
|
51
51
|
|
52
|
-
transform XMIMetaModel::
|
52
|
+
transform XMIMetaModel::UML::Association, :to => :scAssociationClass do
|
53
53
|
{ :endA => trans(scAssocEnds[0]),
|
54
54
|
:endB => trans(scAssocEnds[1]) }
|
55
55
|
end
|
56
56
|
|
57
57
|
method :scAssocEnds do
|
58
|
-
|
58
|
+
association_connection.associationEnd
|
59
59
|
end
|
60
60
|
|
61
61
|
method :scAssociationClass do
|
@@ -64,11 +64,11 @@ class XmiToClassmodel < RGen::Transformer
|
|
64
64
|
UMLAggregation : UMLAssociation )
|
65
65
|
end
|
66
66
|
|
67
|
-
transform XMIMetaModel::
|
67
|
+
transform XMIMetaModel::UML::AssociationEnd, :to => UMLAssociationEnd do
|
68
68
|
# since we don't want to figure out if we are end A or end B,
|
69
69
|
# we let the association transformer do the work
|
70
|
-
trans(
|
71
|
-
{ :clazz => trans(
|
70
|
+
trans(parent.parent)
|
71
|
+
{ :clazz => trans(typeClass),
|
72
72
|
:role => name,
|
73
73
|
:multiplicity => multiplicity,
|
74
74
|
:composite => (aggregation == 'composite'),
|
@@ -17,22 +17,25 @@ class XmiToObjectmodel < RGen::Transformer
|
|
17
17
|
# Do the actual transformation.
|
18
18
|
# Input and output environment have to be provided to the transformer constructor.
|
19
19
|
def transform
|
20
|
-
trans(
|
20
|
+
trans(
|
21
|
+
@env_in.find(:class => XMIMetaModel::UML::ClassifierRole)-
|
22
|
+
@env_in.find(:class => XMIMetaModel::UML::Clazz)
|
23
|
+
)
|
21
24
|
end
|
22
25
|
|
23
|
-
transform XMIMetaModel::
|
26
|
+
transform XMIMetaModel::UML::Package, :to => UMLPackage do
|
24
27
|
{ :name => name,
|
25
|
-
:superpackage => trans(
|
28
|
+
:superpackage => trans(parent.parent.is_a?(XMIMetaModel::UML::Package) ? parent.parent : nil) }
|
26
29
|
end
|
27
30
|
|
28
|
-
transform XMIMetaModel::
|
29
|
-
trans(
|
30
|
-
trans(
|
31
|
+
transform XMIMetaModel::UML::ClassifierRole, :to => UMLObject, :if => :isEASTypeObject do
|
32
|
+
trans(associationEndRoles.parent.parent)
|
33
|
+
trans(associationEnds.parent.parent)
|
31
34
|
taggedValues = TaggedValueHelper.new(@current_object)
|
32
35
|
{ :name => name,
|
33
36
|
:classname => taggedValues['classname'],
|
34
37
|
:attributeSettings => createAttributeSettings(taggedValues['runstate']),
|
35
|
-
:package => trans(
|
38
|
+
:package => trans(parent.parent.parent.parent) }
|
36
39
|
end
|
37
40
|
|
38
41
|
method :isEASTypeObject do
|
@@ -56,8 +59,8 @@ class XmiToObjectmodel < RGen::Transformer
|
|
56
59
|
result
|
57
60
|
end
|
58
61
|
|
59
|
-
transform XMIMetaModel::
|
60
|
-
ends =
|
62
|
+
transform XMIMetaModel::UML::AssociationRole, :to => UMLAssociation, :if => :isEATypeAssociation do
|
63
|
+
ends = association_connection.associationEndRole
|
61
64
|
{ :endA => trans(ends[0]), :endB => trans(ends[1])}
|
62
65
|
end
|
63
66
|
|
@@ -66,21 +69,21 @@ class XmiToObjectmodel < RGen::Transformer
|
|
66
69
|
taggedValues['ea_type'] == 'Association'
|
67
70
|
end
|
68
71
|
|
69
|
-
transform XMIMetaModel::
|
70
|
-
ends =
|
72
|
+
transform XMIMetaModel::UML::Association, :to => UMLAggregation do
|
73
|
+
ends = association_connection.associationEnd
|
71
74
|
{ :endA => trans(ends[0]), :endB => trans(ends[1])}
|
72
75
|
end
|
73
76
|
|
74
|
-
transform XMIMetaModel::
|
77
|
+
transform XMIMetaModel::UML::AssociationEndRole, :to => UMLAssociationEnd do
|
75
78
|
buildAssociationEnd
|
76
79
|
end
|
77
80
|
|
78
|
-
transform XMIMetaModel::
|
81
|
+
transform XMIMetaModel::UML::AssociationEnd, :to => UMLAssociationEnd do
|
79
82
|
buildAssociationEnd
|
80
83
|
end
|
81
84
|
|
82
85
|
method :buildAssociationEnd do
|
83
|
-
{ :object => trans(
|
86
|
+
{ :object => trans(typeClass),
|
84
87
|
:role => name,
|
85
88
|
:composite => (aggregation == 'composite'),
|
86
89
|
:navigable => (isNavigable == 'true') }
|
data/lib/mmgen/mmgen.rb
CHANGED
@@ -1,21 +1,26 @@
|
|
1
|
-
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),"..")
|
2
|
+
|
3
|
+
require 'ea/xmi_class_instantiator'
|
2
4
|
require 'mmgen/metamodel_generator'
|
3
5
|
|
4
|
-
include XMIClassInstantiator
|
5
6
|
include MMGen::MetamodelGenerator
|
6
7
|
|
7
|
-
unless ARGV.length
|
8
|
-
puts "Usage: mmgen.rb <xmi_class_model_file>"
|
8
|
+
unless ARGV.length >= 2
|
9
|
+
puts "Usage: mmgen.rb <xmi_class_model_file> <root package> (<module>)*"
|
9
10
|
exit
|
10
11
|
else
|
11
12
|
file_name = ARGV.shift
|
12
|
-
|
13
|
+
root_package_name = ARGV.shift
|
14
|
+
modules = ARGV
|
15
|
+
out_file = file_name.gsub(/\.\w+$/,'.rb')
|
13
16
|
puts out_file
|
14
17
|
end
|
15
18
|
|
16
19
|
envUML = RGen::Environment.new
|
17
20
|
File.open(file_name) { |f|
|
18
|
-
instantiateUMLClassModel(envUML, f.read)
|
21
|
+
XMIClassInstantiator.new.instantiateUMLClassModel(envUML, f.read)
|
19
22
|
}
|
20
23
|
|
21
|
-
|
24
|
+
rootPackage = envUML.find(:class => UMLClassModel::UMLPackage).select{|p| p.name == root_package_name}.first
|
25
|
+
|
26
|
+
generateMetamodel(rootPackage, out_file, modules)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module RGen
|
2
|
+
|
3
|
+
class Instantiator
|
4
|
+
|
5
|
+
ResolverDescription = Struct.new(:from, :attribute, :block) # :nodoc:
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :resolver_descs
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(env, mod)
|
12
|
+
@env = env
|
13
|
+
end
|
14
|
+
|
15
|
+
# Specifies that +attribute+ should be resolved. If +:class+ is specified,
|
16
|
+
# resolve +attribute+ only for objects of type class.
|
17
|
+
# The block must return the value to which the attribute should be assigned.
|
18
|
+
# The object for which the attribute is to be resolved will be accessible
|
19
|
+
# in the current context within the block.
|
20
|
+
#
|
21
|
+
def self.resolve(attribute, desc=nil, &block)
|
22
|
+
from = (desc.is_a?(Hash) && desc[:class])
|
23
|
+
self.resolver_descs ||= []
|
24
|
+
self.resolver_descs << ResolverDescription.new(from, attribute, block)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Resolves +attribute+ to a model element which has attribute +:id+ set to the
|
28
|
+
# value currently in attribute +:src+
|
29
|
+
#
|
30
|
+
def self.resolve_by_id(attribute, desc)
|
31
|
+
id_attr = (desc.is_a?(Hash) && desc[:id])
|
32
|
+
src_attr = (desc.is_a?(Hash) && desc[:src])
|
33
|
+
raise StandardError.new("No id attribute given.") unless id_attr
|
34
|
+
resolve(attribute) do
|
35
|
+
@env.find(id_attr => @current_object.send(src_attr)).first
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def method_missing(m, *args) #:nodoc:
|
42
|
+
if @current_object
|
43
|
+
@current_object.send(m)
|
44
|
+
else
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def resolve
|
50
|
+
self.class.resolver_descs ||= []
|
51
|
+
self.class.resolver_descs.each { |desc|
|
52
|
+
@env.find(:class => desc.from).each { |e|
|
53
|
+
old_object, @current_object = @current_object, e
|
54
|
+
e.send("#{desc.attribute}=", instance_eval(&desc.block)) if e.respond_to?("#{desc.attribute}=")
|
55
|
+
@current_object = old_object
|
56
|
+
}
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -74,6 +74,12 @@ module BuilderExtensions
|
|
74
74
|
target_class.has_one_internal(target_role,self,own_role,:many)
|
75
75
|
end
|
76
76
|
|
77
|
+
# 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)
|
81
|
+
end
|
82
|
+
|
77
83
|
# Add a bidirectional many-to-many association between two classes.
|
78
84
|
# The class this method is called on is refered to as _own_class_ in
|
79
85
|
# the following.
|
@@ -124,12 +130,31 @@ module BuilderExtensions
|
|
124
130
|
target_class.has_one_internal(target_role,self,own_role,:one)
|
125
131
|
end
|
126
132
|
|
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
|
140
|
+
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
|
149
|
+
end
|
150
|
+
|
127
151
|
protected
|
128
152
|
|
129
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
|
130
157
|
BuildHelper.build self, binding, <<-CODE
|
131
|
-
@@one_assocs ||= []
|
132
|
-
@@one_assocs << name
|
133
158
|
def #{name}=(val)
|
134
159
|
return if val == @#{name}
|
135
160
|
<% if cls %>
|
@@ -149,9 +174,10 @@ module BuilderExtensions
|
|
149
174
|
end
|
150
175
|
|
151
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
|
152
180
|
BuildHelper.build self, binding, <<-CODE
|
153
|
-
@@many_assocs ||= []
|
154
|
-
@@many_assocs << name
|
155
181
|
def add<%= firstToUpper(name) %>(val)
|
156
182
|
@#{name} = [] unless @#{name}
|
157
183
|
return if val.nil? or @#{name}.include?(val)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module RGen
|
2
|
+
|
3
|
+
module ModelDumper
|
4
|
+
|
5
|
+
def dump(obj=nil)
|
6
|
+
obj ||= self
|
7
|
+
if obj.is_a?(Array)
|
8
|
+
obj.collect {|o| dump(o)}.join("\n\n")
|
9
|
+
elsif obj.class.respond_to?(:one_attributes) && obj.class.respond_to?(:many_attributes)
|
10
|
+
([obj.to_s] +
|
11
|
+
obj.class.one_attributes.collect { |a|
|
12
|
+
" #{a} => #{obj.getGeneric(a)}"
|
13
|
+
} +
|
14
|
+
obj.class.many_attributes.collect { |a|
|
15
|
+
" #{a} => [ #{obj.getGeneric(a).join(', ')} ]"
|
16
|
+
}).join("\n")
|
17
|
+
else
|
18
|
+
obj.to_s
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/lib/rgen/name_helper.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
module RGen
|
5
5
|
|
6
6
|
module NameHelper
|
7
|
-
def
|
7
|
+
def normalize(name)
|
8
8
|
name.gsub(/[\.:]/,'_')
|
9
9
|
end
|
10
10
|
def className(object)
|
@@ -13,6 +13,9 @@ module NameHelper
|
|
13
13
|
def firstToUpper(str)
|
14
14
|
str[0..0].upcase + ( str[1..-1] || "" )
|
15
15
|
end
|
16
|
+
def firstToLower(str)
|
17
|
+
str[0..0].downcase + ( str[1..-1] || "" )
|
18
|
+
end
|
16
19
|
end
|
17
20
|
|
18
21
|
end
|
data/lib/rgen/transformer.rb
CHANGED
@@ -196,6 +196,22 @@ class Transformer
|
|
196
196
|
end
|
197
197
|
end
|
198
198
|
|
199
|
+
# This class method specifies that all objects of class +from+ are to be copied
|
200
|
+
# into an object of class +to+. If +to+ is omitted, +from+ is used as target class.
|
201
|
+
# During copy, all attributes according to
|
202
|
+
# MetamodelBuilder::BuilderExtensions.one_attributes and
|
203
|
+
# MetamodelBuilder::BuilderExtensions.many_attributes of the target object
|
204
|
+
# are set to their transformed counterparts of the source object.
|
205
|
+
#
|
206
|
+
def self.copy(from, to=nil)
|
207
|
+
transform(from, :to => to || from) do
|
208
|
+
Hash[*(@current_object.class.one_attributes +
|
209
|
+
@current_object.class.many_attributes).inject([]) {|l,a|
|
210
|
+
l + [a.to_sym, trans(@current_object.send(a))]
|
211
|
+
}]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
199
215
|
# Define a transformer method for the current transformer class.
|
200
216
|
# In contrast to regular Ruby methods, a method defined this way executes in the
|
201
217
|
# context of the object currently being transformed.
|
@@ -228,10 +244,12 @@ class Transformer
|
|
228
244
|
# * a hash used as input to Environment#find with the result being transformed
|
229
245
|
#
|
230
246
|
def trans(obj)
|
247
|
+
obj = @env_in.find(obj) if obj.is_a?(Hash)
|
231
248
|
return nil if obj.nil?
|
249
|
+
return obj if obj.is_a?(TrueClass) or obj.is_a?(FalseClass) or obj.is_a?(Numeric) or obj.is_a?(Symbol)
|
232
250
|
return @transformer_results[obj] if @transformer_results[obj]
|
233
|
-
obj =
|
234
|
-
return obj.collect{|o| trans(o)}.compact if obj.is_a?
|
251
|
+
return @transformer_results[obj] = obj.dup if obj.is_a?(String)
|
252
|
+
return obj.collect{|o| trans(o)}.compact if obj.is_a? Array
|
235
253
|
raise StandardError.new("No transformer for class #{obj.class.name}") unless self.class._transformer_blocks[obj.class]
|
236
254
|
block_desc = _evaluateCondition(obj)
|
237
255
|
return nil unless block_desc
|