oj 1.2.10 → 1.2.11
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/README.md +4 -0
- data/ext/oj/oj.c +26 -11
- data/ext/oj/oj.h +1 -0
- data/lib/oj/version.rb +1 -1
- data/test/perf1.rb +64 -0
- data/test/{foo.rb → perf2.rb} +30 -12
- data/test/perf_obj_old.rb +213 -0
- data/test/tests.rb +3 -0
- metadata +30 -25
- data/test/boo.rb +0 -26
- data/test/bug.rb +0 -18
- data/test/where.rb +0 -54
data/README.md
CHANGED
@@ -24,6 +24,10 @@ A fast JSON parser and Object marshaller as a Ruby gem.
|
|
24
24
|
|
25
25
|
## <a name="release">Release Notes</a>
|
26
26
|
|
27
|
+
### Release 1.2.11
|
28
|
+
|
29
|
+
- Added :max_stack option to limit the size of string allocated on the stack.
|
30
|
+
|
27
31
|
### Release 1.2.10
|
28
32
|
|
29
33
|
- Added check for circular on loading of circular dumped JSON.
|
data/ext/oj/oj.c
CHANGED
@@ -40,9 +40,6 @@
|
|
40
40
|
|
41
41
|
#include "oj.h"
|
42
42
|
|
43
|
-
// maximum to allocate on the stack, arbitrary limit
|
44
|
-
#define SMALL_JSON 65536
|
45
|
-
|
46
43
|
typedef struct _YesNoOpt {
|
47
44
|
VALUE sym;
|
48
45
|
char *attr;
|
@@ -83,6 +80,7 @@ static VALUE circular_sym;
|
|
83
80
|
static VALUE compat_sym;
|
84
81
|
static VALUE create_id_sym;
|
85
82
|
static VALUE indent_sym;
|
83
|
+
static VALUE max_stack_sym;
|
86
84
|
static VALUE mode_sym;
|
87
85
|
static VALUE null_sym;
|
88
86
|
static VALUE object_sym;
|
@@ -117,6 +115,7 @@ struct _Options oj_default_options = {
|
|
117
115
|
No, // ascii_only
|
118
116
|
ObjectMode, // mode
|
119
117
|
json_class, // create_id
|
118
|
+
65536, // max_stack
|
120
119
|
0, // dump_opts
|
121
120
|
};
|
122
121
|
|
@@ -145,6 +144,7 @@ oj_get_odd(VALUE clas) {
|
|
145
144
|
* - symbol_keys: [true|false|nil] use symbols instead of strings for hash keys
|
146
145
|
* - mode: [:object|:strict|:compat|:null] load and dump modes to use for JSON
|
147
146
|
* - create_id: [String|nil] create id for json compatible object encoding, default is 'json_create'
|
147
|
+
* - max_stack: [Fixnum|nil] maximum json size to allocate on the stack, default is 65536
|
148
148
|
* @return [Hash] all current option settings.
|
149
149
|
*/
|
150
150
|
static VALUE
|
@@ -152,6 +152,7 @@ get_def_opts(VALUE self) {
|
|
152
152
|
VALUE opts = rb_hash_new();
|
153
153
|
|
154
154
|
rb_hash_aset(opts, indent_sym, INT2FIX(oj_default_options.indent));
|
155
|
+
rb_hash_aset(opts, max_stack_sym, INT2FIX(oj_default_options.max_stack));
|
155
156
|
rb_hash_aset(opts, circular_sym, (Yes == oj_default_options.circular) ? Qtrue : ((No == oj_default_options.circular) ? Qfalse : Qnil));
|
156
157
|
rb_hash_aset(opts, auto_define_sym, (Yes == oj_default_options.auto_define) ? Qtrue : ((No == oj_default_options.auto_define) ? Qfalse : Qnil));
|
157
158
|
rb_hash_aset(opts, ascii_only_sym, (Yes == oj_default_options.ascii_only) ? Qtrue : ((No == oj_default_options.ascii_only) ? Qfalse : Qnil));
|
@@ -186,6 +187,7 @@ get_def_opts(VALUE self) {
|
|
186
187
|
* the Oj gem. The :null mode ignores non-supported Objects and
|
187
188
|
* replaces them with a null.
|
188
189
|
* @param [String|nil] :create_id create id for json compatible object encoding
|
190
|
+
* @param [Fixnum|nil] :max_stack maximum size to allocate on the stack for a JSON String
|
189
191
|
* @return [nil]
|
190
192
|
*/
|
191
193
|
static VALUE
|
@@ -206,6 +208,17 @@ set_def_opts(VALUE self, VALUE opts) {
|
|
206
208
|
Check_Type(v, T_FIXNUM);
|
207
209
|
oj_default_options.indent = FIX2INT(v);
|
208
210
|
}
|
211
|
+
v = rb_hash_aref(opts, max_stack_sym);
|
212
|
+
if (Qnil != v) {
|
213
|
+
int i;
|
214
|
+
|
215
|
+
Check_Type(v, T_FIXNUM);
|
216
|
+
i = FIX2INT(v);
|
217
|
+
if (0 > i) {
|
218
|
+
i = 0;
|
219
|
+
}
|
220
|
+
oj_default_options.max_stack = (size_t)i;
|
221
|
+
}
|
209
222
|
|
210
223
|
v = rb_hash_lookup(opts, mode_sym);
|
211
224
|
if (Qnil == v) {
|
@@ -311,7 +324,7 @@ load_with_opts(VALUE input, Options copts) {
|
|
311
324
|
if (rb_type(input) == T_STRING) {
|
312
325
|
// the json string gets modified so make a copy of it
|
313
326
|
len = RSTRING_LEN(input) + 1;
|
314
|
-
if (
|
327
|
+
if (copts->max_stack < len) {
|
315
328
|
json = ALLOC_N(char, len);
|
316
329
|
} else {
|
317
330
|
json = ALLOCA_N(char, len);
|
@@ -324,7 +337,7 @@ load_with_opts(VALUE input, Options copts) {
|
|
324
337
|
if (oj_stringio_class == clas) {
|
325
338
|
s = rb_funcall2(input, oj_string_id, 0, 0);
|
326
339
|
len = RSTRING_LEN(s) + 1;
|
327
|
-
if (
|
340
|
+
if (copts->max_stack < len) {
|
328
341
|
json = ALLOC_N(char, len);
|
329
342
|
} else {
|
330
343
|
json = ALLOCA_N(char, len);
|
@@ -338,7 +351,7 @@ load_with_opts(VALUE input, Options copts) {
|
|
338
351
|
|
339
352
|
len = lseek(fd, 0, SEEK_END);
|
340
353
|
lseek(fd, 0, SEEK_SET);
|
341
|
-
if (
|
354
|
+
if (copts->max_stack < len) {
|
342
355
|
json = ALLOC_N(char, len + 1);
|
343
356
|
} else {
|
344
357
|
json = ALLOCA_N(char, len + 1);
|
@@ -351,7 +364,7 @@ load_with_opts(VALUE input, Options copts) {
|
|
351
364
|
} else if (rb_respond_to(input, oj_read_id)) {
|
352
365
|
s = rb_funcall2(input, oj_read_id, 0, 0);
|
353
366
|
len = RSTRING_LEN(s) + 1;
|
354
|
-
if (
|
367
|
+
if (copts->max_stack < len) {
|
355
368
|
json = ALLOC_N(char, len);
|
356
369
|
} else {
|
357
370
|
json = ALLOCA_N(char, len);
|
@@ -362,7 +375,7 @@ load_with_opts(VALUE input, Options copts) {
|
|
362
375
|
}
|
363
376
|
}
|
364
377
|
obj = oj_parse(json, copts);
|
365
|
-
if (
|
378
|
+
if (copts->max_stack < len) {
|
366
379
|
xfree(json);
|
367
380
|
}
|
368
381
|
return obj;
|
@@ -407,6 +420,7 @@ load_file(int argc, VALUE *argv, VALUE self) {
|
|
407
420
|
unsigned long len;
|
408
421
|
VALUE obj;
|
409
422
|
struct _Options options = oj_default_options;
|
423
|
+
size_t max_stack = oj_default_options.max_stack;
|
410
424
|
|
411
425
|
Check_Type(*argv, T_STRING);
|
412
426
|
path = StringValuePtr(*argv);
|
@@ -415,7 +429,7 @@ load_file(int argc, VALUE *argv, VALUE self) {
|
|
415
429
|
}
|
416
430
|
fseek(f, 0, SEEK_END);
|
417
431
|
len = ftell(f);
|
418
|
-
if (
|
432
|
+
if (max_stack < len) {
|
419
433
|
json = ALLOC_N(char, len + 1);
|
420
434
|
} else {
|
421
435
|
json = ALLOCA_N(char, len + 1);
|
@@ -431,7 +445,7 @@ load_file(int argc, VALUE *argv, VALUE self) {
|
|
431
445
|
parse_options(argv[1], &options);
|
432
446
|
}
|
433
447
|
obj = oj_parse(json, &options);
|
434
|
-
if (
|
448
|
+
if (max_stack < len) {
|
435
449
|
xfree(json);
|
436
450
|
}
|
437
451
|
return obj;
|
@@ -832,11 +846,12 @@ void Init_oj() {
|
|
832
846
|
compat_sym = ID2SYM(rb_intern("compat")); rb_gc_register_address(&compat_sym);
|
833
847
|
create_id_sym = ID2SYM(rb_intern("create_id")); rb_gc_register_address(&create_id_sym);
|
834
848
|
indent_sym = ID2SYM(rb_intern("indent")); rb_gc_register_address(&indent_sym);
|
849
|
+
max_stack_sym = ID2SYM(rb_intern("max_stack")); rb_gc_register_address(&max_stack_sym);
|
835
850
|
mode_sym = ID2SYM(rb_intern("mode")); rb_gc_register_address(&mode_sym);
|
836
|
-
symbol_keys_sym = ID2SYM(rb_intern("symbol_keys")); rb_gc_register_address(&symbol_keys_sym);
|
837
851
|
null_sym = ID2SYM(rb_intern("null")); rb_gc_register_address(&null_sym);
|
838
852
|
object_sym = ID2SYM(rb_intern("object")); rb_gc_register_address(&object_sym);
|
839
853
|
strict_sym = ID2SYM(rb_intern("strict")); rb_gc_register_address(&strict_sym);
|
854
|
+
symbol_keys_sym = ID2SYM(rb_intern("symbol_keys")); rb_gc_register_address(&symbol_keys_sym);
|
840
855
|
|
841
856
|
oj_slash_string = rb_str_new2("/"); rb_gc_register_address(&oj_slash_string);
|
842
857
|
|
data/ext/oj/oj.h
CHANGED
data/lib/oj/version.rb
CHANGED
data/test/perf1.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
#!/usr/bin/env ruby -wW1
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
$: << File.join(File.dirname(__FILE__), "../lib")
|
5
|
+
$: << File.join(File.dirname(__FILE__), "../ext")
|
6
|
+
|
7
|
+
#require 'test/unit'
|
8
|
+
require 'optparse'
|
9
|
+
require 'oj'
|
10
|
+
require 'ox'
|
11
|
+
|
12
|
+
$indent = 2
|
13
|
+
|
14
|
+
opts = OptionParser.new
|
15
|
+
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
|
16
|
+
files = opts.parse(ARGV)
|
17
|
+
|
18
|
+
iter = 100000
|
19
|
+
s = %{
|
20
|
+
{ "class": "Foo::Bar",
|
21
|
+
"attr1": [ true, [false, [12345, null], 3.967, ["something", false], null]],
|
22
|
+
"attr2": { "one": 1 }
|
23
|
+
}
|
24
|
+
}
|
25
|
+
#s = File.read('sample.json')
|
26
|
+
|
27
|
+
Oj.default_options = { :indent => 0 }
|
28
|
+
|
29
|
+
obj = Oj.load(s)
|
30
|
+
xml = Ox.dump(obj, :indent => 0)
|
31
|
+
|
32
|
+
puts xml
|
33
|
+
|
34
|
+
start = Time.now
|
35
|
+
iter.times do
|
36
|
+
Oj.load(s)
|
37
|
+
end
|
38
|
+
dt = Time.now - start
|
39
|
+
puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/msec" % [iter, dt, iter/dt/1000.0]
|
40
|
+
|
41
|
+
start = Time.now
|
42
|
+
iter.times do
|
43
|
+
Ox.load(xml)
|
44
|
+
end
|
45
|
+
dt = Time.now - start
|
46
|
+
puts "%d Ox.load()s in %0.3f seconds or %0.1f loads/msec" % [iter, dt, iter/dt/1000.0]
|
47
|
+
|
48
|
+
puts
|
49
|
+
|
50
|
+
start = Time.now
|
51
|
+
iter.times do
|
52
|
+
Oj.dump(obj)
|
53
|
+
end
|
54
|
+
dt = Time.now - start
|
55
|
+
puts "%d Oj.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter, dt, iter/dt/1000.0]
|
56
|
+
|
57
|
+
start = Time.now
|
58
|
+
iter.times do
|
59
|
+
Ox.dump(obj)
|
60
|
+
end
|
61
|
+
dt = Time.now - start
|
62
|
+
puts "%d Ox.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter, dt, iter/dt/1000.0]
|
63
|
+
|
64
|
+
puts
|
data/test/{foo.rb → perf2.rb}
RENAMED
@@ -15,6 +15,19 @@ opts = OptionParser.new
|
|
15
15
|
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
|
16
16
|
files = opts.parse(ARGV)
|
17
17
|
|
18
|
+
class Foo
|
19
|
+
def initialize()
|
20
|
+
@x = true
|
21
|
+
@y = 58
|
22
|
+
end
|
23
|
+
def to_json()
|
24
|
+
%{{"x":#{@x},"y":#{@y}}}
|
25
|
+
end
|
26
|
+
def to_hash()
|
27
|
+
{ 'x' => @x, 'y' => @y }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
18
31
|
iter = 100000
|
19
32
|
s = %{
|
20
33
|
{ "class": "Foo::Bar",
|
@@ -23,36 +36,41 @@ s = %{
|
|
23
36
|
}
|
24
37
|
}
|
25
38
|
|
39
|
+
obj = Oj.load(s)
|
40
|
+
obj["foo"] = Foo.new()
|
41
|
+
|
42
|
+
Oj.default_options = { :indent => 0, :effort => :internal }
|
43
|
+
|
44
|
+
puts
|
45
|
+
|
26
46
|
start = Time.now
|
27
47
|
iter.times do
|
28
48
|
Oj.load(s)
|
29
49
|
end
|
30
|
-
|
31
|
-
puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/msec" % [iter,
|
50
|
+
dt = Time.now - start
|
51
|
+
puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/msec" % [iter, dt, iter/dt/1000.0]
|
32
52
|
|
33
53
|
start = Time.now
|
34
54
|
iter.times do
|
35
55
|
Yajl::Parser.parse(s)
|
36
56
|
end
|
37
|
-
|
38
|
-
puts "%d Yajl::Parser.parse()s in %0.3f seconds or %0.1f parses/msec" % [iter,
|
57
|
+
dt = Time.now - start
|
58
|
+
puts "%d Yajl::Parser.parse()s in %0.3f seconds or %0.1f parses/msec" % [iter, dt, iter/dt/1000.0]
|
39
59
|
|
40
|
-
puts
|
60
|
+
puts
|
41
61
|
|
42
|
-
|
43
|
-
obj = Oj.load(s)
|
44
62
|
start = Time.now
|
45
63
|
iter.times do
|
46
64
|
Oj.dump(obj)
|
47
65
|
end
|
48
|
-
|
49
|
-
puts "%d Oj.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter,
|
66
|
+
dt = Time.now - start
|
67
|
+
puts "%d Oj.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter, dt, iter/dt/1000.0]
|
50
68
|
|
51
69
|
start = Time.now
|
52
70
|
iter.times do
|
53
71
|
Yajl::Encoder.encode(obj)
|
54
72
|
end
|
55
|
-
|
56
|
-
puts "%d Yajl::Encoder.encode()s in %0.3f seconds or %0.1f encodes/msec" % [iter,
|
73
|
+
dt = Time.now - start
|
74
|
+
puts "%d Yajl::Encoder.encode()s in %0.3f seconds or %0.1f encodes/msec" % [iter, dt, iter/dt/1000.0]
|
57
75
|
|
58
|
-
puts
|
76
|
+
puts
|
@@ -0,0 +1,213 @@
|
|
1
|
+
#!/usr/bin/env ruby -wW1
|
2
|
+
|
3
|
+
$: << '.'
|
4
|
+
$: << '..'
|
5
|
+
$: << '../lib'
|
6
|
+
$: << '../ext'
|
7
|
+
|
8
|
+
if __FILE__ == $0
|
9
|
+
if (i = ARGV.index('-I'))
|
10
|
+
x,path = ARGV.slice!(i, 2)
|
11
|
+
$: << path
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'optparse'
|
16
|
+
require 'ox'
|
17
|
+
require 'oj'
|
18
|
+
require 'perf'
|
19
|
+
require 'sample'
|
20
|
+
require 'files'
|
21
|
+
|
22
|
+
$verbose = 0
|
23
|
+
$circular = false
|
24
|
+
$indent = 0
|
25
|
+
|
26
|
+
do_sample = false
|
27
|
+
do_files = false
|
28
|
+
|
29
|
+
do_load = false
|
30
|
+
do_dump = false
|
31
|
+
do_read = false
|
32
|
+
do_write = false
|
33
|
+
$iter = 1000
|
34
|
+
|
35
|
+
opts = OptionParser.new
|
36
|
+
opts.on("-v", "increase verbosity") { $verbose += 1 }
|
37
|
+
|
38
|
+
opts.on("-c", "circular options") { $circular = true }
|
39
|
+
|
40
|
+
opts.on("-s", "load and dump as sample Ruby object") { do_sample = true }
|
41
|
+
opts.on("-f", "load and dump as files Ruby object") { do_files = true }
|
42
|
+
|
43
|
+
opts.on("-l", "load") { do_load = true }
|
44
|
+
opts.on("-d", "dump") { do_dump = true }
|
45
|
+
opts.on("-r", "read") { do_read = true }
|
46
|
+
opts.on("-w", "write") { do_write = true }
|
47
|
+
opts.on("-a", "load, dump, read and write") { do_load = true; do_dump = true; do_read = true; do_write = true }
|
48
|
+
|
49
|
+
opts.on("-i", "--iterations [Int]", Integer, "iterations") { |i| $iter = i }
|
50
|
+
|
51
|
+
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
|
52
|
+
files = opts.parse(ARGV)
|
53
|
+
|
54
|
+
if files.empty?
|
55
|
+
data = []
|
56
|
+
obj = do_sample ? sample_doc(2) : files('..')
|
57
|
+
mars = Marshal.dump(obj)
|
58
|
+
xml = Ox.dump(obj, :indent => $indent, circular: $circular)
|
59
|
+
json = Oj.dump(obj, :indent => $indent, circular: $circular)
|
60
|
+
File.open('sample.xml', 'w') { |f| f.write(xml) }
|
61
|
+
File.open('sample.json', 'w') { |f| f.write(json) }
|
62
|
+
File.open('sample.marshal', 'w') { |f| f.write(mars) }
|
63
|
+
data << { :file => 'sample.xml', :obj => obj, :xml => xml, :marshal => mars, :json => json }
|
64
|
+
else
|
65
|
+
puts "loading and parsing #{files}\n\n"
|
66
|
+
# TBD change to allow xml and json
|
67
|
+
data = files.map do |f|
|
68
|
+
xml = File.read(f)
|
69
|
+
obj = Ox.load(xml);
|
70
|
+
mars = Marshal.dump(obj)
|
71
|
+
json = Oj.dump(obj, :indent => $indent, circular: $circular)
|
72
|
+
{ :file => f, :obj => obj, :xml => xml, :marshal => mars, :json => json }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
$ox_load_time = 0
|
77
|
+
$mars_load_time = 0
|
78
|
+
$ox_dump_time = 0
|
79
|
+
$oj_dump_time = 0
|
80
|
+
$mars_dump_time = 0
|
81
|
+
|
82
|
+
def perf_load(d)
|
83
|
+
filename = d[:file]
|
84
|
+
marshal_filename = 'sample.marshal'
|
85
|
+
xml = d[:xml]
|
86
|
+
mars = d[:marshal]
|
87
|
+
json = d[:json]
|
88
|
+
|
89
|
+
if 0 < $verbose
|
90
|
+
obj = Ox.load(xml, :mode => :object, :trace => $verbose)
|
91
|
+
return
|
92
|
+
end
|
93
|
+
start = Time.now
|
94
|
+
(1..$iter).each do
|
95
|
+
obj = Ox.load(xml, :mode => :object)
|
96
|
+
end
|
97
|
+
$ox_load_time = Time.now - start
|
98
|
+
puts "Parsing #{$iter} times with Ox took #{$ox_load_time} seconds."
|
99
|
+
|
100
|
+
start = Time.now
|
101
|
+
(1..$iter).each do
|
102
|
+
obj = Oj.load(json, :mode => :object)
|
103
|
+
end
|
104
|
+
$oj_load_time = Time.now - start
|
105
|
+
puts "Parsing #{$iter} times with Oj took #{$oj_load_time} seconds."
|
106
|
+
|
107
|
+
start = Time.now
|
108
|
+
(1..$iter).each do
|
109
|
+
obj = Marshal.load(mars)
|
110
|
+
end
|
111
|
+
$mars_load_time = Time.now - start
|
112
|
+
puts "Marshalling #{$iter} times took #{$mars_load_time} seconds."
|
113
|
+
puts ">>> Ox is %0.1f faster than Marshal loading.\n\n" % [$mars_load_time/$ox_load_time]
|
114
|
+
end
|
115
|
+
|
116
|
+
def perf_dump(d)
|
117
|
+
obj = d[:obj]
|
118
|
+
|
119
|
+
start = Time.now
|
120
|
+
(1..$iter).each do
|
121
|
+
xml = Ox.dump(obj, :indent => $indent, :circular => $circular)
|
122
|
+
#puts "*** ox:\n#{xml}"
|
123
|
+
end
|
124
|
+
$ox_dump_time = Time.now - start
|
125
|
+
puts "Ox dumping #{$iter} times with ox took #{$ox_dump_time} seconds."
|
126
|
+
|
127
|
+
Oj.default_options = {:indent => $indent}
|
128
|
+
start = Time.now
|
129
|
+
(1..$iter).each do
|
130
|
+
json = Oj.dump(obj)
|
131
|
+
end
|
132
|
+
$oj_dump_time = Time.now - start
|
133
|
+
puts "Oj dumping #{$iter} times with oj took #{$oj_dump_time} seconds."
|
134
|
+
|
135
|
+
obj = d[:obj]
|
136
|
+
start = Time.now
|
137
|
+
(1..$iter).each do
|
138
|
+
m = Marshal.dump(obj)
|
139
|
+
end
|
140
|
+
$mars_dump_time = Time.now - start
|
141
|
+
puts "Marshal dumping #{$iter} times took #{$mars_dump_time} seconds."
|
142
|
+
puts ">>> Ox is %0.1f faster than Marshal dumping.\n\n" % [$mars_dump_time/$ox_dump_time]
|
143
|
+
end
|
144
|
+
|
145
|
+
def perf_read(d)
|
146
|
+
ox_read_time = 0
|
147
|
+
mars_read_time = 0
|
148
|
+
|
149
|
+
filename = d[:file]
|
150
|
+
marshal_filename = 'sample.marshal'
|
151
|
+
xml = d[:xml]
|
152
|
+
mars = d[:marshal]
|
153
|
+
|
154
|
+
# now load from the file
|
155
|
+
start = Time.now
|
156
|
+
(1..$iter).each do
|
157
|
+
obj = Ox.load_file(filename, :mode => :object)
|
158
|
+
end
|
159
|
+
ox_read_time = Time.now - start
|
160
|
+
puts "Loading and parsing #{$iter} times with ox took #{ox_read_time} seconds."
|
161
|
+
|
162
|
+
start = Time.now
|
163
|
+
(1..$iter).each do
|
164
|
+
m = File.read(marshal_filename)
|
165
|
+
obj = Marshal.load(m)
|
166
|
+
end
|
167
|
+
mars_read_time = Time.now - start
|
168
|
+
puts "Reading and marshalling #{$iter} times took #{mars_read_time} seconds."
|
169
|
+
puts ">>> Ox is %0.1f faster than Marshal loading and parsing.\n\n" % [mars_read_time/ox_read_time]
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
def perf_write(d)
|
174
|
+
ox_write_time = 0
|
175
|
+
mars_write_time = 0
|
176
|
+
|
177
|
+
ox_filename = 'out.xml'
|
178
|
+
marshal_filename = 'out.marshal'
|
179
|
+
obj = d[:obj]
|
180
|
+
|
181
|
+
start = Time.now
|
182
|
+
(1..$iter).each do
|
183
|
+
xml = Ox.to_file(ox_filename, obj, :indent => $indent)
|
184
|
+
end
|
185
|
+
ox_write_time = Time.now - start
|
186
|
+
puts "Ox dumping #{$iter} times with ox took #{ox_write_time} seconds."
|
187
|
+
|
188
|
+
start = Time.now
|
189
|
+
(1..$iter).each do
|
190
|
+
m = Marshal.dump(obj, circular: $circular)
|
191
|
+
File.open(marshal_filename, "w") { |f| f.write(m) }
|
192
|
+
end
|
193
|
+
mars_write_time = Time.now - start
|
194
|
+
puts "Marshal dumping and writing #{$iter} times took #{mars_write_time} seconds."
|
195
|
+
puts ">>> Ox is %0.1f faster than Marshal dumping.\n\n" % [mars_write_time/ox_write_time]
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
#if do_sample or do_files
|
200
|
+
data.each do |d|
|
201
|
+
puts "Using file #{d[:file]}."
|
202
|
+
|
203
|
+
perf_load(d) if do_load
|
204
|
+
perf_dump(d) if do_dump
|
205
|
+
if do_load and do_dump
|
206
|
+
puts ">>> Ox is %0.1f faster than Marshal dumping and loading.\n\n" % [($mars_load_time + $mars_dump_time)/($ox_load_time + $ox_dump_time)] unless 0 == $mars_load_time
|
207
|
+
end
|
208
|
+
|
209
|
+
perf_read(d) if do_read
|
210
|
+
perf_write(d) if do_write
|
211
|
+
|
212
|
+
end
|
213
|
+
#end
|
data/test/tests.rb
CHANGED
@@ -109,6 +109,7 @@ class Juice < ::Test::Unit::TestCase
|
|
109
109
|
:symbol_keys=>false,
|
110
110
|
:ascii_only=>false,
|
111
111
|
:mode=>:object,
|
112
|
+
:max_stack=>65536,
|
112
113
|
:create_id=>'json_class'}, opts)
|
113
114
|
end
|
114
115
|
|
@@ -120,6 +121,7 @@ class Juice < ::Test::Unit::TestCase
|
|
120
121
|
:symbol_keys=>false,
|
121
122
|
:ascii_only=>false,
|
122
123
|
:mode=>:object,
|
124
|
+
:max_stack=>65536,
|
123
125
|
:create_id=>'json_class'}
|
124
126
|
o2 = {
|
125
127
|
:indent=>4,
|
@@ -128,6 +130,7 @@ class Juice < ::Test::Unit::TestCase
|
|
128
130
|
:symbol_keys=>true,
|
129
131
|
:ascii_only=>true,
|
130
132
|
:mode=>:compat,
|
133
|
+
:max_stack=>4000,
|
131
134
|
:create_id=>nil}
|
132
135
|
o3 = { :indent => 4 }
|
133
136
|
Oj.default_options = o2
|
metadata
CHANGED
@@ -1,24 +1,27 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: oj
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.10
|
3
|
+
version: !ruby/object:Gem::Version
|
5
4
|
prerelease:
|
5
|
+
version: 1.2.11
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Peter Ohler
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
12
|
+
|
13
|
+
date: 2012-06-21 00:00:00 Z
|
13
14
|
dependencies: []
|
14
|
-
|
15
|
+
|
16
|
+
description: "The fastest JSON parser and object serializer. "
|
15
17
|
email: peter@ohler.com
|
16
18
|
executables: []
|
17
|
-
|
19
|
+
|
20
|
+
extensions:
|
18
21
|
- ext/oj/extconf.rb
|
19
|
-
extra_rdoc_files:
|
22
|
+
extra_rdoc_files:
|
20
23
|
- README.md
|
21
|
-
files:
|
24
|
+
files:
|
22
25
|
- lib/oj/bag.rb
|
23
26
|
- lib/oj/version.rb
|
24
27
|
- lib/oj.rb
|
@@ -32,13 +35,13 @@ files:
|
|
32
35
|
- ext/oj/fast.c
|
33
36
|
- ext/oj/load.c
|
34
37
|
- ext/oj/oj.c
|
35
|
-
- test/boo.rb
|
36
|
-
- test/bug.rb
|
37
38
|
- test/files.rb
|
38
|
-
- test/foo.rb
|
39
39
|
- test/perf.rb
|
40
|
+
- test/perf1.rb
|
41
|
+
- test/perf2.rb
|
40
42
|
- test/perf_fast.rb
|
41
43
|
- test/perf_obj.rb
|
44
|
+
- test/perf_obj_old.rb
|
42
45
|
- test/perf_simple.rb
|
43
46
|
- test/perf_strict.rb
|
44
47
|
- test/sample/change.rb
|
@@ -58,35 +61,37 @@ files:
|
|
58
61
|
- test/test_fast.rb
|
59
62
|
- test/test_mimic.rb
|
60
63
|
- test/tests.rb
|
61
|
-
- test/where.rb
|
62
64
|
- LICENSE
|
63
65
|
- README.md
|
64
66
|
homepage: http://www.ohler.com/oj
|
65
67
|
licenses: []
|
68
|
+
|
66
69
|
post_install_message:
|
67
|
-
rdoc_options:
|
70
|
+
rdoc_options:
|
68
71
|
- --main
|
69
72
|
- README.md
|
70
|
-
require_paths:
|
73
|
+
require_paths:
|
71
74
|
- lib
|
72
75
|
- ext
|
73
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
77
|
none: false
|
75
|
-
requirements:
|
76
|
-
- -
|
77
|
-
- !ruby/object:Gem::Version
|
78
|
-
version:
|
79
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: "0"
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
83
|
none: false
|
81
|
-
requirements:
|
82
|
-
- -
|
83
|
-
- !ruby/object:Gem::Version
|
84
|
-
version:
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: "0"
|
85
88
|
requirements: []
|
89
|
+
|
86
90
|
rubyforge_project: oj
|
87
91
|
rubygems_version: 1.8.23
|
88
92
|
signing_key:
|
89
93
|
specification_version: 3
|
90
94
|
summary: A fast JSON parser and serializer.
|
91
95
|
test_files: []
|
96
|
+
|
92
97
|
has_rdoc: true
|
data/test/boo.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby -wW1
|
2
|
-
# encoding: UTF-8
|
3
|
-
|
4
|
-
$: << File.join(File.dirname(__FILE__), "../lib")
|
5
|
-
$: << File.join(File.dirname(__FILE__), "../ext")
|
6
|
-
|
7
|
-
require 'yajl'
|
8
|
-
require 'oj'
|
9
|
-
|
10
|
-
iter = 100
|
11
|
-
s = File.read("boo.json")
|
12
|
-
start = Time.now
|
13
|
-
iter.times do
|
14
|
-
Oj.load(s)
|
15
|
-
end
|
16
|
-
oj_dt = Time.now - start
|
17
|
-
puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/second" % [iter, oj_dt, iter/oj_dt]
|
18
|
-
|
19
|
-
start = Time.now
|
20
|
-
iter.times do
|
21
|
-
Yajl::Parser.parse(s)
|
22
|
-
end
|
23
|
-
yajl_dt = Time.now - start
|
24
|
-
puts "%d Yajl::Parser.parse()s in %0.3f seconds or %0.1f parsed/second" % [iter, yajl_dt, iter/yajl_dt]
|
25
|
-
|
26
|
-
puts "Oj is %0.1f times faster than YAJL" % [yajl_dt / oj_dt]
|
data/test/bug.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
|
2
|
-
$: << File.join(File.dirname(__FILE__), "../lib")
|
3
|
-
$: << File.join(File.dirname(__FILE__), "../ext")
|
4
|
-
|
5
|
-
require 'oj'
|
6
|
-
require 'bigdecimal'
|
7
|
-
|
8
|
-
stuff = [
|
9
|
-
BigDecimal.new('10'),
|
10
|
-
Date.today,
|
11
|
-
Time.now,
|
12
|
-
DateTime.now
|
13
|
-
]
|
14
|
-
|
15
|
-
puts Oj.dump(stuff, :mode => :strict)
|
16
|
-
puts Oj.dump(stuff, :mode => :compat)
|
17
|
-
puts Oj.dump(stuff, :mode => :object)
|
18
|
-
|
data/test/where.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby -wW1
|
2
|
-
# encoding: UTF-8
|
3
|
-
|
4
|
-
$: << '.'
|
5
|
-
$: << File.join(File.dirname(__FILE__), "../lib")
|
6
|
-
$: << File.join(File.dirname(__FILE__), "../ext")
|
7
|
-
|
8
|
-
require 'optparse'
|
9
|
-
require 'perf'
|
10
|
-
require 'oj'
|
11
|
-
|
12
|
-
$verbose = false
|
13
|
-
$indent = 0
|
14
|
-
$iter = 1000000
|
15
|
-
|
16
|
-
opts = OptionParser.new
|
17
|
-
opts.on("-v", "verbose") { $verbose = true }
|
18
|
-
opts.on("-c", "--count [Int]", Integer, "iterations") { |i| $iter = i }
|
19
|
-
opts.on("-i", "--indent [Int]", Integer, "indentation") { |i| $indent = i }
|
20
|
-
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
|
21
|
-
files = opts.parse(ARGV)
|
22
|
-
|
23
|
-
$obj = {
|
24
|
-
'a' => 'Alpha', # string
|
25
|
-
'b' => true, # boolean
|
26
|
-
'c' => 12345, # number
|
27
|
-
'd' => [ true, [false, [12345, nil], 3.967, ['something', false], nil]], # mix it up array
|
28
|
-
'e' => { 'one' => 1, 'two' => 2 }, # hash
|
29
|
-
'f' => nil, # nil
|
30
|
-
'g' => 12345678901234567890123456789, # big number
|
31
|
-
'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
|
32
|
-
'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
|
33
|
-
}
|
34
|
-
|
35
|
-
Oj.default_options = { :indent => $indent, :mode => :strict }
|
36
|
-
|
37
|
-
$json = Oj.dump($obj)
|
38
|
-
|
39
|
-
if $verbose
|
40
|
-
puts "json:\n#{$json}\n"
|
41
|
-
end
|
42
|
-
|
43
|
-
puts '-' * 80
|
44
|
-
puts "Parse Performance"
|
45
|
-
Oj::Fast.open($json) do |fast|
|
46
|
-
fast.move('/d/2/4/2')
|
47
|
-
puts fast.where2?
|
48
|
-
puts fast.where?
|
49
|
-
perf = Perf.new()
|
50
|
-
perf.add('Oj:fast', 'where') { fast.where? }
|
51
|
-
perf.add('Oj:fast2', 'where2') { fast.where2? }
|
52
|
-
perf.run($iter)
|
53
|
-
end
|
54
|
-
puts
|