oj 0.5.1 → 0.5.2
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 +3 -1
- data/ext/oj/dump.c +1 -1
- data/ext/oj/load.c +7 -4
- data/ext/oj/oj.c +40 -21
- data/lib/oj/version.rb +1 -1
- data/test/boo.rb +26 -0
- data/test/foo.rb +58 -0
- data/test/perf_simple.rb +65 -0
- data/test/simple.rb +104 -0
- metadata +6 -5
data/README.md
CHANGED
@@ -18,7 +18,9 @@ A fast JSON parser and Object marshaller as a Ruby gem.
|
|
18
18
|
|
19
19
|
## <a name="release">Release Notes</a>
|
20
20
|
|
21
|
-
### Release 0.5
|
21
|
+
### Release 0.5.2
|
22
|
+
|
23
|
+
- Release 0.5.2 fixes encoding and float encoding.
|
22
24
|
|
23
25
|
This is the first release sith a version of 0.5 indicating it is only half
|
24
26
|
done. Basic load() and dump() is supported for Hash, Array, NilClass,
|
data/ext/oj/dump.c
CHANGED
data/ext/oj/load.c
CHANGED
@@ -116,7 +116,7 @@ parse(char *json, Options options) {
|
|
116
116
|
/* initialize parse info */
|
117
117
|
pi.str = json;
|
118
118
|
pi.s = json;
|
119
|
-
pi.encoding = 0;
|
119
|
+
pi.encoding = ('\0' == *options->encoding) ? 0 : rb_enc_find(options->encoding);
|
120
120
|
pi.options = options;
|
121
121
|
if (Qundef == (obj = read_next(&pi))) {
|
122
122
|
raise_error("no object read", pi.str, pi.s);
|
@@ -298,14 +298,17 @@ read_num(ParseInfo pi) {
|
|
298
298
|
e = e * 10 + (*pi->s - '0');
|
299
299
|
}
|
300
300
|
}
|
301
|
-
if (neg) {
|
302
|
-
n = -n;
|
303
|
-
}
|
304
301
|
if (0 == e && 0 == a && 1 == div) {
|
302
|
+
if (neg) {
|
303
|
+
n = -n;
|
304
|
+
}
|
305
305
|
return LONG2NUM(n);
|
306
306
|
} else {
|
307
307
|
double d = (double)n + (double)a / (double)div;
|
308
308
|
|
309
|
+
if (neg) {
|
310
|
+
d = -d;
|
311
|
+
}
|
309
312
|
if (0 != e) {
|
310
313
|
if (eneg) {
|
311
314
|
e = -e;
|
data/ext/oj/oj.c
CHANGED
@@ -41,14 +41,6 @@ typedef struct _YesNoOpt {
|
|
41
41
|
char *attr;
|
42
42
|
} *YesNoOpt;
|
43
43
|
|
44
|
-
struct _Options default_options = {
|
45
|
-
{ '\0' }, // encoding
|
46
|
-
2, // indent
|
47
|
-
No, // circular
|
48
|
-
NoMode, // mode
|
49
|
-
TolerantEffort, // effort
|
50
|
-
};
|
51
|
-
|
52
44
|
void Init_oj();
|
53
45
|
|
54
46
|
VALUE Oj = Qnil;
|
@@ -64,6 +56,13 @@ VALUE simple_sym;
|
|
64
56
|
VALUE strict_sym;
|
65
57
|
VALUE tolerant_sym;
|
66
58
|
|
59
|
+
static struct _Options default_options = {
|
60
|
+
{ '\0' }, // encoding
|
61
|
+
0, // indent
|
62
|
+
No, // circular
|
63
|
+
NoMode, // mode
|
64
|
+
TolerantEffort, // effort
|
65
|
+
};
|
67
66
|
|
68
67
|
/* call-seq: default_options() => Hash
|
69
68
|
*
|
@@ -106,8 +105,13 @@ get_def_opts(VALUE self) {
|
|
106
105
|
* @param [Fixnum] :indent number of spaces to indent each element in an XML document
|
107
106
|
* @param [String] :encoding character encoding for the JSON file
|
108
107
|
* @param [true|false|nil] :circular support circular references while dumping
|
109
|
-
* @param [:object|:simple|nil] :mode load
|
110
|
-
* @param [:strict|:tolerant|:lazy] :effort set the tolerance level for
|
108
|
+
* @param [:object|:simple|nil] :mode load and dump methods to use for JSON
|
109
|
+
* @param [:strict|:tolerant|:lazy] :effort set the tolerance level for
|
110
|
+
* loading. :strict raises an exception when a non-supported Object is
|
111
|
+
* encountered. :tolerant attempts to extract variable values from an
|
112
|
+
* Object using to_json() then it walks the Object's variables. The
|
113
|
+
* :lazy mode ignores non-supported Objects and replaces them with a
|
114
|
+
* null.
|
111
115
|
* @return [nil]
|
112
116
|
*/
|
113
117
|
static VALUE
|
@@ -121,8 +125,10 @@ set_def_opts(VALUE self, VALUE opts) {
|
|
121
125
|
|
122
126
|
Check_Type(opts, T_HASH);
|
123
127
|
|
124
|
-
v =
|
125
|
-
if (
|
128
|
+
v = rb_hash_lookup2(opts, encoding_sym, Qundef);
|
129
|
+
if (Qundef == v) {
|
130
|
+
// no change
|
131
|
+
} else if (Qnil == v) {
|
126
132
|
*default_options.encoding = '\0';
|
127
133
|
} else {
|
128
134
|
Check_Type(v, T_STRING);
|
@@ -135,8 +141,10 @@ set_def_opts(VALUE self, VALUE opts) {
|
|
135
141
|
default_options.indent = FIX2INT(v);
|
136
142
|
}
|
137
143
|
|
138
|
-
v =
|
139
|
-
if (
|
144
|
+
v = rb_hash_lookup2(opts, mode_sym, Qundef);
|
145
|
+
if (Qundef == v) {
|
146
|
+
// no change
|
147
|
+
} else if (Qnil == v) {
|
140
148
|
default_options.mode = NoMode;
|
141
149
|
} else if (object_sym == v) {
|
142
150
|
default_options.mode = ObjectMode;
|
@@ -146,8 +154,10 @@ set_def_opts(VALUE self, VALUE opts) {
|
|
146
154
|
rb_raise(rb_eArgError, ":mode must be :object, :simple, or nil.\n");
|
147
155
|
}
|
148
156
|
|
149
|
-
v =
|
150
|
-
if (
|
157
|
+
v = rb_hash_lookup2(opts, effort_sym, Qundef);
|
158
|
+
if (Qundef == v) {
|
159
|
+
// no change
|
160
|
+
} else if (Qnil == v) {
|
151
161
|
default_options.effort = NoEffort;
|
152
162
|
} else if (strict_sym == v) {
|
153
163
|
default_options.effort = StrictEffort;
|
@@ -159,8 +169,10 @@ set_def_opts(VALUE self, VALUE opts) {
|
|
159
169
|
rb_raise(rb_eArgError, ":effort must be :strict, :tolerant, :lazy, or nil.\n");
|
160
170
|
}
|
161
171
|
for (o = ynos; 0 != o->attr; o++) {
|
162
|
-
v =
|
163
|
-
|
172
|
+
v = rb_hash_lookup2(opts, o->sym, Qundef);
|
173
|
+
if (Qundef == v) {
|
174
|
+
// no change
|
175
|
+
} else if (Qnil == v) {
|
164
176
|
*o->attr = NotSet;
|
165
177
|
} else if (Qtrue == v) {
|
166
178
|
*o->attr = Yes;
|
@@ -246,13 +258,13 @@ load(char *json, int argc, VALUE *argv, VALUE self) {
|
|
246
258
|
return obj;
|
247
259
|
}
|
248
260
|
|
249
|
-
/* call-seq: load(
|
261
|
+
/* call-seq: load(json, options) => Hash, Array, String, Fixnum, Float, true, false, or nil
|
250
262
|
*
|
251
263
|
* Parses a JSON document String into a Hash, Array, String, Fixnum, Float,
|
252
|
-
* true, false, or nil Raises an exception if the JSON is
|
264
|
+
* true, false, or nil. Raises an exception if the JSON is malformed or the
|
253
265
|
* classes specified are not valid.
|
254
266
|
* @param [String] json JSON String
|
255
|
-
* @param [Hash] options load options
|
267
|
+
* @param [Hash] options load options (same as default_options)
|
256
268
|
*/
|
257
269
|
static VALUE
|
258
270
|
load_str(int argc, VALUE *argv, VALUE self) {
|
@@ -294,6 +306,12 @@ load_file(int argc, VALUE *argv, VALUE self) {
|
|
294
306
|
return load(json, argc - 1, argv + 1, self);
|
295
307
|
}
|
296
308
|
|
309
|
+
/* call-seq: dump(obj, options) => json-string
|
310
|
+
*
|
311
|
+
* Dumps an Object (obj) to a string.
|
312
|
+
* @param [Object] obj Object to serialize as an JSON document String
|
313
|
+
* @param [Hash] options same as default_options
|
314
|
+
*/
|
297
315
|
static VALUE
|
298
316
|
dump(int argc, VALUE *argv, VALUE self) {
|
299
317
|
char *json;
|
@@ -340,6 +358,7 @@ void Init_oj() {
|
|
340
358
|
simple_sym = ID2SYM(rb_intern("simple")); rb_ary_push(keep, simple_sym);
|
341
359
|
strict_sym = ID2SYM(rb_intern("strict")); rb_ary_push(keep, strict_sym);
|
342
360
|
tolerant_sym = ID2SYM(rb_intern("tolerant")); rb_ary_push(keep, tolerant_sym);
|
361
|
+
default_options.effort = TolerantEffort;
|
343
362
|
}
|
344
363
|
|
345
364
|
void
|
data/lib/oj/version.rb
CHANGED
data/test/boo.rb
ADDED
@@ -0,0 +1,26 @@
|
|
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/foo.rb
ADDED
@@ -0,0 +1,58 @@
|
|
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 'yajl'
|
10
|
+
require 'oj'
|
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
|
+
|
26
|
+
start = Time.now
|
27
|
+
iter.times do
|
28
|
+
Oj.load(s)
|
29
|
+
end
|
30
|
+
oj_dt = Time.now - start
|
31
|
+
puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/msec" % [iter, oj_dt, iter/oj_dt/1000.0]
|
32
|
+
|
33
|
+
start = Time.now
|
34
|
+
iter.times do
|
35
|
+
Yajl::Parser.parse(s)
|
36
|
+
end
|
37
|
+
yajl_dt = Time.now - start
|
38
|
+
puts "%d Yajl::Parser.parse()s in %0.3f seconds or %0.1f parses/msec" % [iter, yajl_dt, iter/yajl_dt/1000.0]
|
39
|
+
|
40
|
+
puts "Oj is %0.1f times faster than YAJL at parsing." % [yajl_dt / oj_dt]
|
41
|
+
|
42
|
+
|
43
|
+
obj = Oj.load(s)
|
44
|
+
start = Time.now
|
45
|
+
iter.times do
|
46
|
+
Oj.dump(obj)
|
47
|
+
end
|
48
|
+
oj_dt = Time.now - start
|
49
|
+
puts "%d Oj.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter, oj_dt, iter/oj_dt/1000.0]
|
50
|
+
|
51
|
+
start = Time.now
|
52
|
+
iter.times do
|
53
|
+
Yajl::Encoder.encode(obj)
|
54
|
+
end
|
55
|
+
yajl_dt = Time.now - start
|
56
|
+
puts "%d Yajl::Encoder.encode()s in %0.3f seconds or %0.1f encodes/msec" % [iter, yajl_dt, iter/yajl_dt/1000.0]
|
57
|
+
|
58
|
+
puts "Oj is %0.1f times faster than YAJL at dumping." % [yajl_dt / oj_dt]
|
data/test/perf_simple.rb
ADDED
@@ -0,0 +1,65 @@
|
|
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 'yajl'
|
10
|
+
require 'oj'
|
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
|
+
|
26
|
+
Oj.default_options = { :indent => 0 }
|
27
|
+
|
28
|
+
puts
|
29
|
+
|
30
|
+
start = Time.now
|
31
|
+
iter.times do
|
32
|
+
Oj.load(s)
|
33
|
+
end
|
34
|
+
oj_dt = Time.now - start
|
35
|
+
puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/msec" % [iter, oj_dt, iter/oj_dt/1000.0]
|
36
|
+
|
37
|
+
start = Time.now
|
38
|
+
iter.times do
|
39
|
+
Yajl::Parser.parse(s)
|
40
|
+
end
|
41
|
+
yajl_dt = Time.now - start
|
42
|
+
puts "%d Yajl::Parser.parse()s in %0.3f seconds or %0.1f parses/msec" % [iter, yajl_dt, iter/yajl_dt/1000.0]
|
43
|
+
|
44
|
+
puts "Oj is %0.1f times faster than YAJL at parsing." % [yajl_dt / oj_dt]
|
45
|
+
|
46
|
+
puts
|
47
|
+
|
48
|
+
obj = Oj.load(s)
|
49
|
+
start = Time.now
|
50
|
+
iter.times do
|
51
|
+
Oj.dump(obj)
|
52
|
+
end
|
53
|
+
oj_dt = Time.now - start
|
54
|
+
puts "%d Oj.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter, oj_dt, iter/oj_dt/1000.0]
|
55
|
+
|
56
|
+
start = Time.now
|
57
|
+
iter.times do
|
58
|
+
Yajl::Encoder.encode(obj)
|
59
|
+
end
|
60
|
+
yajl_dt = Time.now - start
|
61
|
+
puts "%d Yajl::Encoder.encode()s in %0.3f seconds or %0.1f encodes/msec" % [iter, yajl_dt, iter/yajl_dt/1000.0]
|
62
|
+
|
63
|
+
puts "Oj is %0.1f times faster than YAJL at dumping." % [yajl_dt / oj_dt]
|
64
|
+
|
65
|
+
puts
|
data/test/simple.rb
ADDED
@@ -0,0 +1,104 @@
|
|
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 'oj'
|
9
|
+
|
10
|
+
class Juice < ::Test::Unit::TestCase
|
11
|
+
|
12
|
+
def test_get_options
|
13
|
+
opts = Oj.default_options()
|
14
|
+
assert_equal(opts, {
|
15
|
+
:encoding=>nil,
|
16
|
+
:indent=>0,
|
17
|
+
:circular=>false,
|
18
|
+
:mode=>nil,
|
19
|
+
:effort=>:tolerant})
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_set_options
|
23
|
+
orig = {
|
24
|
+
:encoding=>nil,
|
25
|
+
:indent=>0,
|
26
|
+
:circular=>false,
|
27
|
+
:mode=>nil,
|
28
|
+
:effort=>:tolerant}
|
29
|
+
o2 = {
|
30
|
+
:encoding=>"UTF-8",
|
31
|
+
:indent=>4,
|
32
|
+
:circular=>true,
|
33
|
+
:mode=>:object,
|
34
|
+
:effort=>:strict }
|
35
|
+
o3 = { :indent => 4 }
|
36
|
+
Oj.default_options = o2
|
37
|
+
opts = Oj.default_options()
|
38
|
+
assert_equal(opts, o2);
|
39
|
+
Oj.default_options = o3 # see if it throws an exception
|
40
|
+
Oj.default_options = orig # return to original
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_nil
|
44
|
+
dump_and_load(nil, false)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_true
|
48
|
+
dump_and_load(true, false)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_false
|
52
|
+
dump_and_load(false, false)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_fixnum
|
56
|
+
dump_and_load(0, false)
|
57
|
+
dump_and_load(12345, false)
|
58
|
+
dump_and_load(-54321, false)
|
59
|
+
dump_and_load(1, false)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_float
|
63
|
+
dump_and_load(0.0, false)
|
64
|
+
dump_and_load(12345.6789, false)
|
65
|
+
dump_and_load(-54321.012, true)
|
66
|
+
dump_and_load(2.48e16, false)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_string
|
70
|
+
dump_and_load('', false)
|
71
|
+
dump_and_load('abc', false)
|
72
|
+
dump_and_load("abc\ndef", false)
|
73
|
+
dump_and_load("a\u0041", false)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_array
|
77
|
+
dump_and_load([], false)
|
78
|
+
dump_and_load([true, false], false)
|
79
|
+
dump_and_load(['a', 1, nil], false)
|
80
|
+
dump_and_load([[nil]], false)
|
81
|
+
dump_and_load([[nil], 58], false)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_hash
|
85
|
+
dump_and_load({}, false)
|
86
|
+
dump_and_load({ 'true' => true, 'false' => false}, false)
|
87
|
+
dump_and_load({ 'true' => true, 'array' => [], 'hash' => { }}, false)
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_encode
|
91
|
+
Oj.default_options = { :encoding => 'UTF-8' }
|
92
|
+
dump_and_load("ぴーたー", false)
|
93
|
+
Oj.default_options = { :encoding => nil }
|
94
|
+
end
|
95
|
+
|
96
|
+
def dump_and_load(obj, trace=false)
|
97
|
+
json = Oj.dump(obj, :indent => 2)
|
98
|
+
puts json if trace
|
99
|
+
loaded = Oj.load(json, :mode => :simple);
|
100
|
+
assert_equal(obj, loaded)
|
101
|
+
loaded
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oj
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,10 +11,7 @@ bindir: bin
|
|
11
11
|
cert_chain: []
|
12
12
|
date: 2012-02-19 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
|
-
description: !
|
15
|
-
lib.\n \nOptimized JSON (Oj), as the name implies was written to provide
|
16
|
-
speed optimized\nJSON handling. It was designed to be an alternative to Yajl and
|
17
|
-
other Ruby\nJSON parsers and as an alternative to Marshal for Object serialization. "
|
14
|
+
description: ! 'The fastest JSON parser and object serializer. '
|
18
15
|
email: peter@ohler.com
|
19
16
|
executables: []
|
20
17
|
extensions:
|
@@ -29,6 +26,10 @@ files:
|
|
29
26
|
- ext/oj/dump.c
|
30
27
|
- ext/oj/load.c
|
31
28
|
- ext/oj/oj.c
|
29
|
+
- test/boo.rb
|
30
|
+
- test/foo.rb
|
31
|
+
- test/perf_simple.rb
|
32
|
+
- test/simple.rb
|
32
33
|
- LICENSE
|
33
34
|
- README.md
|
34
35
|
homepage: https://github.com/ohler55/oj
|