sdl4r 0.9.9 → 0.9.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/CHANGELOG +70 -1
  2. data/LICENSE +499 -497
  3. data/Rakefile +38 -28
  4. data/TODO +194 -45
  5. data/doc/classes/SDL4R/AbbreviationTimezoneProxy.html +151 -0
  6. data/doc/classes/SDL4R/ConstantTimezone.html +129 -0
  7. data/doc/classes/SDL4R/Element.html +148 -0
  8. data/doc/classes/SDL4R/Reader.html +683 -0
  9. data/doc/classes/SDL4R/RelativeTimezone.html +187 -0
  10. data/doc/classes/SDL4R/SdlBinary.html +188 -0
  11. data/doc/classes/SDL4R/SdlParseError.html +110 -0
  12. data/doc/classes/SDL4R/SdlTimeSpan.html +651 -0
  13. data/doc/classes/SDL4R/Serializer.html +557 -0
  14. data/doc/classes/SDL4R/Serializer/Ref.html +138 -0
  15. data/doc/classes/SDL4R/TZAbbreviationDB/Record.html +117 -0
  16. data/doc/classes/SDL4R/Tag.html +1274 -0
  17. data/doc/classes/SDL4R/Token.html +131 -0
  18. data/doc/created.rid +1 -0
  19. data/doc/files/CHANGELOG.html +290 -0
  20. data/doc/files/LICENSE.html +53 -0
  21. data/doc/files/README.html +405 -0
  22. data/doc/files/lib/sdl4r/abbreviation_timezone_proxy_rb.html +63 -0
  23. data/doc/files/lib/sdl4r/constant_timezone_rb.html +54 -0
  24. data/doc/files/lib/sdl4r/element_rb.html +54 -0
  25. data/doc/files/lib/sdl4r/reader_rb.html +68 -0
  26. data/doc/files/lib/sdl4r/relative_timezone_rb.html +62 -0
  27. data/doc/files/lib/sdl4r/sdl4r_rb.html +66 -0
  28. data/doc/files/lib/sdl4r/sdl4r_tzinfo_rb.html +64 -0
  29. data/doc/files/lib/sdl4r/sdl4r_version_rb.html +54 -0
  30. data/doc/files/lib/sdl4r/sdl_binary_rb.html +54 -0
  31. data/doc/files/lib/sdl4r/sdl_parse_error_rb.html +54 -0
  32. data/doc/files/lib/sdl4r/sdl_time_span_rb.html +54 -0
  33. data/doc/files/lib/sdl4r/serializer_rb.html +62 -0
  34. data/doc/files/lib/sdl4r/tag_rb.html +66 -0
  35. data/doc/files/lib/sdl4r/token_rb.html +54 -0
  36. data/doc/files/lib/sdl4r/tokenizer_rb.html +64 -0
  37. data/doc/files/lib/sdl4r/tz_abbreviation_db_rb.html +67 -0
  38. data/doc/files/lib/sdl4r_rb.html +54 -0
  39. data/doc/files/lib/sdl4r_tzinfo_rb.html +54 -0
  40. data/doc/fr_class_index.html +23 -0
  41. data/doc/fr_file_index.html +40 -0
  42. data/doc/fr_method_index.html +4711 -0
  43. data/doc/index.html +15 -0
  44. data/doc/rdoc-style.css +328 -0
  45. data/lib/sdl4r.rb +3 -1
  46. data/lib/sdl4r/abbreviation_timezone_proxy.rb +38 -0
  47. data/lib/sdl4r/constant_timezone.rb +58 -0
  48. data/{test/sdl4r/sdl_test.rb → lib/sdl4r/element.rb} +19 -14
  49. data/lib/sdl4r/reader.rb +772 -0
  50. data/lib/sdl4r/relative_timezone.rb +156 -0
  51. data/lib/sdl4r/sdl4r.rb +187 -45
  52. data/lib/sdl4r/sdl4r_tzinfo.rb +75 -0
  53. data/lib/sdl4r/sdl4r_version.rb +24 -0
  54. data/lib/sdl4r/sdl_parse_error.rb +1 -1
  55. data/lib/sdl4r/sdl_time_span.rb +5 -1
  56. data/lib/sdl4r/serializer.rb +473 -60
  57. data/lib/sdl4r/tag.rb +126 -51
  58. data/lib/sdl4r/token.rb +49 -0
  59. data/lib/sdl4r/tokenizer.rb +431 -0
  60. data/lib/sdl4r/tz_abbreviation_db.rb +266 -0
  61. data/read_jprof.html +16934 -0
  62. data/read_jprof_pull.html +14451 -0
  63. data/read_prof.html +4983 -0
  64. data/read_prof_pull.html +4896 -0
  65. data/test/sdl4r/parser_test.rb +577 -503
  66. data/test/sdl4r/read_jprof.rb +58 -0
  67. data/test/sdl4r/read_prof.rb +70 -0
  68. data/test/sdl4r/reader_test.rb +173 -0
  69. data/test/sdl4r/relative_timezone_test.rb +102 -0
  70. data/test/sdl4r/sdl4r_test.rb +611 -528
  71. data/test/sdl4r/sdl4r_tzinfo_test.rb +108 -0
  72. data/test/sdl4r/sdl_test_case.rb +60 -0
  73. data/test/sdl4r/serializer_test.rb +448 -11
  74. data/test/sdl4r/tag_test.rb +84 -5
  75. data/test/sdl4r/tokenizer_test.rb +128 -0
  76. metadata +69 -11
  77. data/lib/sdl4r/parser.rb +0 -648
  78. data/lib/sdl4r/parser/reader.rb +0 -184
  79. data/lib/sdl4r/parser/time_span_with_zone.rb +0 -57
  80. data/lib/sdl4r/parser/token.rb +0 -138
  81. data/lib/sdl4r/parser/tokenizer.rb +0 -507
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+
4
+ #--
5
+ # Simple Declarative Language (SDL) for Ruby
6
+ # Copyright 2005 Ikayzo, inc.
7
+ #
8
+ # This program is free software. You can distribute or modify it under the
9
+ # terms of the GNU Lesser General Public License version 2.1 as published by
10
+ # the Free Software Foundation.
11
+ #
12
+ # This program is distributed AS IS and WITHOUT WARRANTY. OF ANY KIND,
13
+ # INCLUDING MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
14
+ # See the GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with this program; if not, contact the Free Software Foundation, Inc.,
18
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
+ #++
20
+
21
+ require 'date'
22
+
23
+ require 'sdl4r/sdl4r'
24
+ require 'sdl4r/relative_timezone'
25
+
26
+ # Modification of SDL4R in order to use TZInfo for parsing time zones.
27
+ #
28
+ class << SDL4R
29
+
30
+ alias_method :tzinfo_orig_new_time, :new_time
31
+
32
+ # Creates and returns the object representing a time (DateTime by default).
33
+ # This method is called by the Parser class.
34
+ #
35
+ # This implementation uses TZInfo in order to parse timezones (wider support of timezones and
36
+ # better support of DST and such issues).
37
+ #
38
+ # See #use_datetime=
39
+ #
40
+ def tzinfo_replac_new_time(year, month, day, hour, min, sec, msec, timezone_code)
41
+ if timezone_code
42
+ timezone = SDL4R::RelativeTimezone::get(timezone_code)
43
+ tz_ref_time = Time.utc(year, month, day, hour, min, sec, msec * 1000)
44
+ # Arbitrary decision: in ambiguous cases, we choose the not-DST offset.
45
+ timezone_period = timezone.period_for_local(tz_ref_time, false)
46
+ end
47
+
48
+ if use_datetime?
49
+ sec_msec = (msec == 0)? sec : Rational(sec * 1000 + msec, 1000)
50
+ timezone_offset = timezone_code ?
51
+ timezone_period.utc_total_offset_rational :
52
+ Rational(Time.now.utc_offset, SECONDS_IN_DAY)
53
+ return DateTime.civil(year, month, day, hour, min, sec_msec, timezone_offset)
54
+
55
+ else
56
+ return timezone_code ?
57
+ timezone_period.to_utc(Time.utc(year, month, day, hour, min, sec, msec * 1000)) :
58
+ Time.local(year, month, day, hour, min, sec, msec * 1000)
59
+ end
60
+ end
61
+
62
+ def enable_tzinfo
63
+ class << self
64
+ undef_method :new_time if respond_to? :new_time
65
+ define_method(:new_time, instance_method(:tzinfo_replac_new_time))
66
+ end
67
+ end
68
+
69
+ def disable_tzinfo
70
+ class << self
71
+ undef_method :new_time
72
+ define_method(:new_time, instance_method(:tzinfo_orig_new_time))
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+
4
+ #--
5
+ # Simple Declarative Language (SDL) for Ruby
6
+ # Copyright 2005 Ikayzo, inc.
7
+ #
8
+ # This program is free software. You can distribute or modify it under the
9
+ # terms of the GNU Lesser General Public License version 2.1 as published by
10
+ # the Free Software Foundation.
11
+ #
12
+ # This program is distributed AS IS and WITHOUT WARRANTY. OF ANY KIND,
13
+ # INCLUDING MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
14
+ # See the GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with this program; if not, contact the Free Software Foundation, Inc.,
18
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
+ #++
20
+
21
+ module SDL4R
22
+ # Version of the SDL library.
23
+ VERSION = "0.9.11"
24
+ end
@@ -36,7 +36,7 @@ module SDL4R
36
36
  def initialize(description, line_no, position, line = nil)
