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