rgen 0.5.1 → 0.5.2
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 +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
|
+
|