37
37
  super(
38
38
  "#{description} Line " + ((line_no.nil? or line_no < 0)? "unknown" : line_no.to_s) +
39
- ", Position " + ((position.nil? or position < 0)? "unknown" : position.to_s) + $/ +
39
+ ", Position " + ((position.nil? or position < 0)? "unknown" : position.to_s) + "\n" +
40
40
  ((line and position >= 0)? line + (position ? " " * (position - 1) : "") + "^" : ""))
41
41
 
42
42
  @line = line_no
@@ -129,7 +129,11 @@ module SDL4R
129
129
  (minutes * MILLISECONDS_IN_MINUTE) -
130
130
  (seconds * MILLISECONDS_IN_SECOND)
131
131
  end
132
- alias_method :usec, :milliseconds
132
+ alias_method :msec, :milliseconds
133
+
134
+ def usec
135
+ milliseconds * 1000
136
+ end
133
137
 
134
138
  # Get the total number of hours in this time span. For example, if
135
139
  # this time span represents two days, this method will return 48.
@@ -23,129 +23,542 @@ module SDL4R
23
23
 
24
24
  require 'ostruct'
25
25
 
26
- require File.dirname(__FILE__) + '/sdl4r'
27
- require File.dirname(__FILE__) + '/tag'
28
-
29
- # Allows to serialize/deserialize between SDL and Ruby Objects.
26
+ # Allows to serialize/deserialize between SDL and Ruby objects.
27
+ #
28
+ # Classes which need to implement custom serialization/deserialization should define the
29
+ # +to_sdl()+ and +from_sdl()+ methods as follows:
30
+ #
31
+ # class MyClass
32
+ #
33
+ # attr_accessor :firstname
34
+ #
35
+ # def from_sdl(tag, serializer = Serializer.new)
36
+ # self.firstname = tag.attribute("name")
37
+ # self
38
+ # end
30
39
  #
