rgen 0.4.3 → 0.4.4
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 +6 -0
- data/lib/mmgen/metamodel_generator.rb +2 -1
- data/lib/mmgen/mm_ext/{ecore_ext.rb → ecore_mmgen_ext.rb} +3 -7
- data/lib/mmgen/templates/metamodel_generator.tpl +10 -8
- data/lib/rgen/ecore/ecore_ext.rb +69 -0
- data/lib/rgen/ecore/ecore_transformer.rb +1 -1
- data/lib/rgen/metamodel_builder/builder_extensions.rb +10 -2
- data/lib/rgen/serializer/xmi11_serializer.rb +101 -0
- data/lib/rgen/serializer/xmi20_serializer.rb +7 -7
- data/lib/rgen/serializer/xml_serializer.rb +47 -14
- data/test/ea_serializer_test.rb +29 -0
- data/test/ea_serializer_test/ea_testmodel_regenerated.xml +821 -0
- data/test/metamodel_roundtrip_test.rb +1 -2
- data/test/metamodel_roundtrip_test/TestModel.rb +1 -0
- data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +34 -35
- data/test/metamodel_roundtrip_test/houseMetamodel_Regenerated.ecore +128 -236
- data/test/rgen_test.rb +1 -0
- metadata +93 -95
- data/lib/rgen/metamodel_builder.rb.bak +0 -196
- data/lib/rgen/metamodel_builder/builder_extensions.rb.bak +0 -437
- data/lib/rgen/metamodel_builder/builder_runtime.rb.bak +0 -73
- data/lib/rgen/name_helper.rb.bak +0 -37
- data/lib/rgen/template_language.rb.bak +0 -289
- data/lib/rgen/template_language/directory_template_container.rb.bak +0 -69
- data/lib/rgen/template_language/output_handler.rb.bak +0 -88
- data/lib/rgen/template_language/template_container.rb.bak +0 -196
- data/lib/rgen/transformer.rb.bak +0 -381
- data/test/environment_test.rb.bak +0 -52
- data/test/metamodel_builder_test.rb.bak +0 -443
- data/test/output_handler_test.rb.bak +0 -50
- data/test/template_language_test.rb.bak +0 -72
- data/test/transformer_test.rb.bak +0 -223
data/CHANGELOG
CHANGED
@@ -64,3 +64,9 @@
|
|
64
64
|
* Bugfix: Use object identity for metamodel to-many add/remove methods
|
65
65
|
* Bugfix: If expand's :for expression evaluates to nil an error is generated (silently used current context before)
|
66
66
|
* Template language indentation string can be set on DirectoryTemplateContainer and with the "file" command
|
67
|
+
|
68
|
+
=0.4.4 (Sep 10th, 2008)
|
69
|
+
|
70
|
+
* Added "abstract" metamodel DSL command
|
71
|
+
* Added ecore_ext.rb with convenience methods
|
72
|
+
* Added XMI1.1 serializer, revised XMLSerializer super class
|
@@ -16,10 +16,6 @@ module RGen
|
|
16
16
|
eSuperPackage.qualifiedModuleName(rootPackage) + "::" + moduleName
|
17
17
|
end
|
18
18
|
|
19
|
-
def allClassifiers
|
20
|
-
eSubpackages.inject(eClassifiers) {|r,p| r.concat(p.allClassifiers) }
|
21
|
-
end
|
22
|
-
|
23
19
|
def ancestorPackages
|
24
20
|
return [] unless eSuperPackage
|
25
21
|
[eSuperPackage] + eSuperPackage.ancestorPackages
|
@@ -66,17 +62,17 @@ module RGen
|
|
66
62
|
def classifierName
|
67
63
|
firstToUpper(name)
|
68
64
|
end
|
69
|
-
def
|
65
|
+
def qualifiedClassifierName(rootPackage)
|
70
66
|
(ePackage ? ePackage.qualifiedModuleName(rootPackage) + "::" : "") + classifierName
|
71
67
|
end
|
72
68
|
def ancestorPackages
|
73
69
|
return [] unless ePackage
|
74
70
|
[ePackage] + ePackage.ancestorPackages
|
75
71
|
end
|
76
|
-
def
|
72
|
+
def qualifiedClassifierNameIfRequired(package)
|
77
73
|
if ePackage != package
|
78
74
|
commonSuper = (package.ancestorPackages & ancestorPackages).first
|
79
|
-
|
75
|
+
qualifiedClassifierName(commonSuper)
|
80
76
|
else
|
81
77
|
classifierName
|
82
78
|
end
|
@@ -23,6 +23,7 @@
|
|
23
23
|
<% expand 'EnumTypes' %>
|
24
24
|
<% for c in ownClasses %><%nl%>
|
25
25
|
<% expand 'ClassHeader', this, :for => c %><%iinc%>
|
26
|
+
<% if c.abstract %>abstract<% end %>
|
26
27
|
<% expand 'annotations::Annotations', :for => c %>
|
27
28
|
<% expand 'Attribute', this, :foreach => c.eAttributes %>
|
28
29
|
<%idec%>
|
@@ -37,6 +38,7 @@
|
|
37
38
|
<% define 'GenerateClassesReordered', :for => EPackage do %>
|
38
39
|
<% for c in allClassesSorted %><%nl%>
|
39
40
|
<% expand 'ClassHeaderFullyQualified', this, :for => c %><%iinc%>
|
41
|
+
<% if c.abstract %>abstract<% end %>
|
40
42
|
<% expand 'annotations::Annotations', :for => c %>
|
41
43
|
<% expand 'Attribute', this, :foreach => c.eAttributes %>
|
42
44
|
<%idec%>
|
@@ -61,7 +63,7 @@
|
|
61
63
|
<% if upperBound == 1%>
|
62
64
|
has_attr '<%= name %>', <%nows%>
|
63
65
|
<% if eType.is_a?(EEnum) %><%nows%>
|
64
|
-
<%= eType.
|
66
|
+
<%= eType.qualifiedClassifierName(rootp) %><%nows%>
|
65
67
|
<% else %><%nows%>
|
66
68
|
<%= eType && eType.instanceClass.to_s %><%nows%>
|
67
69
|
<% end %><%nows%>
|
@@ -90,7 +92,7 @@
|
|
90
92
|
|
91
93
|
<% define 'GenerateAssocs', :for => EPackage do %>
|
92
94
|
<% refDone = {} %>
|
93
|
-
<% for ref in
|
95
|
+
<% for ref in eAllClassifiers.select{|c| c.is_a?(EClass)}.eReferences %>
|
94
96
|
<% if !refDone[ref] && ref.eOpposite %>
|
95
97
|
<% ref = ref.eOpposite if ref.eOpposite.containment %>
|
96
98
|
<% refDone[ref] = refDone[ref.eOpposite] = true %>
|
@@ -133,7 +135,7 @@
|
|
133
135
|
<% end %>
|
134
136
|
|
135
137
|
<% define 'Reference', :for => EReference do |cmd, rootpackage| %>
|
136
|
-
<%= eContainingClass.
|
138
|
+
<%= eContainingClass.qualifiedClassifierName(rootpackage) %>.<%= cmd %> '<%= name %>', <%= eType && eType.qualifiedClassifierName(rootpackage) %><%nows%>
|
137
139
|
<% if eOpposite %><%nows%>
|
138
140
|
, '<%= eOpposite.name%>'<%nows%>
|
139
141
|
<% end %><%nows%>
|
@@ -151,20 +153,20 @@
|
|
151
153
|
<% define 'ClassHeader', :for => EClass do |rootp| %>
|
152
154
|
class <%= classifierName %> < <% nows %>
|
153
155
|
<% if eSuperTypes.size > 1 %><% nows %>
|
154
|
-
RGen::MetamodelBuilder::MMMultiple(<%= eSuperTypes.collect{|t| t.
|
156
|
+
RGen::MetamodelBuilder::MMMultiple(<%= eSuperTypes.collect{|t| t.qualifiedClassifierNameIfRequired(rootp)}.join(', ') %>)
|
155
157
|
<% elsif eSuperTypes.size > 0 %><% nows %>
|
156
|
-
<%= eSuperTypes.first.
|
158
|
+
<%= eSuperTypes.first.qualifiedClassifierNameIfRequired(rootp) %>
|
157
159
|
<% else %><% nows %>
|
158
160
|
RGen::MetamodelBuilder::MMBase
|
159
161
|
<% end %>
|
160
162
|
<% end %>
|
161
163
|
|
162
164
|
<% define 'ClassHeaderFullyQualified', :for => EClass do |rootp| %>
|
163
|
-
class <%=
|
165
|
+
class <%= qualifiedClassifierName(rootp) %> < <% nows %>
|
164
166
|
<% if eSuperTypes.size > 1 %><% nows %>
|
165
|
-
RGen::MetamodelBuilder::MMMultiple(<%= eSuperTypes.collect{|t| t.
|
167
|
+
RGen::MetamodelBuilder::MMMultiple(<%= eSuperTypes.collect{|t| t.qualifiedClassifierName(rootp)}.join(', ') %>)
|
166
168
|
<% elsif eSuperTypes.size > 0 %><% nows %>
|
167
|
-
<%= eSuperTypes.first.
|
169
|
+
<%= eSuperTypes.first.qualifiedClassifierName(rootp) %>
|
168
170
|
<% else %><% nows %>
|
169
171
|
RGen::MetamodelBuilder::MMBase
|
170
172
|
<% end %>
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'rgen/array_extensions'
|
2
|
+
require 'rgen/ecore/ecore'
|
3
|
+
|
4
|
+
module RGen
|
5
|
+
module ECore
|
6
|
+
|
7
|
+
# make super type reference bidirectional
|
8
|
+
EClass.many_to_many 'eSuperTypes', ECore::EClass, 'eSubTypes'
|
9
|
+
|
10
|
+
module EModelElement::ClassModule
|
11
|
+
|
12
|
+
def annotationValue(source, tag)
|
13
|
+
detail = eAnnotations.select{ |a| a.source == source }.details.find{ |d| d.key == tag }
|
14
|
+
detail && detail.value
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
module EPackage::ClassModule
|
20
|
+
|
21
|
+
def qualifiedName
|
22
|
+
if eSuperPackage
|
23
|
+
eSuperPackage.qualifiedName+"::"+name
|
24
|
+
else
|
25
|
+
name
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def eAllClassifiers
|
30
|
+
eClassifiers + eSubpackages.eAllClassifiers
|
31
|
+
end
|
32
|
+
def eAllSubpackages
|
33
|
+
eSubpackages + eSubpackages.eAllSubpackages
|
34
|
+
end
|
35
|
+
|
36
|
+
def eClasses
|
37
|
+
eClassifiers.select{|c| c.is_a?(ECore::EClass)}
|
38
|
+
end
|
39
|
+
|
40
|
+
def eAllClasses
|
41
|
+
eClasses + eSubpackages.eAllClasses
|
42
|
+
end
|
43
|
+
|
44
|
+
def eDataTypes
|
45
|
+
eClassifiers.select{|c| c.is_a?(ECore::EDataType)}
|
46
|
+
end
|
47
|
+
|
48
|
+
def eAllDataTypes
|
49
|
+
eDataTypes + eSubpackages.eAllDataTypes
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module EClass::ClassModule
|
54
|
+
|
55
|
+
def qualifiedName
|
56
|
+
if ePackage
|
57
|
+
ePackage.qualifiedName+"::"+name
|
58
|
+
else
|
59
|
+
name
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def eAllSubTypes
|
64
|
+
eSubTypes + eSubTypes.eAllSubTypes
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -12,7 +12,7 @@ class ECoreTransformer < Transformer
|
|
12
12
|
|
13
13
|
transform Class, :to => EClass, :if => :convert? do
|
14
14
|
{ :name => name.gsub(/.*::(\w+)$/,'\1'),
|
15
|
-
:abstract =>
|
15
|
+
:abstract => _abstract_class,
|
16
16
|
:interface => false,
|
17
17
|
:eStructuralFeatures => trans(_metamodel_description),
|
18
18
|
:ePackage => trans(name =~ /(.*)::\w+$/ ? eval($1) : nil),
|
@@ -218,9 +218,17 @@ module BuilderExtensions
|
|
218
218
|
def _metamodel_description # :nodoc:
|
219
219
|
@metamodel_description ||= []
|
220
220
|
end
|
221
|
+
|
222
|
+
def abstract
|
223
|
+
@abstract = true
|
224
|
+
end
|
225
|
+
|
226
|
+
def _abstract_class
|
227
|
+
@abstract || false
|
228
|
+
end
|
221
229
|
|
222
|
-
|
223
|
-
|
230
|
+
def inherited(c)
|
231
|
+
c.send(:include, c.const_set(:ClassModule, Module.new))
|
224
232
|
end
|
225
233
|
|
226
234
|
protected
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'rgen/serializer/xml_serializer'
|
2
|
+
|
3
|
+
module RGen
|
4
|
+
|
5
|
+
module Serializer
|
6
|
+
|
7
|
+
class XMI11Serializer < XMLSerializer
|
8
|
+
|
9
|
+
def initialize(file)
|
10
|
+
super
|
11
|
+
@namespacePrefix = ""
|
12
|
+
end
|
13
|
+
|
14
|
+
def setNamespace(shortcut, url)
|
15
|
+
@namespaceShortcut = shortcut
|
16
|
+
@namespaceUrl = url
|
17
|
+
@namespacePrefix = shortcut+":"
|
18
|
+
end
|
19
|
+
|
20
|
+
def serialize(rootElement, headerInfo=nil)
|
21
|
+
attrs = {}
|
22
|
+
attrs['xmi.version'] = "1.1"
|
23
|
+
attrs['xmlns:'+@namespaceShortcut] = @namespaceUrl if @namespaceUrl
|
24
|
+
attrs['timestamp'] = Time.now.to_s
|
25
|
+
startTag("XMI", attrs)
|
26
|
+
if headerInfo
|
27
|
+
startTag("XMI.header")
|
28
|
+
writeHeaderInfo(headerInfo)
|
29
|
+
endTag("XMI.header")
|
30
|
+
end
|
31
|
+
startTag("XMI.content")
|
32
|
+
writeElement(rootElement)
|
33
|
+
endTag("XMI.content")
|
34
|
+
endTag("XMI")
|
35
|
+
end
|
36
|
+
|
37
|
+
def writeHeaderInfo(hash)
|
38
|
+
hash.each_pair do |k,v|
|
39
|
+
tag = "XMI." + k.to_s
|
40
|
+
startTag(tag)
|
41
|
+
if v.is_a?(Hash)
|
42
|
+
writeHeaderInfo(v)
|
43
|
+
else
|
44
|
+
writeText(v.to_s)
|
45
|
+
end
|
46
|
+
endTag(tag)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def writeElement(element)
|
51
|
+
tag = @namespacePrefix + element.class.ecore.name
|
52
|
+
attrs = attributeHash(element)
|
53
|
+
startTag(tag, attrs)
|
54
|
+
containmentReferences(element).each do |r|
|
55
|
+
roletag = @namespacePrefix + r.eContainingClass.name + "." + r.name
|
56
|
+
targets = element.getGeneric(r.name)
|
57
|
+
targets = [ targets ] unless targets.is_a?(Array)
|
58
|
+
targets.compact!
|
59
|
+
next if targets.empty?
|
60
|
+
startTag(roletag)
|
61
|
+
targets.each do |t|
|
62
|
+
writeElement(t)
|
63
|
+
end
|
64
|
+
endTag(roletag)
|
65
|
+
end
|
66
|
+
endTag(tag)
|
67
|
+
end
|
68
|
+
|
69
|
+
def attributeHash(element)
|
70
|
+
result = {"xmi.id" => xmiId(element)}
|
71
|
+
eAllAttributes(element).select{|a| !a.derived}.each do |a|
|
72
|
+
val = element.getGeneric(a.name)
|
73
|
+
result[a.name] = val unless val.nil? || val == ""
|
74
|
+
end
|
75
|
+
eAllReferences(element).each do |r|
|
76
|
+
next if r.derived
|
77
|
+
next if r.containment
|
78
|
+
next if r.eOpposite && r.eOpposite.containment
|
79
|
+
next if r.eOpposite && r.many && !r.eOpposite.many
|
80
|
+
targetElements = element.getGeneric(r.name)
|
81
|
+
targetElements = [targetElements] unless targetElements.is_a?(Array)
|
82
|
+
targetElements.compact!
|
83
|
+
val = targetElements.collect{|te| xmiId(te)}.compact.join(' ')
|
84
|
+
result[r.name] = val unless val == ""
|
85
|
+
end
|
86
|
+
result
|
87
|
+
end
|
88
|
+
|
89
|
+
def xmiId(element)
|
90
|
+
if element.respond_to?(:_xmi_id) && element._xmi_id
|
91
|
+
element._xmi_id.to_s
|
92
|
+
else
|
93
|
+
element.object_id.to_s
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -14,19 +14,19 @@ class XMI20Serializer < XMLSerializer
|
|
14
14
|
attrs['xmlns:xsi'] = "http://www.w3.org/2001/XMLSchema-instance"
|
15
15
|
attrs['xmlns:ecore'] = "http://www.eclipse.org/emf/2002/Ecore"
|
16
16
|
tag = "ecore:"+rootElement.class.ecore.name
|
17
|
-
startTag(tag, attrs
|
18
|
-
writeComposites(rootElement
|
19
|
-
endTag(tag
|
17
|
+
startTag(tag, attrs)
|
18
|
+
writeComposites(rootElement)
|
19
|
+
endTag(tag)
|
20
20
|
end
|
21
21
|
|
22
|
-
def writeComposites(element
|
22
|
+
def writeComposites(element)
|
23
23
|
eachReferencedElement(element, containmentReferences(element)) do |r,te|
|
24
24
|
attrs = attributeHash(te)
|
25
25
|
attrs['xsi:type'] = "ecore:"+te.class.ecore.name
|
26
26
|
tag = r.name
|
27
|
-
startTag(tag, attrs
|
28
|
-
writeComposites(te
|
29
|
-
endTag(tag
|
27
|
+
startTag(tag, attrs)
|
28
|
+
writeComposites(te)
|
29
|
+
endTag(tag)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -4,25 +4,41 @@ module Serializer
|
|
4
4
|
|
5
5
|
class XMLSerializer
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
INDENT_SPACE = 2
|
8
|
+
|
9
|
+
def initialize(file)
|
10
|
+
@indent = 0
|
11
|
+
@lastStartTag = nil
|
12
|
+
@textContent = false
|
13
|
+
@file = file
|
13
14
|
end
|
14
15
|
|
15
16
|
def serialize(rootElement)
|
16
17
|
raise "Abstract class, overwrite method in subclass!"
|
17
18
|
end
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
|
20
|
+
def startTag(tag, attributes={})
|
21
|
+
@textContent = false
|
22
|
+
handleLastStartTag(false, true)
|
23
|
+
@lastStartTag = " "*@indent*INDENT_SPACE +
|
24
|
+
"<#{tag} "+attributes.keys.collect{|k| "#{k}=\"#{attributes[k]}\""}.join(" ")
|
25
|
+
@indent += 1
|
26
|
+
end
|
27
|
+
|
28
|
+
def endTag(tag)
|
29
|
+
@indent -= 1
|
30
|
+
unless handleLastStartTag(true, true)
|
31
|
+
output " "*@indent*INDENT_SPACE unless @textContent
|
32
|
+
output "</#{tag}>\n"
|
33
|
+
end
|
34
|
+
@textContent = false
|
35
|
+
end
|
22
36
|
|
23
|
-
|
24
|
-
|
25
|
-
|
37
|
+
def writeText(text)
|
38
|
+
handleLastStartTag(false, false)
|
39
|
+
output "#{text}"
|
40
|
+
@textContent = true
|
41
|
+
end
|
26
42
|
|
27
43
|
protected
|
28
44
|
|
@@ -52,8 +68,25 @@ class XMLSerializer
|
|
52
68
|
end
|
53
69
|
|
54
70
|
def containmentReferences(element)
|
55
|
-
|
71
|
+
@containmentReferences ||= {}
|
72
|
+
@containmentReferences[element.class] ||= eAllReferences(element).select{|r| r.containment}
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def handleLastStartTag(close, newline)
|
78
|
+
return false unless @lastStartTag
|
79
|
+
output @lastStartTag
|
80
|
+
output close ? "/>" : ">"
|
81
|
+
output "\n" if newline
|
82
|
+
@lastStartTag = nil
|
83
|
+
true
|
84
|
+
end
|
85
|
+
|
86
|
+
def output(text)
|
87
|
+
@file.write(text)
|
56
88
|
end
|
89
|
+
|
57
90
|
end
|
58
91
|
|
59
92
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),"..","lib")
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'rgen/environment'
|
5
|
+
require 'metamodels/uml13_metamodel'
|
6
|
+
require 'instantiators/ea_instantiator'
|
7
|
+
require 'rgen/serializer/xmi11_serializer'
|
8
|
+
|
9
|
+
class EASerializerTest < Test::Unit::TestCase
|
10
|
+
|
11
|
+
MODEL_DIR = File.join(File.dirname(__FILE__),"testmodel")
|
12
|
+
TEST_DIR = File.join(File.dirname(__FILE__),"ea_serializer_test")
|
13
|
+
|
14
|
+
def test_serializer
|
15
|
+
envUML = RGen::Environment.new
|
16
|
+
File.open(MODEL_DIR+"/ea_testmodel.xml") { |f|
|
17
|
+
inst = EAInstantiator.new(envUML, EAInstantiator::ERROR)
|
18
|
+
inst.instantiate(f.read)
|
19
|
+
}
|
20
|
+
models = envUML.find(:class => UML13::Model)
|
21
|
+
assert_equal 1, models.size
|
22
|
+
|
23
|
+
File.open(TEST_DIR+"/ea_testmodel_regenerated.xml", "w") do |f|
|
24
|
+
ser = RGen::Serializer::XMI11Serializer.new(f)
|
25
|
+
ser.serialize(models.first, {:documentation => {:exporter => "Enterprise Architect", :exporterVersion => "2.5"}})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|