firm 0.9.7 → 0.9.8
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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/firm/serializer/json.rb +124 -74
- data/lib/firm/serializer/xml.rb +80 -65
- data/lib/firm/version.rb +1 -1
- data/tests/serializer_tests.rb +46 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70fc573f0deb51e97747caf3a36ccfabb8e93a0ff8cb72f0de16e877eeb9713b
|
4
|
+
data.tar.gz: 66811b4933baeaa1e555223fa554292339534a5de8d4de66bbd2fe4d26db1633
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a37bb0eb3d1aaffed3531979640070f7048e899c93206c61f2e9377bf256f923b4c70f19d1cd8bedc486a94b124803e6f7cd2b42419a65c2746e8f19ca1db432
|
7
|
+
data.tar.gz: 8fe43c7d9828632f27c0e12271250c85b06662ffd9969d3feefb4c9e78f653fc993c42361fcb38dc8e719c2c75601e9da603b26c8ee83736b9d3d991750ef963
|
data/README.md
CHANGED
@@ -50,7 +50,7 @@ resolve Class objects from these names if really needed.
|
|
50
50
|
FIRM also supports a simple scheme to provide (de-)serialization support for user defined classes.
|
51
51
|
|
52
52
|
FIRM provides object aliasing support for JSON and XML in a similar fashion as the standard support provided
|
53
|
-
by YAML.
|
53
|
+
by YAML.
|
54
54
|
|
55
55
|
FIRM also automatically recognizes and handles cyclic references of aliasable objects.
|
56
56
|
|
data/lib/firm/serializer/json.rb
CHANGED
@@ -44,15 +44,64 @@ module FIRM
|
|
44
44
|
alias key? include?
|
45
45
|
end
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
47
|
+
module ContainerPatch
|
48
|
+
|
49
|
+
def self.included(base)
|
50
|
+
class << base
|
51
|
+
def json_new(object, &block)
|
52
|
+
# deserializing (anchor) object or alias
|
53
|
+
if object.has_key?('*id')
|
54
|
+
if FIRM::Serializable::Aliasing.restored?(self, object['*id'])
|
55
|
+
# resolving an already restored anchor for this alias
|
56
|
+
FIRM::Serializable::Aliasing.resolve_anchor(self, object['*id'])
|
57
|
+
else
|
58
|
+
# in case of cyclic references JSON will restore aliases before the anchors
|
59
|
+
# so in this case we instantiate an instance here and register it as
|
60
|
+
# the anchor; when the anchor is restored it will replace the contents of this
|
61
|
+
# instance with the restored elements
|
62
|
+
FIRM::Serializable::Aliasing.restore_anchor(object['*id'], self.new)
|
63
|
+
end
|
64
|
+
else
|
65
|
+
instance = if object.has_key?('&id')
|
66
|
+
anchor_id = object['&id'] # extract anchor id
|
67
|
+
if FIRM::Serializable::Aliasing.restored?(self, anchor_id)
|
68
|
+
# in case of cyclic references an alias will already have restored the anchor instance
|
69
|
+
# (default constructed); retrieve that instance here for deserialization of properties
|
70
|
+
FIRM::Serializable::Aliasing.resolve_anchor(self, anchor_id)
|
71
|
+
else
|
72
|
+
# restore the anchor here with a newly instantiated instance
|
73
|
+
FIRM::Serializable::Aliasing.restore_anchor(anchor_id, self.new)
|
74
|
+
end
|
75
|
+
else
|
76
|
+
self.new
|
77
|
+
end
|
78
|
+
block.call(instance)
|
79
|
+
instance
|
80
|
+
end
|
81
|
+
end
|
82
|
+
private :json_new
|
83
|
+
end
|
55
84
|
end
|
85
|
+
|
86
|
+
def build_json(&block)
|
87
|
+
json_data = {
|
88
|
+
::JSON.create_id => self.class.name
|
89
|
+
}
|
90
|
+
if (anchor = FIRM::Serializable::Aliasing.get_anchor(self))
|
91
|
+
anchor_data = FIRM::Serializable::Aliasing.get_anchor_data(self)
|
92
|
+
# retroactively insert the anchor in the anchored instance's serialization data
|
93
|
+
anchor_data['&id'] = anchor unless anchor_data.has_key?('&id')
|
94
|
+
json_data['*id'] = anchor
|
95
|
+
else
|
96
|
+
# register anchor object **before** serializing properties to properly handle cycling (bidirectional
|
97
|
+
# references)
|
98
|
+
FIRM::Serializable::Aliasing.register_anchor_object(self, json_data)
|
99
|
+
block.call(json_data)
|
100
|
+
end
|
101
|
+
json_data
|
102
|
+
end
|
103
|
+
private :build_json
|
104
|
+
|
56
105
|
end
|
57
106
|
|
58
107
|
class << self
|
@@ -131,8 +180,8 @@ module FIRM
|
|
131
180
|
# enable safe deserializing
|
132
181
|
self.start_safe_deserialize
|
133
182
|
::JSON.parse!(source,
|
134
|
-
|
135
|
-
|
183
|
+
create_additions: true,
|
184
|
+
object_class: Serializable::JSON::ObjectHash)
|
136
185
|
ensure
|
137
186
|
# reset safe deserializing
|
138
187
|
self.end_safe_deserialize
|
@@ -279,100 +328,101 @@ class ::Class
|
|
279
328
|
end
|
280
329
|
|
281
330
|
class ::Array
|
331
|
+
include FIRM::Serializable::JSON::ContainerPatch
|
332
|
+
|
333
|
+
class << self
|
334
|
+
# Create a new Array instance from deserialized JSON data.
|
335
|
+
# @param [Hash] object deserialized JSON object
|
336
|
+
# @return [Array] restored Array instance
|
337
|
+
def json_create(object)
|
338
|
+
json_new(object) { |instance| instance.replace(object['data']) }
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
282
342
|
def as_json(*)
|
283
|
-
|
343
|
+
build_json do |json_data|
|
344
|
+
json_data['data'] = collect { |e| e.respond_to?(:as_json) ? e.as_json : e }
|
345
|
+
end
|
284
346
|
end
|
285
347
|
end
|
286
348
|
|
287
349
|
class ::Hash
|
350
|
+
include FIRM::Serializable::JSON::ContainerPatch
|
351
|
+
|
288
352
|
class << self
|
289
|
-
|
353
|
+
# Create a new Hash instance from deserialized JSON data.
|
354
|
+
# @param [Hash] object deserialized JSON object
|
355
|
+
# @return [Hash] restored Hash instance
|
356
|
+
def json_create(object)
|
357
|
+
json_new(object) { |instance| instance.replace(object['data'].to_h) }
|
358
|
+
end
|
290
359
|
end
|
360
|
+
|
291
361
|
def as_json(*)
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
}
|
362
|
+
build_json do |json_data|
|
363
|
+
json_data['data'] = collect { |k,v| [k.respond_to?(:as_json) ? k.as_json : k, v.respond_to?(:as_json) ? v.as_json : v] }
|
364
|
+
end
|
296
365
|
end
|
297
366
|
end
|
298
367
|
|
299
368
|
class ::Set
|
369
|
+
include FIRM::Serializable::JSON::ContainerPatch
|
370
|
+
|
371
|
+
class << self
|
372
|
+
# Create a new Set instance from deserialized JSON data.
|
373
|
+
# @param [Hash] object deserialized JSON object
|
374
|
+
# @return [Set] restored Set instance
|
375
|
+
def json_create(object)
|
376
|
+
json_new(object) { |instance| instance.replace(object['a']) }
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
300
380
|
def as_json(*)
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
}
|
381
|
+
build_json do |json_data|
|
382
|
+
json_data['a'] = to_a.collect { |e| e.respond_to?(:as_json) ? e.as_json : e }
|
383
|
+
end
|
305
384
|
end
|
306
385
|
end
|
307
386
|
|
308
387
|
class ::Struct
|
388
|
+
include FIRM::Serializable::JSON::ContainerPatch
|
389
|
+
|
309
390
|
class << self
|
391
|
+
# Create a new Struct instance from deserialized JSON data.
|
392
|
+
# @param [Hash] object deserialized JSON object
|
393
|
+
# @return [Struct] restored Set instance
|
310
394
|
def json_create(object)
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
# resolving an already restored anchor for this alias
|
315
|
-
FIRM::Serializable::Aliasing.resolve_anchor(self, object['*id'])
|
316
|
-
else
|
317
|
-
# in case of cyclic references JSON will restore aliases before the anchors
|
318
|
-
# so in this case we allocate an instance here and register it as
|
319
|
-
# the anchor; when the anchor is restored it will re-use this instance to restore
|
320
|
-
# the properties
|
321
|
-
FIRM::Serializable::Aliasing.restore_anchor(object['*id'], self.allocate)
|
322
|
-
end
|
323
|
-
else
|
324
|
-
if object.has_key?('&id')
|
325
|
-
anchor_id = object['&id'] # extract anchor id
|
326
|
-
instance = if FIRM::Serializable::Aliasing.restored?(self, anchor_id)
|
327
|
-
# in case of cyclic references an alias will already have restored the anchor instance
|
328
|
-
# (default constructed); retrieve that instance here for deserialization of properties
|
329
|
-
FIRM::Serializable::Aliasing.resolve_anchor(self, anchor_id)
|
330
|
-
else
|
331
|
-
# restore the anchor here with a newly instantiated instance
|
332
|
-
FIRM::Serializable::Aliasing.restore_anchor(anchor_id, self.allocate)
|
333
|
-
end
|
334
|
-
instance.__send__(:initialize, *object['v'])
|
335
|
-
instance
|
336
|
-
else
|
337
|
-
self.new(*object['v'])
|
395
|
+
json_new(object) do |instance|
|
396
|
+
values = object['v']
|
397
|
+
instance.members.each_with_index { |n, i| instance[n] = values[i] }
|
338
398
|
end
|
339
|
-
end
|
340
399
|
end
|
341
400
|
end
|
342
401
|
|
343
402
|
def as_json(*)
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
# JSON.create_id => klass,
|
348
|
-
# 'v' => values.as_json,
|
349
|
-
# }
|
350
|
-
json_data = {
|
351
|
-
::JSON.create_id => klass
|
352
|
-
}
|
353
|
-
if (anchor = FIRM::Serializable::Aliasing.get_anchor(self))
|
354
|
-
anchor_data = FIRM::Serializable::Aliasing.get_anchor_data(self)
|
355
|
-
# retroactively insert the anchor in the anchored instance's serialization data
|
356
|
-
anchor_data['&id'] = anchor unless anchor_data.has_key?('&id')
|
357
|
-
json_data['*id'] = anchor
|
358
|
-
else
|
359
|
-
# register anchor object **before** serializing properties to properly handle cycling (bidirectional
|
360
|
-
# references)
|
361
|
-
FIRM::Serializable::Aliasing.register_anchor_object(self, json_data)
|
362
|
-
json_data['v'] = values.as_json
|
403
|
+
self.class.name.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!"
|
404
|
+
build_json do |json_data|
|
405
|
+
json_data['v'] = values.collect { |e| e.respond_to?(:as_json) ? e.as_json : e }
|
363
406
|
end
|
364
|
-
json_data
|
365
407
|
end
|
366
408
|
end
|
367
409
|
|
368
410
|
class ::OpenStruct
|
411
|
+
include FIRM::Serializable::JSON::ContainerPatch
|
412
|
+
|
413
|
+
class << self
|
414
|
+
# Create a new OpenStruct instance from deserialized JSON data.
|
415
|
+
# @param [Hash] object deserialized JSON object
|
416
|
+
# @return [OpenStruct] restored OpenStruct instance
|
417
|
+
def json_create(object)
|
418
|
+
json_new(object) { |instance| object['t'].each { |k,v| instance[k] = v } }
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
369
422
|
def as_json(*)
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
JSON.create_id => klass,
|
374
|
-
't' => table.as_json,
|
375
|
-
}
|
423
|
+
build_json do |json_data|
|
424
|
+
json_data['t'] = table.collect { |k,v| [k.respond_to?(:as_json) ? k.as_json : k, v.respond_to?(:as_json) ? v.as_json : v] }
|
425
|
+
end
|
376
426
|
end
|
377
427
|
end
|
378
428
|
|
data/lib/firm/serializer/xml.rb
CHANGED
@@ -56,6 +56,7 @@ module FIRM
|
|
56
56
|
def create_type_node(xml)
|
57
57
|
xml.add_child(Nokogiri::XML::Node.new(tag.to_s, xml.document))
|
58
58
|
end
|
59
|
+
private :create_type_node
|
59
60
|
def to_xml(_, _)
|
60
61
|
raise Serializable::Exception, "Missing serialization method for #{klass} XML handler"
|
61
62
|
end
|
@@ -65,6 +66,42 @@ module FIRM
|
|
65
66
|
end
|
66
67
|
private_constant :HandlerMethods
|
67
68
|
|
69
|
+
module AliasableHandler
|
70
|
+
def build_xml(xml, value, &block)
|
71
|
+
node = create_type_node(xml)
|
72
|
+
node['class'] = value.class.name
|
73
|
+
if (anchor = Serializable::Aliasing.get_anchor(value))
|
74
|
+
anchor_data = Serializable::Aliasing.get_anchor_data(value)
|
75
|
+
# retroactively insert the anchor in the anchored instance's serialization data
|
76
|
+
anchor_data['anchor'] = anchor unless anchor_data.has_attribute?('anchor')
|
77
|
+
node['alias'] = "#{anchor}"
|
78
|
+
else
|
79
|
+
# register anchor object **before** serializing properties to properly handle cycling (bidirectional
|
80
|
+
# references)
|
81
|
+
Serializable::Aliasing.register_anchor_object(value, node)
|
82
|
+
block.call(node)
|
83
|
+
end
|
84
|
+
xml
|
85
|
+
end
|
86
|
+
private :build_xml
|
87
|
+
def create_from_xml(xml, &block)
|
88
|
+
klass = ::Object.const_get(xml['class'])
|
89
|
+
if xml.has_attribute?('alias')
|
90
|
+
# deserializing alias
|
91
|
+
Serializable::Aliasing.resolve_anchor(klass, xml['alias'].to_i)
|
92
|
+
else
|
93
|
+
instance = klass.new
|
94
|
+
# in case this is an anchor restore the anchor instance before restoring the member values
|
95
|
+
# and afterwards initialize the instance with the restored member values
|
96
|
+
Serializable::Aliasing.restore_anchor(xml['anchor'].to_i, instance) if xml.has_attribute?('anchor')
|
97
|
+
block.call(instance)
|
98
|
+
instance
|
99
|
+
end
|
100
|
+
end
|
101
|
+
private :create_from_xml
|
102
|
+
end
|
103
|
+
private_constant :AliasableHandler
|
104
|
+
|
68
105
|
def xml_handlers
|
69
106
|
@xml_handlers ||= {}
|
70
107
|
end
|
@@ -86,9 +123,10 @@ module FIRM
|
|
86
123
|
end
|
87
124
|
private :get_xml_handler
|
88
125
|
|
89
|
-
def define_xml_handler(klass, tag=nil, &block)
|
126
|
+
def define_xml_handler(klass, tag=nil, aliasable: false, &block)
|
90
127
|
hnd_klass = Class.new
|
91
128
|
hnd_klass.singleton_class.include(HandlerMethods)
|
129
|
+
hnd_klass.singleton_class.include(AliasableHandler) if aliasable
|
92
130
|
tag_code = if tag
|
93
131
|
::Symbol === tag ? ":#{tag}" : "'#{tag.to_s}'"
|
94
132
|
else
|
@@ -179,16 +217,14 @@ module FIRM
|
|
179
217
|
end
|
180
218
|
end
|
181
219
|
|
182
|
-
define_xml_handler(::Array) do
|
220
|
+
define_xml_handler(::Array, aliasable: true) do
|
183
221
|
def to_xml(xml, value)
|
184
|
-
node
|
185
|
-
value.each do |v|
|
186
|
-
Serializable::XML.to_xml(node, v)
|
187
|
-
end
|
188
|
-
xml
|
222
|
+
build_xml(xml, value) { |node| value.each { |v| Serializable::XML.to_xml(node, v) } }
|
189
223
|
end
|
190
224
|
def from_xml(xml)
|
191
|
-
xml
|
225
|
+
create_from_xml(xml) do |instance|
|
226
|
+
instance.replace(xml.elements.collect { |child| Serializable::XML.from_xml(child) })
|
227
|
+
end
|
192
228
|
end
|
193
229
|
end
|
194
230
|
|
@@ -243,56 +279,35 @@ module FIRM
|
|
243
279
|
end
|
244
280
|
end
|
245
281
|
|
246
|
-
define_xml_handler(::Hash) do
|
282
|
+
define_xml_handler(::Hash, aliasable: true) do
|
247
283
|
def to_xml(xml, value)
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
284
|
+
build_xml(xml, value) do |node|
|
285
|
+
value.each_pair do |k,v|
|
286
|
+
pair = node.add_child(Nokogiri::XML::Node.new('P', node.document))
|
287
|
+
Serializable::XML.to_xml(pair, k)
|
288
|
+
Serializable::XML.to_xml(pair, v)
|
289
|
+
end
|
253
290
|
end
|
254
|
-
xml
|
255
291
|
end
|
256
292
|
def from_xml(xml)
|
257
|
-
xml
|
258
|
-
|
259
|
-
|
260
|
-
|
293
|
+
create_from_xml(xml) do |instance|
|
294
|
+
xml.elements.inject(instance) do |hash, pair|
|
295
|
+
k, v = pair.elements
|
296
|
+
instance[Serializable::XML.from_xml(k)] = Serializable::XML.from_xml(v)
|
297
|
+
instance
|
298
|
+
end
|
261
299
|
end
|
262
300
|
end
|
263
301
|
end
|
264
302
|
|
265
|
-
define_xml_handler(::Struct) do
|
303
|
+
define_xml_handler(::Struct, aliasable: true) do
|
266
304
|
def to_xml(xml, value)
|
267
|
-
node
|
268
|
-
node['class'] = value.class.name
|
269
|
-
if (anchor = Serializable::Aliasing.get_anchor(value))
|
270
|
-
anchor_data = Serializable::Aliasing.get_anchor_data(value)
|
271
|
-
# retroactively insert the anchor in the anchored instance's serialization data
|
272
|
-
anchor_data['anchor'] = anchor unless anchor_data.has_attribute?('anchor')
|
273
|
-
node['alias'] = "#{anchor}"
|
274
|
-
else
|
275
|
-
# register anchor object **before** serializing properties to properly handle cycling (bidirectional
|
276
|
-
# references)
|
277
|
-
Serializable::Aliasing.register_anchor_object(value, node)
|
278
|
-
value.each do |v|
|
279
|
-
Serializable::XML.to_xml(node, v)
|
280
|
-
end
|
281
|
-
end
|
282
|
-
xml
|
305
|
+
build_xml(xml, value) { |node| value.each { |v| Serializable::XML.to_xml(node, v) } }
|
283
306
|
end
|
284
307
|
def from_xml(xml)
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
Serializable::Aliasing.resolve_anchor(klass, xml['alias'].to_i)
|
289
|
-
else
|
290
|
-
instance = klass.allocate
|
291
|
-
# in case this is an anchor restore the anchor instance before restoring the member values
|
292
|
-
# and afterwards initialize the instance with the restored member values
|
293
|
-
Serializable::Aliasing.restore_anchor(xml['anchor'].to_i, instance) if xml.has_attribute?('anchor')
|
294
|
-
instance.__send__(:initialize, *xml.elements.collect { |child| Serializable::XML.from_xml(child) })
|
295
|
-
instance
|
308
|
+
create_from_xml(xml) do |instance|
|
309
|
+
elems = xml.elements
|
310
|
+
instance.members.each_with_index { |n, i| instance[n] = Serializable::XML.from_xml(elems[i]) }
|
296
311
|
end
|
297
312
|
end
|
298
313
|
end
|
@@ -408,34 +423,34 @@ module FIRM
|
|
408
423
|
end
|
409
424
|
end
|
410
425
|
|
411
|
-
define_xml_handler(::Set) do
|
426
|
+
define_xml_handler(::Set, aliasable: true) do
|
412
427
|
def to_xml(xml, value)
|
413
|
-
node
|
414
|
-
value.each do |v|
|
415
|
-
Serializable::XML.to_xml(node, v)
|
416
|
-
end
|
417
|
-
xml
|
428
|
+
build_xml(xml, value) { |node| value.each { |v| Serializable::XML.to_xml(node, v) } }
|
418
429
|
end
|
419
430
|
def from_xml(xml)
|
420
|
-
|
431
|
+
create_from_xml(xml) do |instance|
|
432
|
+
instance.replace(xml.elements.collect { |child| Serializable::XML.from_xml(child) })
|
433
|
+
end
|
421
434
|
end
|
422
435
|
end
|
423
436
|
|
424
|
-
define_xml_handler(::OpenStruct) do
|
437
|
+
define_xml_handler(::OpenStruct, aliasable: true) do
|
425
438
|
def to_xml(xml, value)
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
439
|
+
build_xml(xml, value) do |node|
|
440
|
+
value.each_pair do |k,v|
|
441
|
+
pair = node.add_child(Nokogiri::XML::Node.new('P', node.document))
|
442
|
+
Serializable::XML.to_xml(pair, k)
|
443
|
+
Serializable::XML.to_xml(pair, v)
|
444
|
+
end
|
431
445
|
end
|
432
|
-
xml
|
433
446
|
end
|
434
447
|
def from_xml(xml)
|
435
|
-
xml
|
436
|
-
|
437
|
-
|
438
|
-
|
448
|
+
create_from_xml(xml) do |instance|
|
449
|
+
xml.elements.inject(::OpenStruct.new) do |hash, pair|
|
450
|
+
k, v = pair.elements
|
451
|
+
instance[Serializable::XML.from_xml(k)] = Serializable::XML.from_xml(v)
|
452
|
+
instance
|
453
|
+
end
|
439
454
|
end
|
440
455
|
end
|
441
456
|
end
|
data/lib/firm/version.rb
CHANGED
data/tests/serializer_tests.rb
CHANGED
@@ -770,12 +770,56 @@ module SerializerTestMixin
|
|
770
770
|
struct = CyclicTest.new
|
771
771
|
struct.list = [struct]
|
772
772
|
obj_serial = struct.serialize
|
773
|
-
struct_new =
|
774
|
-
assert_nothing_raised { struct_new = FIRM.deserialize(obj_serial) }
|
773
|
+
struct_new = assert_nothing_raised { FIRM.deserialize(obj_serial) }
|
775
774
|
assert_instance_of(CyclicTest, struct_new)
|
776
775
|
assert_equal(struct_new.object_id, struct_new.list[0].object_id)
|
777
776
|
end
|
778
777
|
|
778
|
+
def test_cyclic_core_containers
|
779
|
+
|
780
|
+
array = [1, 2, 3]
|
781
|
+
array << array
|
782
|
+
obj_serial = array.serialize
|
783
|
+
arr_new = assert_nothing_raised { FIRM.deserialize(obj_serial) }
|
784
|
+
assert_instance_of(::Array, arr_new)
|
785
|
+
assert_instance_of(::Array, arr_new.last)
|
786
|
+
assert_equal(arr_new.size, arr_new.last.size)
|
787
|
+
assert_equal(arr_new.object_id, arr_new.last.object_id)
|
788
|
+
|
789
|
+
hash = { one: 1, two: 2 }
|
790
|
+
hash[:self] = hash
|
791
|
+
obj_serial = hash.serialize
|
792
|
+
hash_new = assert_nothing_raised { FIRM.deserialize(obj_serial) }
|
793
|
+
assert_instance_of(::Hash, hash_new)
|
794
|
+
assert_instance_of(::Hash, hash_new[:self])
|
795
|
+
assert_equal(hash_new.size, hash_new[:self].size)
|
796
|
+
assert_equal(hash_new.object_id, hash_new[:self].object_id)
|
797
|
+
|
798
|
+
# the JRuby Psych implementation has a bug preventing cyclic reference support
|
799
|
+
# for Set objects (https://github.com/jruby/jruby/issues/8352)
|
800
|
+
unless defined? JRUBY_VERSION
|
801
|
+
set = ::Set.new([[1,2], {one: 1}])
|
802
|
+
set << set
|
803
|
+
obj_serial = set.serialize(pretty: true)
|
804
|
+
set_new = assert_nothing_raised { FIRM.deserialize(obj_serial) }
|
805
|
+
assert_instance_of(::Set, set_new)
|
806
|
+
assert_true(set_new.any? { |e| ::Array === e })
|
807
|
+
assert_true(set_new.any? { |e| ::Hash === e })
|
808
|
+
assert_true(set_new.any? { |e| ::Set === e && set_new.object_id == e.object_id })
|
809
|
+
end
|
810
|
+
|
811
|
+
ostruct = ::OpenStruct.new(one: 1, two: 2)
|
812
|
+
ostruct.me = ostruct
|
813
|
+
obj_serial = ostruct.serialize
|
814
|
+
ostruct_new = assert_nothing_raised { FIRM.deserialize(obj_serial) }
|
815
|
+
assert_instance_of(::OpenStruct, ostruct_new)
|
816
|
+
assert_equal(1, ostruct_new.one)
|
817
|
+
assert_equal(2, ostruct_new.two)
|
818
|
+
assert_instance_of(::OpenStruct, ostruct_new.me)
|
819
|
+
assert_equal(ostruct_new.object_id, ostruct_new.me.object_id)
|
820
|
+
|
821
|
+
end
|
822
|
+
|
779
823
|
def test_nested_hash_with_complex_keys
|
780
824
|
id_obj = Identifiable.new(:one)
|
781
825
|
id_obj2 = Identifiable.new(:two)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: firm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Corino
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-09-
|
11
|
+
date: 2024-09-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|