31
- # == Authors
40
+ # def to_sdl(serializer = Serializer.new, tag = serializer.new_tag(nil, self, nil))
41
+ # tag.set_attribute("name", self.firstname)
42
+ # tag
43
+ # end
44
+ #
45
+ # end
46
+ #
47
+ # Custom serialization (using +to_sdl()+) or deserialization (using +from_sdl()+) can be more
48
+ # efficient than the standard one as its logic is more straightforward).
49
+ #
50
+ # == Author
32
51
  # Philippe Vosges
33
52
  #
34
53
  class Serializer
35
54
 
36
- def serialize(o, tag = Tag.new(SDL4R::ROOT_TAG_NAME))
55
+ OBJECT_ID_ATTR_NAME = 'oid'
56
+ OBJECT_REF_ATTR_NAME = 'oref'
57
+
58
+ @@DEFAULT_OPTIONS = {
59
+ :omit_nil_properties => false,
60
+ :default_namespace => ""
61
+ }
62
+
63
+ #
64
+ #
65
+ # === options:
66
+ #
67
+ # [:omit_nil_properties]
68
+ # if true, nil object properties are not exported to the serialized SDL (default: false)
69
+ # [:default_namespace]
70
+ # the default namespace of the generated tags (default: ""). This namespace doesn't apply to
71
+ # attributes.
72
+ #
73
+ def initialize(options = {})
74
+ @options = {}.merge(@@DEFAULT_OPTIONS).merge!(options)
75
+ @next_oid = 1
76
+ @ref_by_oid = {}
77
+ @ref_by_object = {}
78
+ end
79
+
80
+ # Represents a reference to an object during serialization or deserialization.
81
+ # Used in order to avoid infinite cycles, repetitions, etc.
82
+ #
83
+ class Ref
84
+ attr_reader :o, :oid, :count
85
+ attr_accessor :tag
86
+
87
+ # Initializes a reference with a reference counter of 0.
88
+ #
89
+ def initialize(o, oid)
90
+ @tag = nil
91
+ @o = o
92
+ @oid = oid
93
+ @count = 0
94
+ end
95
+
96
+ # Increments the reference counter by one.
97
+ #
98
+ def inc
99
+ @count += 1
100
+ end
101
+ end
102
+
103
+ # References the provided object if it is not already referenced. If the object is referenced
104
+ # already, returns the corresponding Ref. The reference counter is not incremented by this
105
+ # method.
106
+ #
107
+ # _oid_:: the Object ID (ignore if serializing, provide if deserializing).
108
+ #
109
+ def reference_object(o, oid = nil)
110
+ ref = @ref_by_object[o]
111
+
112
+ unless ref
113
+ unless oid
114
+ oid = @next_oid
115
+ @next_oid += 1
116
+ end
117
+
118
+ ref = Ref.new(o, oid)
119
+ @ref_by_oid[oid] = @ref_by_object[o] = ref
120
+ end
121
+
122
+ ref
123
+ end
124
+
125
+ # Returns a new Tag to be used for serializing 'o'.
126
+ #
127
+ # _name_:: name of the Tag to create (can be +nil+ for a root Tag)
128
+ # _o_:: object/value that the new tag will represent
129
+ # _parent_tag_:: parent Tag of the new tag
130
+ #
131
+ def new_tag(name, o, parent_tag = nil)
132
+ if name
133
+ namespace = @options[:default_namespace]
134
+ else
135
+ namespace = ''
136
+ name = SDL4R::ROOT_TAG_NAME
137
+ end
138
+
139
+ if parent_tag.nil?
140
+ Tag.new(namespace, name)
141
+ else
142
+ parent_tag.new_child(namespace, name)
143
+ end
144
+ end
145
+
146
+ # Returns a Tag representing the provided Ref.
147
+ #
148
+ # _name_:: name of the created Tag (if +nil+, the definition Tag name - i.e. the name of the
149
+ # first Tag representing the referenced object - is used)
150
+ # _ref_:: represented reference (Ref)
151
+ # _parent_tag_:: parent Tag of the created Tag
152
+ #
153
+ def new_ref_tag(name, ref, parent_tag)
154
+ name = ref.tag.name if name.nil?
155
+
156
+ ref_tag = parent_tag.new_child(@options[:default_namespace], name)
157
+ ref_tag.set_attribute('', OBJECT_REF_ATTR_NAME, ref.oid)
158
+ ref_tag
159
+ end
160
+
161
+ # Serializes the given object into a returned Tag.
162
+ #
163
+ # _tag_:: a Tag representing 'o' (if not provided, one will be created).
164
+ #
165
+ def serialize(o, tag = nil, parent_tag = nil)
166
+ root = serialize_impl(o, tag, parent_tag)
167
+
168
+ # Assign an OID attribute to tags of objects referenced more than once
169
+ @ref_by_object.each_value { |ref|
170
+ if ref.count > 1
171
+ ref.tag.set_attribute('', OBJECT_ID_ATTR_NAME, ref.oid)
172
+ end
173
+ }
174
+
175
+ root
176
+ end
177
+
178
+ # Serializes 'o' into a Tag, which is then returned.
179
+ # Dislike #serialize this method doesn't perform any final operation like assigning object ids
180
+ # attributes to the Tags that represent serialized objects.
181
+ #
182
+ # _tag_:: a tag to be used as the serialized form of 'o'.
183
+ # Note that this parameter will be ignored if the +to_sdl()+ is called on the serialized
184
+ # object.
185
+ #
186
+ def serialize_impl(o, tag = nil, parent_tag = nil)
187
+ tag = new_tag(nil, o, parent_tag) if tag.nil?
37
188
  raise ArgumentError, '"tag" must be a Tag' unless tag.is_a?(Tag)
