26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
# File 'lib/bparity/recording.rb', line 26
def dump(value, projections: {}, seen: nil)
seen ||= {}.compare_by_identity
projection = projections[value.class.name]
if projection
return { "$unserializable" => value.class.name, "$reason" => "cyclic projection" } if seen.key?(value)
return dump(projection.call(value), projections:, seen: with_seen(seen, value))
end
if recursive?(value)
return { "$unserializable" => value.class.name, "$reason" => "cyclic reference" } if seen.key?(value)
seen = with_seen(seen, value)
end
case value
when nil, true, false, Integer then value
when String
if value.valid_encoding?
value
else
{ "$string_bytes" => [value.b].pack("m0"), "$encoding" => value.encoding.name }
end
when Float then value.finite? ? value : { "$float" => value.to_s }
when Symbol then { "$symbol" => value.to_s }
when Time then { "$time" => value.utc.iso8601(9) }
when Array then value.map { |item| dump(item, projections:, seen:) }
when Hash
{ "$hash" => value.map do |key, item|
[dump(key, projections:, seen:), dump(item, projections:, seen:)]
end }
else
dump_object(value, projections, seen)
end
rescue StandardError
{ "$unserializable" => value.class.name, "$digest" => safe_digest(value) }
end
|