oj 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of oj might be problematic. Click here for more details.
- data/LICENSE +1 -1
- data/README.md +163 -104
- data/ext/oj/cache8.c +130 -0
- data/ext/oj/cache8.h +46 -0
- data/ext/oj/dump.c +270 -106
- data/ext/oj/load.c +266 -77
- data/ext/oj/oj.c +7 -0
- data/ext/oj/oj.h +3 -0
- data/lib/oj/version.rb +1 -1
- data/test/perf_obj.rb +3 -3
- data/test/perf_strict.rb +105 -35
- data/test/tests.rb +108 -7
- metadata +4 -2
data/ext/oj/oj.c
CHANGED
@@ -45,8 +45,10 @@ void Init_oj();
|
|
45
45
|
|
46
46
|
VALUE Oj = Qnil;
|
47
47
|
|
48
|
+
ID oj_as_json_id;
|
48
49
|
ID oj_at_id;
|
49
50
|
ID oj_instance_variables_id;
|
51
|
+
ID oj_json_create_id;
|
50
52
|
ID oj_to_hash_id;
|
51
53
|
ID oj_to_json_id;
|
52
54
|
ID oj_to_sym_id;
|
@@ -55,6 +57,7 @@ ID oj_tv_sec_id;
|
|
55
57
|
ID oj_tv_usec_id;
|
56
58
|
|
57
59
|
VALUE oj_bag_class;
|
60
|
+
VALUE oj_struct_class;
|
58
61
|
VALUE oj_time_class;
|
59
62
|
|
60
63
|
static VALUE auto_define_sym;
|
@@ -188,6 +191,7 @@ static void
|
|
188
191
|
parse_options(VALUE ropts, Options copts) {
|
189
192
|
struct _YesNoOpt ynos[] = {
|
190
193
|
{ circular_sym, &copts->circular },
|
194
|
+
{ auto_define_sym, &copts->auto_define },
|
191
195
|
{ Qnil, 0 }
|
192
196
|
};
|
193
197
|
YesNoOpt o;
|
@@ -364,8 +368,10 @@ void Init_oj() {
|
|
364
368
|
rb_define_module_function(Oj, "dump", dump, -1);
|
365
369
|
rb_define_module_function(Oj, "to_file", to_file, -1);
|
366
370
|
|
371
|
+
oj_as_json_id = rb_intern("as_json");
|
367
372
|
oj_at_id = rb_intern("at");
|
368
373
|
oj_instance_variables_id = rb_intern("instance_variables");
|
374
|
+
oj_json_create_id = rb_intern("json_create");
|
369
375
|
oj_to_hash_id = rb_intern("to_hash");
|
370
376
|
oj_to_json_id = rb_intern("to_json");
|
371
377
|
oj_to_sym_id = rb_intern("to_sym");
|
@@ -374,6 +380,7 @@ void Init_oj() {
|
|
374
380
|
oj_tv_usec_id = rb_intern("tv_usec");
|
375
381
|
|
376
382
|
oj_bag_class = rb_const_get_at(Oj, rb_intern("Bag"));
|
383
|
+
oj_struct_class = rb_const_get(rb_cObject, rb_intern("Struct"));
|
377
384
|
oj_time_class = rb_const_get(rb_cObject, rb_intern("Time"));
|
378
385
|
|
379
386
|
auto_define_sym = ID2SYM(rb_intern("auto_define")); rb_ary_push(keep, auto_define_sym);
|
data/ext/oj/oj.h
CHANGED
@@ -94,10 +94,13 @@ extern void _oj_raise_error(const char *msg, const char *xml, const char *curren
|
|
94
94
|
extern VALUE Oj;
|
95
95
|
|
96
96
|
extern VALUE oj_bag_class;
|
97
|
+
extern VALUE oj_struct_class;
|
97
98
|
extern VALUE oj_time_class;
|
98
99
|
|
100
|
+
extern ID oj_as_json_id;
|
99
101
|
extern ID oj_at_id;
|
100
102
|
extern ID oj_instance_variables_id;
|
103
|
+
extern ID oj_json_create_id;
|
101
104
|
extern ID oj_to_hash_id;
|
102
105
|
extern ID oj_to_json_id;
|
103
106
|
extern ID oj_to_sym_id;
|
data/lib/oj/version.rb
CHANGED
data/test/perf_obj.rb
CHANGED
@@ -63,8 +63,8 @@ end
|
|
63
63
|
if files.empty?
|
64
64
|
$obj = do_sample ? sample_doc(2) : files('..')
|
65
65
|
$mars = Marshal.dump($obj)
|
66
|
-
$xml = Ox.dump($obj, :indent => $indent, circular
|
67
|
-
$json = Oj.dump($obj, :indent => $indent, circular
|
66
|
+
$xml = Ox.dump($obj, :indent => $indent, :circular => $circular)
|
67
|
+
$json = Oj.dump($obj, :indent => $indent, :circular => $circular)
|
68
68
|
File.open('sample.xml', 'w') { |f| f.write($xml) }
|
69
69
|
File.open('sample.json', 'w') { |f| f.write($json) }
|
70
70
|
File.open('sample.marshal', 'w') { |f| f.write($mars) }
|
@@ -79,7 +79,7 @@ else
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
Oj.default_options = { :mode => :object, :indent => $indent }
|
82
|
+
Oj.default_options = { :mode => :object, :indent => $indent, :circular => $circular }
|
83
83
|
|
84
84
|
if do_load
|
85
85
|
puts '-' * 80
|
data/test/perf_strict.rb
CHANGED
@@ -16,36 +16,54 @@ require 'oj'
|
|
16
16
|
require 'ox'
|
17
17
|
|
18
18
|
class Jazz
|
19
|
+
attr_accessor :boolean, :number, :string
|
20
|
+
|
19
21
|
def initialize()
|
20
22
|
@boolean = true
|
21
23
|
@number = 58
|
22
24
|
@string = "A string"
|
23
|
-
@array = [true, false, nil]
|
24
|
-
@hash = { 'one' => 1, 'two' => 2 }
|
25
25
|
end
|
26
|
+
|
27
|
+
def eql?(o)
|
28
|
+
(self.class == o.class &&
|
29
|
+
boolean == o.boolean &&
|
30
|
+
number == o.number &&
|
31
|
+
string == o.string)
|
32
|
+
end
|
33
|
+
alias == eql?
|
34
|
+
|
26
35
|
def to_json(*) # Yajl and JSON have different signatures
|
27
36
|
%{
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
}
|
34
|
-
}
|
37
|
+
{ "json_class":"Jazz",
|
38
|
+
"boolean":#{@boolean},
|
39
|
+
"number":#{@number},
|
40
|
+
"string":"#{@string}"
|
41
|
+
}}
|
35
42
|
end
|
43
|
+
|
36
44
|
def to_hash()
|
37
|
-
{ '
|
45
|
+
{ 'json_class' => "Jazz",
|
46
|
+
'boolean' => @boolean,
|
38
47
|
'number' => @number,
|
39
|
-
'string' => @string
|
40
|
-
'array' => @array,
|
41
|
-
'hash' => @hash,
|
48
|
+
'string' => @string
|
42
49
|
}
|
43
50
|
end
|
51
|
+
alias as_json to_hash
|
52
|
+
|
44
53
|
def to_msgpack(out)
|
45
54
|
out << MessagePack.pack(to_hash())
|
46
55
|
end
|
56
|
+
|
57
|
+
def self.json_create(h)
|
58
|
+
j = self.new()
|
59
|
+
j.instance_variable_set(:@boolean, h['boolean'])
|
60
|
+
j.instance_variable_set(:@number, h['number'])
|
61
|
+
j.instance_variable_set(:@string, h['string'])
|
62
|
+
j
|
63
|
+
end
|
47
64
|
end
|
48
65
|
|
66
|
+
$verbose = false
|
49
67
|
$indent = 0
|
50
68
|
$iter = 100000
|
51
69
|
$with_object = true
|
@@ -53,6 +71,7 @@ $with_bignum = true
|
|
53
71
|
$with_nums = true
|
54
72
|
|
55
73
|
opts = OptionParser.new
|
74
|
+
opts.on("-v", "verbose") { $verbose = true }
|
56
75
|
opts.on("-c", "--count [Int]", Integer, "iterations") { |i| $iter = i }
|
57
76
|
opts.on("-i", "--indent [Int]", Integer, "indentation") { |i| $indent = i }
|
58
77
|
opts.on("-o", "without objects") { $with_object = false }
|
@@ -70,7 +89,6 @@ if $with_nums
|
|
70
89
|
'e' => { 'one' => 1, 'two' => 2 },
|
71
90
|
'f' => nil,
|
72
91
|
}
|
73
|
-
$obj['g'] = Jazz.new() if $with_object
|
74
92
|
$obj['h'] = 12345678901234567890123456789 if $with_bignum
|
75
93
|
else
|
76
94
|
$obj = {
|
@@ -82,50 +100,102 @@ else
|
|
82
100
|
'f' => nil,
|
83
101
|
}
|
84
102
|
end
|
103
|
+
$obj['g'] = Jazz.new() if $with_object
|
85
104
|
|
86
105
|
Oj.default_options = { :indent => $indent, :mode => :compat }
|
87
106
|
Ox.default_options = { :indent => $indent, :mode => :object }
|
88
107
|
|
89
108
|
$json = Oj.dump($obj)
|
109
|
+
$obj_json = Oj.dump($obj, :mode => :object)
|
90
110
|
$xml = Ox.dump($obj, :indent => $indent)
|
111
|
+
$failed = {} # key is same as String used in tests later
|
112
|
+
|
113
|
+
def capture_error(tag, orig, load_key, dump_key, &blk)
|
114
|
+
begin
|
115
|
+
obj = blk.call(orig)
|
116
|
+
raise "#{tag} #{dump_key} and #{load_key} did not return the same object as the original." unless orig == obj
|
117
|
+
rescue Exception => e
|
118
|
+
$failed[tag] = "#{e.class}: #{e.message}"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Verify that all packages dump and load correctly and return the same Object as the original.
|
123
|
+
capture_error('Oj:compat', $obj, 'load', 'dump') { |o| Oj.load(Oj.dump(o)) }
|
124
|
+
capture_error('Oj', $obj, 'load', 'dump') { |o| Oj.load(Oj.dump(o, :mode => :compat), :mode => :compat) }
|
125
|
+
capture_error('Ox', $obj, 'load', 'dump') { |o| Ox.load(Ox.dump(o, :mode => :object), :mode => :object) }
|
126
|
+
capture_error('MessagePack', $obj, 'unpack', 'pack') { |o| MessagePack.unpack(MessagePack.pack($obj)) }
|
127
|
+
capture_error('Yajl', $obj, 'encode', 'parse') { |o| Yajl::Parser.parse(Yajl::Encoder.encode(o)) }
|
128
|
+
capture_error('JSON::Ext', $obj, 'generate', 'parse') { |o| JSON.generator = JSON::Ext::Generator; JSON::Ext::Parser.new(JSON.generate(o)).parse }
|
129
|
+
capture_error('JSON::Pure', $obj, 'generate', 'parse') { |o| JSON.generator = JSON::Pure::Generator; JSON::Pure::Parser.new(JSON.generate(o)).parse }
|
130
|
+
|
91
131
|
begin
|
92
132
|
$msgpack = MessagePack.pack($obj)
|
93
133
|
rescue Exception => e
|
94
|
-
puts "MessagePack failed to pack! #{e.class}: #{e.message}.\nSkipping."
|
95
134
|
$msgpack = nil
|
96
135
|
end
|
97
136
|
|
137
|
+
if $verbose
|
138
|
+
puts "json:\n#{$json}\n"
|
139
|
+
puts "object json:\n#{$obj_json}\n"
|
140
|
+
puts "Oj loaded object:\n#{Oj.load($json)}\n"
|
141
|
+
puts "Yajl loaded object:\n#{Yajl::Parser.parse($json)}\n"
|
142
|
+
puts "JSON loaded object:\n#{JSON::Ext::Parser.new($json).parse}\n"
|
143
|
+
end
|
144
|
+
|
98
145
|
puts '-' * 80
|
99
146
|
puts "Load/Parse Performance"
|
100
147
|
perf = Perf.new()
|
101
|
-
|
102
|
-
perf.add('
|
103
|
-
perf.
|
104
|
-
|
105
|
-
|
106
|
-
perf.add('
|
148
|
+
unless $failed.has_key?('Oj:compat')
|
149
|
+
perf.add('Oj:compat', 'load') { Oj.load($json) }
|
150
|
+
perf.before('Oj:compat') { Oj.default_options = { :mode => :compat} }
|
151
|
+
end
|
152
|
+
unless $failed.has_key?('Oj')
|
153
|
+
perf.add('Oj', 'load') { Oj.load($obj_json) }
|
154
|
+
perf.before('Oj') { Oj.default_options = { :mode => :object} }
|
155
|
+
end
|
156
|
+
perf.add('Yajl', 'parse') { Yajl::Parser.parse($json) } unless $failed.has_key?('Yajl')
|
157
|
+
perf.add('JSON::Ext', 'parse') { JSON::Ext::Parser.new($json).parse } unless $failed.has_key?('JSON::Ext')
|
158
|
+
perf.add('JSON::Pure', 'parse') { JSON::Pure::Parser.new($json).parse } unless $failed.has_key?('JSON::Ext')
|
159
|
+
perf.add('Ox', 'load') { Ox.load($xml) } unless $failed.has_key?('Ox')
|
160
|
+
perf.add('MessagePack', 'unpack') { MessagePack.unpack($msgpack) } unless $failed.has_key?('MessagePack')
|
107
161
|
perf.run($iter)
|
108
162
|
|
109
163
|
puts
|
110
164
|
puts '-' * 80
|
111
165
|
puts "Dump/Encode/Generate Performance"
|
112
166
|
perf = Perf.new()
|
113
|
-
|
114
|
-
perf.add('
|
115
|
-
|
116
|
-
perf.add('JSON::Ext', 'generate') { JSON.generate($obj) }
|
117
|
-
else
|
118
|
-
perf.add('JSON::Ext', 'generate') { JSON.pretty_generate($obj) }
|
167
|
+
unless $failed.has_key?('Oj:compat')
|
168
|
+
perf.add('Oj:compat', 'dump') { Oj.dump($obj) }
|
169
|
+
perf.before('Oj:compat') { Oj.default_options = { :mode => :compat} }
|
119
170
|
end
|
120
|
-
|
121
|
-
|
122
|
-
perf.
|
123
|
-
else
|
124
|
-
perf.add('JSON::Pure', 'generate') { JSON.pretty_generate($obj) }
|
171
|
+
unless $failed.has_key?('Oj')
|
172
|
+
perf.add('Oj', 'dump') { Oj.dump($obj) }
|
173
|
+
perf.before('Oj') { Oj.default_options = { :mode => :object} }
|
125
174
|
end
|
126
|
-
perf.
|
127
|
-
|
128
|
-
|
175
|
+
perf.add('Yajl', 'encode') { Yajl::Encoder.encode($obj) } unless $failed.has_key?('Yajl')
|
176
|
+
unless $failed.has_key?('JSON::Ext')
|
177
|
+
if 0 == $indent
|
178
|
+
perf.add('JSON::Ext', 'generate') { JSON.generate($obj) }
|
179
|
+
else
|
180
|
+
perf.add('JSON::Ext', 'generate') { JSON.pretty_generate($obj) }
|
181
|
+
end
|
182
|
+
perf.before('JSON::Ext') { JSON.generator = JSON::Ext::Generator }
|
183
|
+
end
|
184
|
+
unless $failed.has_key?('JSON::Pure')
|
185
|
+
if 0 == $indent
|
186
|
+
perf.add('JSON::Pure', 'generate') { JSON.generate($obj) }
|
187
|
+
else
|
188
|
+
perf.add('JSON::Pure', 'generate') { JSON.pretty_generate($obj) }
|
189
|
+
end
|
190
|
+
perf.before('JSON::Pure') { JSON.generator = JSON::Pure::Generator }
|
191
|
+
end
|
192
|
+
perf.add('Ox', 'dump') { Ox.dump($obj) } unless $failed.has_key?('Ox')
|
193
|
+
perf.add('MessagePack', 'pack') { MessagePack.pack($obj) } unless $failed.has_key?('MessagePack')
|
129
194
|
perf.run($iter)
|
130
195
|
|
131
196
|
puts
|
197
|
+
|
198
|
+
unless $failed.empty?
|
199
|
+
puts "The following packages were not included for the reason listed"
|
200
|
+
$failed.each { |tag,msg| puts "***** #{tag}: #{msg}" }
|
201
|
+
end
|
data/test/tests.rb
CHANGED
@@ -8,7 +8,7 @@ require 'test/unit'
|
|
8
8
|
require 'oj'
|
9
9
|
|
10
10
|
class Jam
|
11
|
-
|
11
|
+
attr_accessor :x, :y
|
12
12
|
|
13
13
|
def initialize(x, y)
|
14
14
|
@x = x
|
@@ -28,9 +28,12 @@ class Jeez < Jam
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def to_json()
|
31
|
-
%{{"x":#{@x},"y":#{@y}}}
|
31
|
+
%{{"json_class":"#{self.class}","x":#{@x},"y":#{@y}}}
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.json_create(h)
|
35
|
+
self.new(h['x'], h['y'])
|
32
36
|
end
|
33
|
-
|
34
37
|
end # Jeez
|
35
38
|
|
36
39
|
class Jazz < Jam
|
@@ -38,10 +41,19 @@ class Jazz < Jam
|
|
38
41
|
super
|
39
42
|
end
|
40
43
|
def to_hash()
|
41
|
-
{ 'x' => @x, 'y' => @y }
|
44
|
+
{ 'json_class' => self.class.to_s, 'x' => @x, 'y' => @y }
|
45
|
+
end
|
46
|
+
def self.json_create(h)
|
47
|
+
self.new(h['x'], h['y'])
|
42
48
|
end
|
43
49
|
end # Jazz
|
44
50
|
|
51
|
+
class Range
|
52
|
+
def to_hash()
|
53
|
+
{ 'begin' => self.begin, 'end' => self.end, 'exclude_end' => self.exclude_end? }
|
54
|
+
end
|
55
|
+
end # Range
|
56
|
+
|
45
57
|
class Juice < ::Test::Unit::TestCase
|
46
58
|
|
47
59
|
def test_get_options
|
@@ -260,9 +272,11 @@ class Juice < ::Test::Unit::TestCase
|
|
260
272
|
assert_equal('null', json)
|
261
273
|
end
|
262
274
|
def test_json_object_compat
|
275
|
+
Oj.default_options = { :mode => :compat }
|
263
276
|
obj = Jeez.new(true, 58)
|
264
|
-
json = Oj.dump(obj, :
|
265
|
-
assert_equal(%{{"x":true,"y":58}}, json)
|
277
|
+
json = Oj.dump(obj, :indent => 2)
|
278
|
+
assert_equal(%{{"json_class":"Jeez","x":true,"y":58}}, json)
|
279
|
+
dump_and_load(obj, false)
|
266
280
|
end
|
267
281
|
def test_json_object_object
|
268
282
|
obj = Jeez.new(true, 58)
|
@@ -293,6 +307,7 @@ class Juice < ::Test::Unit::TestCase
|
|
293
307
|
obj = Jazz.new(true, 58)
|
294
308
|
json = Oj.dump(obj, :mode => :compat, :indent => 2)
|
295
309
|
assert_equal(%{{
|
310
|
+
"json_class":"Jazz",
|
296
311
|
"x":true,
|
297
312
|
"y":58}}, json)
|
298
313
|
end
|
@@ -307,7 +322,7 @@ class Juice < ::Test::Unit::TestCase
|
|
307
322
|
assert_equal(obj, obj2)
|
308
323
|
end
|
309
324
|
|
310
|
-
# Object without to_json() or to_hash()
|
325
|
+
# Object without to_json() or to_hash()
|
311
326
|
def test_object_strict
|
312
327
|
obj = Jam.new(true, 58)
|
313
328
|
begin
|
@@ -339,6 +354,7 @@ class Juice < ::Test::Unit::TestCase
|
|
339
354
|
assert_equal(obj, obj2)
|
340
355
|
end
|
341
356
|
|
357
|
+
# Exception
|
342
358
|
def test_exception
|
343
359
|
err = nil
|
344
360
|
begin
|
@@ -356,6 +372,34 @@ class Juice < ::Test::Unit::TestCase
|
|
356
372
|
assert_equal(e, e2);
|
357
373
|
end
|
358
374
|
|
375
|
+
# Range
|
376
|
+
def test_range_strict
|
377
|
+
begin
|
378
|
+
json = Oj.dump(1..7, :mode => :strict)
|
379
|
+
rescue Exception => e
|
380
|
+
assert(true)
|
381
|
+
end
|
382
|
+
end
|
383
|
+
def test_range_null
|
384
|
+
json = Oj.dump(1..7, :mode => :null)
|
385
|
+
assert_equal('null', json)
|
386
|
+
end
|
387
|
+
def test_range_compat
|
388
|
+
json = Oj.dump(1..7, :mode => :compat)
|
389
|
+
assert_equal(%{{"begin":1,"end":7,"exclude_end":false}}, json)
|
390
|
+
json = Oj.dump(1...7, :mode => :compat)
|
391
|
+
assert_equal(%{{"begin":1,"end":7,"exclude_end":true}}, json)
|
392
|
+
end
|
393
|
+
def test_range_object
|
394
|
+
Oj.default_options = { :mode => :object }
|
395
|
+
json = Oj.dump(1..7, :mode => :object, :indent => 0)
|
396
|
+
assert_equal(%{{"^u":["Range",1,7,false]}}, json)
|
397
|
+
dump_and_load(1..7, false)
|
398
|
+
dump_and_load(1..1, false)
|
399
|
+
dump_and_load(1...7, false)
|
400
|
+
end
|
401
|
+
|
402
|
+
# autodefine Oj::Bag
|
359
403
|
def test_bag
|
360
404
|
json = %{{
|
361
405
|
"^o":"Jem",
|
@@ -367,6 +411,63 @@ class Juice < ::Test::Unit::TestCase
|
|
367
411
|
assert_equal(58, obj.y)
|
368
412
|
end
|
369
413
|
|
414
|
+
# Circular
|
415
|
+
def test_circular_object
|
416
|
+
obj = Jam.new(nil, 58)
|
417
|
+
obj.x = obj
|
418
|
+
json = Oj.dump(obj, :mode => :object, :indent => 2, :circular => true)
|
419
|
+
assert_equal(%{{
|
420
|
+
"^o":"Jam",
|
421
|
+
"^i":1,
|
422
|
+
"x":"^r1",
|
423
|
+
"y":58}}, json)
|
424
|
+
obj2 = Oj.load(json, :mode => :object, :circular => true)
|
425
|
+
assert_equal(obj2.x.__id__, obj2.__id__)
|
426
|
+
end
|
427
|
+
|
428
|
+
def test_circular_hash
|
429
|
+
h = { 'a' => 7 }
|
430
|
+
h['b'] = h
|
431
|
+
json = Oj.dump(h, :mode => :object, :indent => 2, :circular => true)
|
432
|
+
assert_equal(%{{
|
433
|
+
"^i":1,
|
434
|
+
"a":7,
|
435
|
+
"b":"^r1"}}, json)
|
436
|
+
h2 = Oj.load(json, :mode => :object, :circular => true)
|
437
|
+
assert_equal(h['b'].__id__, h.__id__)
|
438
|
+
end
|
439
|
+
|
440
|
+
def test_circular_array
|
441
|
+
a = [7]
|
442
|
+
a << a
|
443
|
+
json = Oj.dump(a, :mode => :object, :indent => 2, :circular => true)
|
444
|
+
assert_equal(%{[
|
445
|
+
"^i1",
|
446
|
+
7,
|
447
|
+
"^r1"]}, json)
|
448
|
+
a2 = Oj.load(json, :mode => :object, :circular => true)
|
449
|
+
assert_equal(a2[1].__id__, a2.__id__)
|
450
|
+
end
|
451
|
+
|
452
|
+
def test_circular
|
453
|
+
h = { 'a' => 7 }
|
454
|
+
obj = Jam.new(h, 58)
|
455
|
+
obj.x['b'] = obj
|
456
|
+
json = Oj.dump(obj, :mode => :object, :indent => 2, :circular => true)
|
457
|
+
assert_equal(%{{
|
458
|
+
"^o":"Jam",
|
459
|
+
"^i":1,
|
460
|
+
"x":{
|
461
|
+
"^i":2,
|
462
|
+
"a":7,
|
463
|
+
"b":"^r1"
|
464
|
+
},
|
465
|
+
"y":58}}, json)
|
466
|
+
obj2 = Oj.load(json, :mode => :object, :circular => true)
|
467
|
+
assert_equal(obj.x.__id__, h.__id__)
|
468
|
+
assert_equal(h['b'].__id__, obj.__id__)
|
469
|
+
end
|
470
|
+
|
370
471
|
def dump_and_load(obj, trace=false)
|
371
472
|
json = Oj.dump(obj, :indent => 2)
|
372
473
|
puts json if trace
|