38
-
39
- o = o.marshal_dump if o.is_a? OpenStruct
40
189
 
41
- if o.is_a? Hash
42
- o.each_pair { |key, value|
43
- serialize_variable(key.to_s, value, tag)
44
- }
190
+ if o.respond_to? :to_sdl
191
+ tag = o.to_sdl(self, tag)
45
192
 
46
193
  else
47
- o.instance_variables.each { |name|
48
- value = o.instance_variable_get(name)
49
- name = name[1..name.size] if name =~ /^@/
50
- serialize_variable(name, value, tag)
51
- }
194
+ tag = case o
195
+ when OpenStruct
196
+ serialize_hash(o.marshal_dump, tag)
197
+
198
+ when Hash
199
+ serialize_hash(o, tag)
200
+
201
+ else
202
+ serialize_plain_object(o, tag)
203
+ end
52
204
  end
53
205
 
54
206
  tag
55
207
  end
56
208
 
57
- def deserialize(tag, o = OpenStruct.new)
58
- is_open_struct_or_hash = o.is_a?(OpenStruct) or o.is_a?(Hash)
209
+ private :serialize_impl
210
+
211
+ def serialize_hash(hash, tag)
212
+ hash.each_pair { |key, value|
213
+ serialize_property(key.to_s, value, tag)
214
+ }
215
+ tag
216
+ end
217
+
218
+ def serialize_plain_object(o, tag)
219
+ processed_properties = {}
220
+
221
+ # Read+write attributes are used rather than variables
222
+ o.methods.each { |name|
223
+ if name =~ /\w/ and # check this is not an operator
224
+ name =~ /^([^=]+)=$/ # check setter name pattern
225
+ if get_method(o, name, 1)
226
+ getter_name = $1
227
+ getter = get_method(o, getter_name, 0)
228
+
229
+ if getter
230
+ # read and write accessors are defined
231
+ value = getter.call
232
+ serialize_property(getter_name, value, tag)
233
+ processed_properties[getter_name] = true
234
+ end
235
+ end
236
+ end
237
+ }
238
+
239
+ # Otherwise, we read instance variables
240
+ o.instance_variables.each { |variable_name|
241
+ name = variable_name[1..variable_name.size] if variable_name =~ /^@/
242
+ unless processed_properties.has_key?(name)
243
+ value = o.instance_variable_get(variable_name)
244
+ serialize_property(name, value, tag)
245
+ end
246
+ }
247
+
248
+ tag
249
+ end
250
+
251
+ # Returns the method of object 'o', which has the specified name and arity (with or without
252
+ # default parameters). Returns nil if no such method corresponds.
253
+ #
254
+ def get_method(o, method_name, arity)
255
+ begin
256
+ m = o.method(method_name)
257
+ rescue NameError
258
+ m = nil
259
+ end
59
260
 
