rgen 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +12 -0
- data/MIT-LICENSE +2 -2
- data/Rakefile +2 -2
- data/lib/mmgen/templates/metamodel_generator.tpl +4 -5
- data/lib/rgen/instantiator/ecore_xml_instantiator.rb +31 -22
- data/lib/rgen/instantiator/json_instantiator.rb +79 -0
- data/lib/rgen/instantiator/json_parser.rb +326 -0
- data/lib/rgen/instantiator/json_parser.y +89 -0
- data/lib/rgen/instantiator/qualified_name_resolver.rb +93 -0
- data/lib/rgen/instantiator/reference_resolver.rb +44 -0
- data/lib/rgen/metamodel_builder.rb +12 -1
- data/lib/rgen/metamodel_builder/builder_extensions.rb +40 -11
- data/lib/rgen/metamodel_builder/builder_runtime.rb +19 -1
- data/lib/rgen/serializer/json_serializer.rb +120 -0
- data/lib/rgen/serializer/xmi20_serializer.rb +14 -3
- data/test/json_test.rb +91 -0
- data/test/metamodel_builder_test.rb +194 -0
- data/test/metamodel_roundtrip_test.rb +37 -3
- data/test/metamodel_roundtrip_test/TestModel.rb +2 -1
- data/test/metamodel_roundtrip_test/houseMetamodel.ecore +1 -0
- data/test/metamodel_roundtrip_test/houseMetamodel_from_ecore.rb +1 -0
- data/test/metamodel_roundtrip_test/using_builtin_types.ecore +8 -0
- data/test/metamodel_roundtrip_test/using_builtin_types_serialized.ecore +8 -0
- data/test/qualified_name_resolver_test.rb +102 -0
- data/test/reference_resolver_test.rb +50 -0
- data/test/rgen_test.rb +4 -0
- metadata +16 -14
@@ -0,0 +1,89 @@
|
|
1
|
+
class JsonParser
|
2
|
+
|
3
|
+
rule
|
4
|
+
|
5
|
+
json: value { result = val[0] }
|
6
|
+
|
7
|
+
array: "[" valueList "]" { result = val[1] }
|
8
|
+
| "[" "]" { result = [] }
|
9
|
+
|
10
|
+
valueList: value { result = [ val[0] ] }
|
11
|
+
| value "," valueList { result = [ val[0] ] + val[2] }
|
12
|
+
|
13
|
+
object: "{" memberList "}" { result = @instantiator.createObject(val[1]) }
|
14
|
+
| "{" "}" { result = nil }
|
15
|
+
|
16
|
+
memberList: member { result = val[0] }
|
17
|
+
| member "," memberList { result = val[0].merge(val[2]) }
|
18
|
+
|
19
|
+
member: STRING ":" value { result = {val[0].value => val[2]} }
|
20
|
+
|
21
|
+
value: array { result = val[0] }
|
22
|
+
| object { result = val[0] }
|
23
|
+
| STRING { result = val[0].value }
|
24
|
+
| INTEGER { result = val[0].value.to_i }
|
25
|
+
| FLOAT { result = val[0].value.to_f }
|
26
|
+
| "true" { result = true }
|
27
|
+
| "false" { result = false }
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
---- header
|
32
|
+
|
33
|
+
module RGen
|
34
|
+
|
35
|
+
module Instantiator
|
36
|
+
|
37
|
+
---- inner
|
38
|
+
|
39
|
+
ParserToken = Struct.new(:line, :file, :value)
|
40
|
+
|
41
|
+
def initialize(instantiator)
|
42
|
+
@instantiator = instantiator
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse(str, file=nil)
|
46
|
+
@q = []
|
47
|
+
line = 1
|
48
|
+
|
49
|
+
until str.empty?
|
50
|
+
case str
|
51
|
+
when /\A\n/
|
52
|
+
str = $'
|
53
|
+
line +=1
|
54
|
+
when /\A\s+/
|
55
|
+
str = $'
|
56
|
+
when /\A([-+]?\d+\.\d+)/
|
57
|
+
str = $'
|
58
|
+
@q << [:FLOAT, ParserToken.new(line, file, $1)]
|
59
|
+
when /\A([-+]?\d+)/
|
60
|
+
str = $'
|
61
|
+
@q << [:INTEGER, ParserToken.new(line, file, $1)]
|
62
|
+
when /\A"((?:[^"\\]|\\"|\\\\|\\[^"\\])*)"/
|
63
|
+
str = $'
|
64
|
+
sval = $1
|
65
|
+
sval.gsub!('\\\\','\\')
|
66
|
+
sval.gsub!('\\"','"')
|
67
|
+
@q << [:STRING, ParserToken.new(line, file, sval)]
|
68
|
+
when /\A(\{|\}|\[|\]|,|:|true|false)/
|
69
|
+
str = $'
|
70
|
+
@q << [$1, ParserToken.new(line, file, $1)]
|
71
|
+
else
|
72
|
+
raise "parse error in line #{line} on "+str[0..20].inspect+"..."
|
73
|
+
end
|
74
|
+
end
|
75
|
+
@q.push [false, ParserToken.new(line, file, '$end')]
|
76
|
+
do_parse
|
77
|
+
end
|
78
|
+
|
79
|
+
def next_token
|
80
|
+
r = @q.shift
|
81
|
+
r
|
82
|
+
end
|
83
|
+
|
84
|
+
---- footer
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'rgen/instantiator/reference_resolver'
|
2
|
+
|
3
|
+
module RGen
|
4
|
+
|
5
|
+
module Instantiator
|
6
|
+
|
7
|
+
# This is a resolver resolving element identifiers which are qualified names.
|
8
|
+
class QualifiedNameResolver
|
9
|
+
include ReferenceResolver
|
10
|
+
|
11
|
+
attr_reader :nameAttribute
|
12
|
+
attr_reader :separator
|
13
|
+
attr_reader :leadingSeparator
|
14
|
+
|
15
|
+
def initialize(rootElements, options={})
|
16
|
+
@rootElements = rootElements
|
17
|
+
@nameAttribute = options[:nameAttribute] || "name"
|
18
|
+
@separator = options[:separator] || "/"
|
19
|
+
@leadingSeparator = options.has_key?(:leadingSeparator) ? options[:leadingSeparator] : true
|
20
|
+
@elementByQName = {}
|
21
|
+
@visitedQName = {}
|
22
|
+
@childReferences = {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def resolveIdentifier(qualifiedName)
|
26
|
+
return @elementByQName[qualifiedName] if @elementByQName.has_key?(qualifiedName)
|
27
|
+
path = qualifiedName.split(separator).reject{|s| s == ""}
|
28
|
+
if path.size > 1
|
29
|
+
parentQName = (leadingSeparator ? separator : "") + path[0..-2].join(separator)
|
30
|
+
parents = resolveIdentifier(parentQName)
|
31
|
+
parents = [parents].compact unless parents.is_a?(Array)
|
32
|
+
children = parents.collect{|p| allNamedChildren(p)}.flatten
|
33
|
+
elsif path.size == 1
|
34
|
+
parentQName = ""
|
35
|
+
children = allRootNamedChildren
|
36
|
+
else
|
37
|
+
return @elementByQName[qualifiedName] = nil
|
38
|
+
end
|
39
|
+
# if the parent was already visited all matching elements are the hash
|
40
|
+
if !@visitedQName[parentQName]
|
41
|
+
children.each do |c|
|
42
|
+
name = c.send(nameAttribute)
|
43
|
+
if name
|
44
|
+
qname = parentQName + ((parentQName != "" || leadingSeparator) ? separator : "") + name
|
45
|
+
existing = @elementByQName[qname]
|
46
|
+
if existing
|
47
|
+
@elementByQName[qname] = [existing] unless existing.is_a?(Array)
|
48
|
+
@elementByQName[qname] << c
|
49
|
+
else
|
50
|
+
@elementByQName[qname] = c
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
# all named children of praent have been checked and hashed
|
55
|
+
@visitedQName[parentQName] = true
|
56
|
+
end
|
57
|
+
@elementByQName[qualifiedName] ||= nil
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def allNamedChildren(element)
|
63
|
+
childReferences(element.class).collect do |r|
|
64
|
+
element.getGenericAsArray(r.name).collect do |c|
|
65
|
+
if c.respond_to?(nameAttribute)
|
66
|
+
c
|
67
|
+
else
|
68
|
+
allNamedChildren(c)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end.flatten
|
72
|
+
end
|
73
|
+
|
74
|
+
def allRootNamedChildren
|
75
|
+
@rootElements.collect do |e|
|
76
|
+
if e.respond_to?(nameAttribute)
|
77
|
+
e
|
78
|
+
else
|
79
|
+
allNamedChildren(e)
|
80
|
+
end
|
81
|
+
end.flatten
|
82
|
+
end
|
83
|
+
|
84
|
+
def childReferences(clazz)
|
85
|
+
@childReferences[clazz] ||= clazz.ecore.eAllReferences.select{|r| r.containment}
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module RGen
|
2
|
+
|
3
|
+
module Instantiator
|
4
|
+
|
5
|
+
# This module is meant to be mixed into a resolver class providing the method +resolveIdentifier+
|
6
|
+
module ReferenceResolver
|
7
|
+
|
8
|
+
# Instances of this class represent information about not yet resolved references.
|
9
|
+
# This consists of the +element+ and metamodel +featureName+ which hold/is to hold the reference
|
10
|
+
# and the proxy object which is the placeholder for the reference.
|
11
|
+
UnresolvedReference = Struct.new(:element, :featureName, :proxy)
|
12
|
+
|
13
|
+
# tries to resolve the given +unresolvedReferences+
|
14
|
+
# if resolution is successful, the proxy object will be removed
|
15
|
+
# otherwise there will be an error description in +problems+
|
16
|
+
# returns an array of the references which are still unresolved
|
17
|
+
def resolveReferences(unresolvedReferences, problems=[])
|
18
|
+
stillUnresolvedReferences = []
|
19
|
+
unresolvedReferences.each do |ur|
|
20
|
+
target = resolveIdentifier(ur.proxy.targetIdentifier)
|
21
|
+
if target && !target.is_a?(Array)
|
22
|
+
if ur.element.hasManyMethods(ur.featureName)
|
23
|
+
ur.element.removeGeneric(ur.featureName, ur.proxy)
|
24
|
+
ur.element.addGeneric(ur.featureName, target)
|
25
|
+
else
|
26
|
+
# this will replace the proxy
|
27
|
+
ur.element.setGeneric(ur.featureName, target)
|
28
|
+
end
|
29
|
+
elsif target
|
30
|
+
problems << "identifier #{ur.proxy.targetIdentifier} not uniq"
|
31
|
+
stillUnresolvedReferences << ur
|
32
|
+
else
|
33
|
+
problems << "identifier #{ur.proxy.targetIdentifier} not found"
|
34
|
+
stillUnresolvedReferences << ur
|
35
|
+
end
|
36
|
+
end
|
37
|
+
stillUnresolvedReferences
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -192,6 +192,17 @@ module MetamodelBuilder
|
|
192
192
|
end
|
193
193
|
end
|
194
194
|
|
195
|
+
# Instances of the proxy class can be used as values in any reference feature
|
196
|
+
# They can be used instead of the real target elements in case references should be resolved later on
|
197
|
+
class MMProxy
|
198
|
+
# The +targetIdentifer+ is an object identifying the element the proxy represents
|
199
|
+
attr_accessor :targetIdentifier
|
200
|
+
|
201
|
+
def initialize(ident=nil)
|
202
|
+
@targetIdentifier = ident
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
195
206
|
end
|
196
207
|
|
197
|
-
end
|
208
|
+
end
|
@@ -36,6 +36,15 @@ module BuilderExtensions
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
+
# Add an attribute which can hold a single value.
|
40
|
+
# 'role' specifies the name which is used to access the attribute.
|
41
|
+
# 'target_class' specifies the type of objects which can be held by this attribute.
|
42
|
+
# If no target class is given, String will be default.
|
43
|
+
#
|
44
|
+
# This class method adds the following instance methods, where 'role' is to be
|
45
|
+
# replaced by the given role name:
|
46
|
+
# class#role # getter
|
47
|
+
# class#role=(value) # setter
|
39
48
|
def has_attr(role, target_class=nil, raw_props={}, &block)
|
40
49
|
props = AttributeDescription.new(target_class, _ownProps(raw_props).merge({
|
41
50
|
:name=>role, :upperBound=>1}))
|
@@ -43,14 +52,34 @@ module BuilderExtensions
|
|
43
52
|
FeatureBlockEvaluator.eval(block, props)
|
44
53
|
_build_internal(props)
|
45
54
|
end
|
46
|
-
|
47
|
-
|
55
|
+
|
56
|
+
# Add an attribute which can hold multiple values.
|
48
57
|
# 'role' specifies the name which is used to access the attribute.
|
49
58
|
# 'target_class' specifies the type of objects which can be held by this attribute.
|
50
59
|
# If no target class is given, String will be default.
|
51
60
|
#
|
52
61
|
# This class method adds the following instance methods, where 'role' is to be
|
53
62
|
# replaced by the given role name:
|
63
|
+
# class#addRole(value)
|
64
|
+
# class#removeRole(value)
|
65
|
+
# class#role # getter, returns an array
|
66
|
+
# class#role= # setter, sets multiple values at once
|
67
|
+
# Note that the first letter of the role name is turned into an uppercase
|
68
|
+
# for the add and remove methods.
|
69
|
+
def has_many_attr(role, target_class=nil, raw_props={}, &block)
|
70
|
+
props = AttributeDescription.new(target_class, _setManyUpperBound(_ownProps(raw_props).merge({
|
71
|
+
:name=>role})))
|
72
|
+
raise "No opposite available" unless _oppositeProps(raw_props).empty?
|
73
|
+
FeatureBlockEvaluator.eval(block, props)
|
74
|
+
_build_internal(props)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Add a single unidirectional association.
|
78
|
+
# 'role' specifies the name which is used to access the association.
|
79
|
+
# 'target_class' specifies the type of objects which can be held by this association.
|
80
|
+
#
|
81
|
+
# This class method adds the following instance methods, where 'role' is to be
|
82
|
+
# replaced by the given role name:
|
54
83
|
# class#role # getter
|
55
84
|
# class#role=(value) # setter
|
56
85
|
#
|
@@ -245,7 +274,7 @@ module BuilderExtensions
|
|
245
274
|
#
|
246
275
|
def _build_internal(props1, props2=nil)
|
247
276
|
_add_metamodel_description(props1)
|
248
|
-
if props1.
|
277
|
+
if props1.many?
|
249
278
|
_build_many_methods(props1, props2)
|
250
279
|
else
|
251
280
|
_build_one_methods(props1, props2)
|
@@ -301,15 +330,15 @@ module BuilderExtensions
|
|
301
330
|
oldval = @<%= name %>
|
302
331
|
@<%= name %> = val
|
303
332
|
<% if other_role %>
|
304
|
-
oldval._unregister<%= firstToUpper(other_role) %>(self) unless oldval.nil?
|
305
|
-
val._register<%= firstToUpper(other_role) %>(self) unless val.nil?
|
333
|
+
oldval._unregister<%= firstToUpper(other_role) %>(self) unless oldval.nil? || oldval.is_a?(MMProxy)
|
334
|
+
val._register<%= firstToUpper(other_role) %>(self) unless val.nil? || val.is_a?(MMProxy)
|
306
335
|
<% end %>
|
307
336
|
end
|
308
337
|
alias set<%= firstToUpper(name) %> <%= name %>=
|
309
338
|
|
310
339
|
def _register<%= firstToUpper(name) %>(val)
|
311
340
|
<% if other_role %>
|
312
|
-
@<%= name %>._unregister<%= firstToUpper(other_role) %>(self) unless @<%= name %>.nil?
|
341
|
+
@<%= name %>._unregister<%= firstToUpper(other_role) %>(self) unless @<%= name %>.nil? || @<%= name %>.is_a?(MMProxy)
|
313
342
|
<% end %>
|
314
343
|
@<%= name %> = val
|
315
344
|
end
|
@@ -353,7 +382,7 @@ module BuilderExtensions
|
|
353
382
|
<%= type_check_code("val", props) %>
|
354
383
|
@<%= name %>.push val
|
355
384
|
<% if other_role %>
|
356
|
-
val._register<%= firstToUpper(other_role) %>(self)
|
385
|
+
val._register<%= firstToUpper(other_role) %>(self) unless val.is_a?(MMProxy)
|
357
386
|
<% end %>
|
358
387
|
end
|
359
388
|
|
@@ -363,7 +392,7 @@ module BuilderExtensions
|
|
363
392
|
if e.object_id == val.object_id
|
364
393
|
@<%= name %>.delete_at(i)
|
365
394
|
<% if other_role %>
|
366
|
-
|
395
|
+
val._unregister<%= firstToUpper(other_role) %>(self) unless val.is_a?(MMProxy)
|
367
396
|
<% end %>
|
368
397
|
return
|
369
398
|
end
|
@@ -428,10 +457,10 @@ module BuilderExtensions
|
|
428
457
|
def type_check_code(varname, props)
|
429
458
|
code = ""
|
430
459
|
if props.impl_type.is_a?(Class)
|
431
|
-
code << "unless #{varname}.nil?
|
460
|
+
code << "unless #{varname}.nil? || #{varname}.is_a?(#{props.impl_type}) || #{varname}.is_a?(MMProxy)\n"
|
432
461
|
expected = props.impl_type.to_s
|
433
462
|
elsif props.impl_type.is_a?(RGen::MetamodelBuilder::DataTypes::Enum)
|
434
|
-
code << "unless #{varname}.nil?
|
463
|
+
code << "unless #{varname}.nil? || [#{props.impl_type.literals_as_strings.join(',')}].include?(#{varname})\n"
|
435
464
|
expected = "["+props.impl_type.literals_as_strings.join(',')+"]"
|
436
465
|
else
|
437
466
|
raise StandardError.new("Unkown type "+props.impl_type.to_s)
|
@@ -464,4 +493,4 @@ end
|
|
464
493
|
|
465
494
|
end
|
466
495
|
|
467
|
-
end
|
496
|
+
end
|
@@ -30,10 +30,28 @@ module BuilderRuntime
|
|
30
30
|
send("#{role}=",value)
|
31
31
|
end
|
32
32
|
|
33
|
+
def hasManyMethods(role)
|
34
|
+
respond_to?("add#{firstToUpper(role)}")
|
35
|
+
end
|
36
|
+
|
37
|
+
def setOrAddGeneric(role, value)
|
38
|
+
if hasManyMethods(role)
|
39
|
+
addGeneric(role, value)
|
40
|
+
else
|
41
|
+
setGeneric(role, value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
33
45
|
def getGeneric(role)
|
34
46
|
send("#{role}")
|
35
47
|
end
|
36
48
|
|
49
|
+
def getGenericAsArray(role)
|
50
|
+
result = getGeneric(role)
|
51
|
+
result = [result].compact unless result.is_a?(Array)
|
52
|
+
result
|
53
|
+
end
|
54
|
+
|
37
55
|
def _assignmentTypeError(target, value, expected)
|
38
56
|
text = ""
|
39
57
|
if target
|
@@ -52,4 +70,4 @@ end
|
|
52
70
|
|
53
71
|
end
|
54
72
|
|
55
|
-
end
|
73
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module RGen
|
2
|
+
|
3
|
+
module Serializer
|
4
|
+
|
5
|
+
class JsonSerializer
|
6
|
+
|
7
|
+
def initialize(writer, opts={})
|
8
|
+
@writer = writer
|
9
|
+
@elementIdentifiers = {}
|
10
|
+
@identAttrName = opts[:identAttrName] || "name"
|
11
|
+
@separator = opts[:separator] || "/"
|
12
|
+
@leadingSeparator = opts.has_key?(:leadingSeparator) ? opts[:leadingSeparator] : true
|
13
|
+
@featureFilter = opts[:featureFilter]
|
14
|
+
@identifierProvider = opts[:identifierProvider]
|
15
|
+
end
|
16
|
+
|
17
|
+
def elementIdentifier(element)
|
18
|
+
ident = @identifierProvider && @identifierProvider.call(element)
|
19
|
+
ident || (element.is_a?(RGen::MetamodelBuilder::MMProxy) && element.targetIdentifier) || qualifiedElementName(element)
|
20
|
+
end
|
21
|
+
|
22
|
+
# simple identifier calculation based on qualified names
|
23
|
+
# prerequisits:
|
24
|
+
# * containment relations must be bidirectionsl
|
25
|
+
# * local name stored in single attribute +@identAttrName+ for all classes
|
26
|
+
#
|
27
|
+
def qualifiedElementName(element)
|
28
|
+
return @elementIdentifiers[element] if @elementIdentifiers[element]
|
29
|
+
localIdent = ((element.respond_to?(@identAttrName) && element.getGeneric(@identAttrName)) || "").strip
|
30
|
+
parentRef = element.class.ecore.eAllReferences.select{|r| r.eOpposite && r.eOpposite.containment}.first
|
31
|
+
parent = parentRef && element.getGeneric(parentRef.name)
|
32
|
+
if parent
|
33
|
+
if localIdent.size > 0
|
34
|
+
parentIdent = qualifiedElementName(parent)
|
35
|
+
result = parentIdent + @separator + localIdent
|
36
|
+
else
|
37
|
+
result = qualifiedElementName(parent)
|
38
|
+
end
|
39
|
+
else
|
40
|
+
result = (@leadingSeparator ? @separator : "") + localIdent
|
41
|
+
end
|
42
|
+
@elementIdentifiers[element] = result
|
43
|
+
end
|
44
|
+
|
45
|
+
def serialize(elements)
|
46
|
+
if elements.is_a?(Array)
|
47
|
+
write("[ ")
|
48
|
+
elements.each_with_index do |e, i|
|
49
|
+
serializeElement(e)
|
50
|
+
write(",\n") unless i == elements.size-1
|
51
|
+
end
|
52
|
+
write("]")
|
53
|
+
else
|
54
|
+
serializeElement(elements)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def serializeElement(element, indent="")
|
59
|
+
write(indent + "{ \"_class\": \""+element.class.ecore.name+"\"")
|
60
|
+
element.class.ecore.eAllStructuralFeatures.each do |f|
|
61
|
+
next if f.derived
|
62
|
+
value = element.getGeneric(f.name)
|
63
|
+
unless value == [] || value.nil? ||
|
64
|
+
(f.is_a?(RGen::ECore::EReference) && f.eOpposite && f.eOpposite.containment) ||
|
65
|
+
(@featureFilter && !@featureFilter.call(f))
|
66
|
+
write(", ")
|
67
|
+
writeFeature(f, value, indent)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
write(" }")
|
71
|
+
end
|
72
|
+
|
73
|
+
def writeFeature(feat, value, indent)
|
74
|
+
write("\""+feat.name+"\": ")
|
75
|
+
if feat.is_a?(RGen::ECore::EAttribute)
|
76
|
+
if value.is_a?(Array)
|
77
|
+
write("[ "+value.collect{|v| attributeValue(v, feat)}.join(", ")+" ]")
|
78
|
+
else
|
79
|
+
write(attributeValue(value, feat))
|
80
|
+
end
|
81
|
+
elsif !feat.containment
|
82
|
+
if value.is_a?(Array)
|
83
|
+
write("[ "+value.collect{|v| "\""+elementIdentifier(v)+"\""}.join(", ")+" ]")
|
84
|
+
else
|
85
|
+
write("\""+elementIdentifier(value)+"\"")
|
86
|
+
end
|
87
|
+
else
|
88
|
+
if value.is_a?(Array)
|
89
|
+
write("[ \n")
|
90
|
+
value.each_with_index do |v, i|
|
91
|
+
serializeElement(v, indent+" ")
|
92
|
+
write(",\n") unless i == value.size-1
|
93
|
+
end
|
94
|
+
write("]")
|
95
|
+
else
|
96
|
+
write("\n")
|
97
|
+
serializeElement(value, indent+" ")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def attributeValue(value, a)
|
103
|
+
if a.eType == RGen::ECore::EString || a.eType.is_a?(RGen::ECore::EEnum)
|
104
|
+
"\""+value.to_s.gsub('"','\\"').gsub('\\','\\\\')+"\""
|
105
|
+
else
|
106
|
+
value.to_s
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def write(s)
|
113
|
+
@writer.write(s)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|