rgen 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. data/CHANGELOG +6 -0
  2. data/lib/mmgen/metamodel_generator.rb +2 -1
  3. data/lib/mmgen/mm_ext/{ecore_ext.rb → ecore_mmgen_ext.rb} +3 -7
  4. data/lib/mmgen/templates/metamodel_generator.tpl +10 -8
  5. data/lib/rgen/ecore/ecore_ext.rb +69 -0
  6. data/lib/rgen/ecore/ecore_transformer.rb +1 -1
  7. data/lib/rgen/metamodel_builder/builder_extensions.rb +10 -2
  8. data/lib/rgen/serializer/xmi11_serializer.rb +101 -0
  9. data/lib/rgen/serializer/xmi20_serializer.rb +7 -7
  10. data/lib/rgen/serializer/xml_serializer.rb +47 -14
  11. data/test/ea_serializer_test.rb +29 -0
  12. data/test/ea_serializer_test/ea_testmodel_regenerated.xml +821 -0
  13. data/test/metamodel_roundtrip_test.rb +1 -2
  14. data/test/metamodel_roundtrip_test/TestModel.rb +1 -0
  15. data/test/metamodel_roundtrip_test/TestModel_Regenerated.rb +34 -35
  16. data/test/metamodel_roundtrip_test/houseMetamodel_Regenerated.ecore +128 -236
  17. data/test/rgen_test.rb +1 -0
  18. metadata +93 -95
  19. data/lib/rgen/metamodel_builder.rb.bak +0 -196
  20. data/lib/rgen/metamodel_builder/builder_extensions.rb.bak +0 -437
  21. data/lib/rgen/metamodel_builder/builder_runtime.rb.bak +0 -73
  22. data/lib/rgen/name_helper.rb.bak +0 -37
  23. data/lib/rgen/template_language.rb.bak +0 -289
  24. data/lib/rgen/template_language/directory_template_container.rb.bak +0 -69
  25. data/lib/rgen/template_language/output_handler.rb.bak +0 -88
  26. data/lib/rgen/template_language/template_container.rb.bak +0 -196
  27. data/lib/rgen/transformer.rb.bak +0 -381
  28. data/test/environment_test.rb.bak +0 -52
  29. data/test/metamodel_builder_test.rb.bak +0 -443
  30. data/test/output_handler_test.rb.bak +0 -50
  31. data/test/template_language_test.rb.bak +0 -72
  32. 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
@@ -1,7 +1,8 @@
1
1
  require 'rgen/environment'
2
2
  require 'rgen/template_language'
3
3
  require 'rgen/ecore/ecore'
4
- require 'mmgen/mm_ext/ecore_ext'
4
+ require 'rgen/ecore/ecore_ext'
5
+ require 'mmgen/mm_ext/ecore_mmgen_ext'
5
6
 
6
7
  module MMGen
7
8
 
@@ -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 qualifiedName(rootPackage)
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 qualifiedNameIfRequired(package)
72
+ def qualifiedClassifierNameIfRequired(package)
77
73
  if ePackage != package
78
74
  commonSuper = (package.ancestorPackages & ancestorPackages).first
79
- qualifiedName(commonSuper)
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.qualifiedName(rootp) %><%nows%>
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 allClassifiers.select{|c| c.is_a?(EClass)}.eReferences %>
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.qualifiedName(rootpackage) %>.<%= cmd %> '<%= name %>', <%= eType && eType.qualifiedName(rootpackage) %><%nows%>
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.qualifiedNameIfRequired(rootp)}.join(', ') %>)
156
+ RGen::MetamodelBuilder::MMMultiple(<%= eSuperTypes.collect{|t| t.qualifiedClassifierNameIfRequired(rootp)}.join(', ') %>)
155
157
  <% elsif eSuperTypes.size > 0 %><% nows %>
156
- <%= eSuperTypes.first.qualifiedNameIfRequired(rootp) %>
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 <%= qualifiedName(rootp) %> < <% nows %>
165
+ class <%= qualifiedClassifierName(rootp) %> < <% nows %>
164
166
  <% if eSuperTypes.size > 1 %><% nows %>
165
- RGen::MetamodelBuilder::MMMultiple(<%= eSuperTypes.collect{|t| t.qualifiedName(rootp)}.join(', ') %>)
167
+ RGen::MetamodelBuilder::MMMultiple(<%= eSuperTypes.collect{|t| t.qualifiedClassifierName(rootp)}.join(', ') %>)
166
168
  <% elsif eSuperTypes.size > 0 %><% nows %>
167
- <%= eSuperTypes.first.qualifiedName(rootp) %>
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 => false,
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
- def inherited(c)
223
- c.send(:include, c.const_set(:ClassModule, Module.new))
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, 0)
18
- writeComposites(rootElement, 1)
19
- endTag(tag, 0)
17
+ startTag(tag, attrs)
18
+ writeComposites(rootElement)
19
+ endTag(tag)
20
20
  end
21
21
 
22
- def writeComposites(element, indent)
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, indent)
28
- writeComposites(te, indent+1)
29
- endTag(tag, indent)
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
- def initialize
8
- @output = ""
9
- end
10
-
11
- def result
12
- @output
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
- def startTag(tag, attributes, indent)
20
- @output += " "*indent + "<#{tag} " + attributes.keys.collect{|k| "#{k}=\"#{attributes[k]}\""}.join(" ") + ">\n"
21
- end
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
- def endTag(tag, indent)
24
- @output += " "*indent + "</#{tag}>\n"
25
- end
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
- eAllReferences(element).select{|r| r.containment}
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