60
- # TODO Deserialization from anonymous child tags
261
+ unless m.nil? or m.arity == arity or m.arity == (-arity - 1)
262
+ m = nil
263
+ end
264
+
265
+ return m
266
+ end
267
+
268
+ # Indicates whether the specified property is a serializable property for the given object.
269
+ #
270
+ def serializable_property?(o, property_name)
271
+ return o.is_a?(OpenStruct) ||
272
+ o.is_a?(Hash) ||
273
+ o.instance_variable_defined?("@#{property_name}") ||
274
+ (get_method(o, property_name, 0) and get_method(o, "#{property_name}=", 1))
275
+ end
276
+
277
+ # Serializes a property under a given Tag.
278
+ # Ignores any property whose name is not a valid SDL name.
279
+ #
280
+ # _name_:: property name
281
+ # _value_:: property value (SDL value, plain object or Array)
282
+ #
283
+ def serialize_property(name, value, parent_tag)
284
+ return unless SDL4R::valid_identifier?(name)
61
285
 
62
- # Deserialization from values
286
+ if value.is_a? Array
287
+ serialize_array(name, value, parent_tag)
288
+
289
+ elsif SDL4R::is_coercible?(value)
290
+ # SDL literal type
291
+ unless value.nil? and @options[:omit_nil_properties]
292
+ if parent_tag.name == SDL4R::ROOT_TAG_NAME
293
+ value_tag = new_tag(name, value, parent_tag)
294
+ value_tag.values = [value]
295
+ else
296
+ parent_tag.set_attribute(name, value)
297
+ end
298
+ end
299
+
300
+ else
301
+ serialize_object_or_ref(name, value, parent_tag)
302
+ end
303
+ end
304
+
305
+ def serialize_array(name, array, parent_tag)
306
+ not_literal_values = array.reject { |item| SDL4R::is_coercible?(item) }
307
+ if not_literal_values.empty?
308
+ # If it is an array of SDL-compatible values, we use SDL values.
309
+ array_tag = new_tag(name, array, parent_tag)
310
+ array_tag.values = array
311
+
312
+ else
313
+ # Otherwise, we use separate child tags.
314
+ serialize_array_as_child_tags(name, array, parent_tag)
315
+ end
316
+ end
317
+
318
+ def serialize_array_as_child_tags(name, array, parent_tag)
319
+ array.each { |item|
320
+ if SDL4R::is_coercible?(item)
321
+ value_tag = new_tag(name, item, parent_tag)
322
+ value_tag.values = [item]
323
+ else
324
+ serialize_object_or_ref(name, item, parent_tag)
325
+ end
326
+ }
327
+ end
328
+
329
+ # Serializes an object (possibly using a reference).
330
+ #
331
+ # _name_:: name used for the object in the parent Tag
332
+ #
333
+ def serialize_object_or_ref(name, value, parent_tag)
334
+ ref = reference_object(value)
335
+ ref.inc
336
+
337
+ if ref.count == 1
338
+ ref.tag = new_tag(name, value, parent_tag)
339
+ serialize_impl(value, ref.tag)
340
+ else
341
+ new_ref_tag(name, ref, parent_tag)
342
+ end
343
+ end
344
+
345
+ public
346
+
347
+ # Provides deserialized new plain object instances (i.e. "plain object" as opposed to special
348
+ # cases like SDL values).
349
+ # By default, returns 'o' or a new instance of OpenStruct if 'o' is +nil+.
350
+ #
351
+ # _tag_:: the deserialized Tag
352
+ # _o_:: the currently used object or nil if there is none yet
353
+ # _parent_object_:: the parent object or +nil+ if root
354
+ #
355
+ def new_plain_object(tag, o = nil, parent_object = nil)
356
+ if o.nil?
357
+ OpenStruct.new
358
+ else
359
+ o
360
+ end
361
+ end
362
+
363
+ def deserialize(tag, o = new_plain_object(tag))
364
+ if o.respond_to? :from_sdl
365
+ o = o.from_sdl(tag, self)
366
+
367
+ else
368
+ o = deserialize_object(tag, o)
369
+ end
370
+
371
+ o
372
+ end
373
+
374
+ # Called by #deserialize when not using +from_sdl()+.
375
+ # Deserializes the specified tag into an object using values, attributes, child tags, etc.
376
+ #
377
+ def deserialize_object(tag, o = new_plain_object(tag))
378
+ deserialize_from_child_tags(tag, o, true)
379
+ deserialize_from_values(tag, o)
380
+ deserialize_from_attributes(tag, o)
381
+ deserialize_from_child_tags(tag, o, false)
382
+
383
+ o = apply_anonymous_tag_list_idiom(tag, o)
384
+
385
+ o
386
+ end
387
+
388
+ def deserialize_from_values(tag, o)
63
389
  if tag.has_values?
64
390
  if tag.has_children? or tag.has_attributes?
65
- variable_value = tag.values
391
+ property_value = tag.values
66
392
 
67
393
  if o.instance_variable_defined?("@value") or not o.instance_variable_defined?("@values")
68
394
  # value is preferred
69
- variable_name = "value"
70
- variable_value = variable_value[0] if variable_value.length == 1
395
+ property_name = "value"
396
+ property_value = property_value[0] if property_value.length == 1
71
397
  else
72
- variable_name = "values"
398
+ property_name = "values"
73
399
  end
74
400
 
75
- if is_open_struct_or_hash or o.instance_variable_defined?(variable_name)
76
- set_object_variable(o, variable_name, variable_value)
401
+ if serializable_property?(o, property_name)
402
+ set_serializable_property(o, property_name, property_value)
77
403
  end
78
404
 
79
405
  else
80
406
  # the tag only has values
81
- return variable_value.length == 1 ? variable_value[0] : variable_value
407
+ return property_value.length == 1 ? property_value[0] : property_value
82
408
  end
83
409
  end
410
+ end
84
411
 
85
- # Deserialization from attributes
412
+ def deserialize_from_attributes(tag, o)
86
413
  tag.attributes do |attribute_namespace, attribute_name, attribute_value|
87
- if is_open_struct_or_hash or o.instance_variable_defined?("@#{attribute_name}")
88
- set_object_variable(o, attribute_name, attribute_value)
414
+ if attribute_namespace == '' and attribute_name == OBJECT_REF_ATTR_NAME
415
+ # ignore this technical attribute
416
+
417
+ elsif attribute_namespace == '' and attribute_name == OBJECT_ID_ATTR_NAME
418
+ # reference and make no impact on 'o'
419
+ ref = reference_object(o, attribute_value)
420
+ ref.inc
421
+
422
+ else
423
+ set_serializable_property(o, attribute_name, attribute_value)
89
424
  end
90
425
  end
426
+ end
427
+
428
+ # Returns the name of the property to which the specified Tag is supposed to be assigned in the
429
+ # parent object.
430
+ # Default behavior: this implementation returns the tag's name (ignoring the namespace).
431
+ #
432
+ def get_deserialized_property_name(tag, parent_tag, parent_object)
433
+ tag.name
434
+ end
91
435
 
92
- # Deserialization from (not anonymous) child tags
436
+ # _handle_anonymous_::
437
+ # if true, this method only handles anonymous child tags,
438
+ # if false, it only handles named child tags
439
+ #
440
+ def deserialize_from_child_tags(tag, o, handle_anonymous)
441
+ # Group the homonym tags together
442
+ child_tags_by_name = {}
93
443
  tag.children do |child|
94
- # if child.namespace != '' or child.name != SDL4R::ANONYMOUS_TAG_NAME
95
- variable_name = "@#{child.name}"
444
+ if handle_anonymous == (child.namespace == '' and child.name == SDL4R::ANONYMOUS_TAG_NAME)
445
+ property_name = get_deserialized_property_name(child, tag, o)
446
+ homonymous_children = (child_tags_by_name[property_name] ||= [])
447
+ homonymous_children << child
448
+ end
449
+ end
450
+
451
+ child_tags_by_name.each_pair do |property_name, homonymous_children|
452
+ # Check wether this variable is assignable
453
+ if o.is_a? Array or serializable_property?(o, property_name)
454
+ property_values = []
96
455
 
97
- # Check wether this variable is assignable
98
- if is_open_struct_or_hash or o.instance_variable_defined?(variable_name)
99
- variable_value = nil
456
+ homonymous_children.each do |child|
457
+ property_value = nil
100
458
 
101
- if child.has_values? and not child.has_children? and not child.has_attributes?
459
+ if child.has_attribute?(OBJECT_REF_ATTR_NAME)
460
+ # Object reference
461
+ ref = @ref_by_oid[child.attribute(OBJECT_REF_ATTR_NAME)]
462
+ property_value = deserialize(child, ref.o) if ref
463
+
464
+ elsif child.has_values? and not child.has_children? and not child.has_attributes?
102
465
  # If the object only has values (no children, no atttributes):
103
466
  # then the values are the variable value
104
- variable_value = child.values
105
- variable_value = variable_value[0] if variable_value.length == 1
467
+ property_value = child.values
468
+ property_value = property_value[0] if property_value.length == 1
106
469
 
107
470
  else
108
- # Consider this tag as an object
109
- previous_value = o.instance_variable_get(variable_name)
110
- if previous_value.nil?
111
- variable_value = deserialize(child)
112
- elsif SDL4R::is_coercible?(previous_value)
113
- variable_value = deserialize(child)
471
+ # Consider this tag as a plain object
472
+ variable_name = "@#{property_name}"
473
+ previous_value =
474
+ (o.instance_variable_defined? variable_name) ?
475
+ o.instance_variable_get(variable_name) :
476
+ nil
477
+ if previous_value.nil? or SDL4R::is_coercible?(previous_value)
478
+ property_value = deserialize(child, new_plain_object(child, nil, o))
114
479
  else
115
- variable_value = deserialize(child, previous_value)
480
+ property_value = deserialize(child, new_plain_object(child, previous_value, o))
116
481
  end
117
482
  end
118
483
 
119
- set_object_variable(o, child.name, variable_value)
484
+ property_values << property_value
120
485
  end
121
- # end
122
- end
123
486
 
124
- return o
487
+ if o.is_a? Array
488
+ o.concat(property_values)
489
+ elsif property_values.length == 1
490
+ set_serializable_property(o, property_name, property_values[0])
491
+ elsif property_values.length > 1
492
+ set_serializable_property(o, property_name, property_values)
493
+ end
494
+ end
495
+ end
125
496
  end
126
497
 
127
498
  private
128
499
 
129
- def serialize_variable(name, value, tag)
130
- if SDL4R::is_coercible?(value)
131
- # SDL litteral type
132
- tag.set_attribute(name, value)
133
- else
134
- # Simple object
135
- serialize(value, tag.new_child(name))
500
+ def apply_anonymous_tag_list_idiom(tag, o)
501
+ if tag.has_child?('', SDL4R::ANONYMOUS_TAG_NAME) and
502
+ not tag.has_attributes? and not tag.has_values?
503
+
504
+ getter = get_method(o, SDL4R::ANONYMOUS_TAG_NAME, 0)
505
+ if getter
506
+ # Check that the tag only has anonymous tags
507
+ anonymous_child_tags = nil
508
+ tag.children do |child|
509
+ if child.namespace == '' and child.name == SDL4R::ANONYMOUS_TAG_NAME
510
+ anonymous_child_tags ||= []
511
+ anonymous_child_tags << child
512
+ else
513
+ anonymous_child_tags = nil
514
+ break
515
+ end
516
+ end
517
+
518
+ if anonymous_child_tags and tag.child_count == anonymous_child_tags.length
519
+ # Only anonymous child tags were found.
520
+ value = getter.call
521
+ return value
522
+ end
523
+ end
136
524
  end
525
+
526
+ return o
137
527
  end
138
528
 
139
- def set_object_variable(o, name, value)
529
+ public
530
+
531
+ # Sets the given property in the given object.
532
+ # Returns whether the property has been assigned or not.
533
+ #
534
+ # This method could be redefined in order to convert a value to a custom one, for instance.
535
+ #
536
+ def set_serializable_property(o, name, value)
140
537
  case o
141
538
  when Hash
142
539
  o[name] = value
540
+ return true
143
541
 
144
542
  when OpenStruct
145
543
  o.send "#{name}=", value
544
+ return true
146
545
 
147
546
  else
148
- o.instance_variable_set("@#{name}", value)
547
+ accessor_name = "#{name}="
548
+ if o.respond_to?(accessor_name)
549
+ o.send accessor_name, value
550
+ return true
551
+
552
+ else
553
+ variable_name = "@#{name}"
554
+ if o.instance_variable_defined?(variable_name)
555
+ o.instance_variable_set(variable_name, value)
556
+ return true
557
+
558
+ else
559
+ return false
560
+ end
561
+ end
149
562
  end
150
563
  end
151
564
  end