oj 1.4.7 → 2.0.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/README.md +13 -2
- data/ext/oj/cache.c +0 -1
- data/ext/oj/dump.c +3 -1
- data/ext/oj/oj.c +93 -0
- data/ext/oj/oj.h +9 -0
- data/ext/oj/saj.c +812 -0
- data/lib/oj.rb +1 -0
- data/lib/oj/saj.rb +63 -0
- data/lib/oj/version.rb +1 -1
- data/test/a.rb +38 -0
- data/test/perf_saj.rb +109 -0
- data/test/test_fast.rb +0 -1
- data/test/test_saj.rb +186 -0
- metadata +7 -2
data/lib/oj.rb
CHANGED
data/lib/oj/saj.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module Oj
|
2
|
+
# A SAX style parse handler for JSON hence the acronym SAJ for Simple API for JSON. The Oj::Saj handler class should be subclassed
|
3
|
+
# and then used with the Oj.saj_parse() method. The Saj methods will then be
|
4
|
+
# called as the file is parsed.
|
5
|
+
# @example
|
6
|
+
#
|
7
|
+
# require 'oj'
|
8
|
+
#
|
9
|
+
# class MySaj < ::Oj::Saj
|
10
|
+
# def initialize()
|
11
|
+
# @hash_cnt = 0
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# def start_hash(key)
|
15
|
+
# @hash_cnt += 1
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# cnt = MySaj.new()
|
20
|
+
# File.open('any.xml', 'r') do |f|
|
21
|
+
# Oj.saj_parse(cnt, f)
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# To make the desired methods active while parsing the desired method should be made public in the subclasses. If the
|
25
|
+
# methods remain private they will not be called during parsing.
|
26
|
+
#
|
27
|
+
# def hash_start(key); end
|
28
|
+
# def hash_end(key); end
|
29
|
+
# def array_start(key); end
|
30
|
+
# def array_end(key); end
|
31
|
+
# def add_value(value, key); end
|
32
|
+
# def error(message, line, column); end
|
33
|
+
#
|
34
|
+
class Saj
|
35
|
+
# Create a new instance of the Saj handler class.
|
36
|
+
def initialize()
|
37
|
+
end
|
38
|
+
|
39
|
+
# To make the desired methods active while parsing the desired method
|
40
|
+
# should be made public in the subclasses. If the methods remain private
|
41
|
+
# they will not be called during parsing.
|
42
|
+
private
|
43
|
+
|
44
|
+
def hash_start(key)
|
45
|
+
end
|
46
|
+
|
47
|
+
def hash_end(key)
|
48
|
+
end
|
49
|
+
|
50
|
+
def array_start(key)
|
51
|
+
end
|
52
|
+
|
53
|
+
def array_end(key)
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_value(value, key)
|
57
|
+
end
|
58
|
+
|
59
|
+
def error(message, line, column)
|
60
|
+
end
|
61
|
+
|
62
|
+
end # Saj
|
63
|
+
end # Oj
|
data/lib/oj/version.rb
CHANGED
data/test/a.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby -wW1
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
$: << File.dirname(__FILE__)
|
5
|
+
$: << File.join(File.dirname(__FILE__), "../lib")
|
6
|
+
$: << File.join(File.dirname(__FILE__), "../ext")
|
7
|
+
|
8
|
+
require 'pp'
|
9
|
+
require 'oj'
|
10
|
+
require 'perf'
|
11
|
+
|
12
|
+
obj = [[1],[2],[3],[4],[5],[6],[7],[8],[9]]
|
13
|
+
obj = [[],[],[],[],[],[],[],[],[]]
|
14
|
+
obj = {
|
15
|
+
'a' => 'Alpha', # string
|
16
|
+
'b' => true, # boolean
|
17
|
+
'c' => 12345, # number
|
18
|
+
'd' => [ true, [false, [12345, nil], 3.967, ['something', false], nil]], # mix it up array
|
19
|
+
'e' => { 'one' => 1, 'two' => 2 }, # hash
|
20
|
+
'f' => nil, # nil
|
21
|
+
'g' => 12345678901234567890123456789, # big number
|
22
|
+
'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
|
23
|
+
'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
|
24
|
+
}
|
25
|
+
|
26
|
+
json = Oj.dump(obj, mode: :compat)
|
27
|
+
|
28
|
+
puts json
|
29
|
+
#pp Oj.saj_parse(nil, json)
|
30
|
+
pp Oj.t_parse(json)
|
31
|
+
|
32
|
+
if true
|
33
|
+
perf = Perf.new()
|
34
|
+
perf.add('SAJ', 'oj') { Oj.saj_parse(nil, json) }
|
35
|
+
perf.add('T', 'oj') { Oj.t_parse(json) }
|
36
|
+
perf.add('load', 'oj') { Oj.load(json) }
|
37
|
+
perf.run(10000)
|
38
|
+
end
|
data/test/perf_saj.rb
ADDED
@@ -0,0 +1,109 @@
|
|
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 'yajl'
|
10
|
+
require 'perf'
|
11
|
+
require 'json'
|
12
|
+
require 'json/ext'
|
13
|
+
require 'oj'
|
14
|
+
|
15
|
+
$verbose = false
|
16
|
+
$indent = 0
|
17
|
+
$iter = 10000
|
18
|
+
$gets = 0
|
19
|
+
$fetch = false
|
20
|
+
$write = false
|
21
|
+
$read = false
|
22
|
+
|
23
|
+
opts = OptionParser.new
|
24
|
+
opts.on("-v", "verbose") { $verbose = true }
|
25
|
+
opts.on("-c", "--count [Int]", Integer, "iterations") { |i| $iter = i }
|
26
|
+
opts.on("-i", "--indent [Int]", Integer, "indentation") { |i| $indent = i }
|
27
|
+
opts.on("-g", "--gets [Int]", Integer, "number of gets") { |i| $gets = i }
|
28
|
+
opts.on("-f", "fetch") { $fetch = true }
|
29
|
+
opts.on("-w", "write") { $write = true }
|
30
|
+
opts.on("-r", "read") { $read = true }
|
31
|
+
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
|
32
|
+
files = opts.parse(ARGV)
|
33
|
+
|
34
|
+
class AllSaj < Oj::Saj
|
35
|
+
def initialize()
|
36
|
+
end
|
37
|
+
|
38
|
+
def hash_start(key)
|
39
|
+
end
|
40
|
+
|
41
|
+
def hash_end(key)
|
42
|
+
end
|
43
|
+
|
44
|
+
def array_start(key)
|
45
|
+
end
|
46
|
+
|
47
|
+
def array_end(key)
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_value(value, key)
|
51
|
+
end
|
52
|
+
end # AllSaj
|
53
|
+
|
54
|
+
class NoSaj < Oj::Saj
|
55
|
+
def initialize()
|
56
|
+
end
|
57
|
+
end # NoSaj
|
58
|
+
|
59
|
+
saj_handler = AllSaj.new()
|
60
|
+
no_saj = NoSaj.new()
|
61
|
+
|
62
|
+
$obj = {
|
63
|
+
'a' => 'Alpha', # string
|
64
|
+
'b' => true, # boolean
|
65
|
+
'c' => 12345, # number
|
66
|
+
'd' => [ true, [false, {'12345' => 12345, 'nil' => nil}, 3.967, { 'x' => 'something', 'y' => false, 'z' => true}, nil]], # mix it up array
|
67
|
+
'e' => { 'one' => 1, 'two' => 2 }, # hash
|
68
|
+
'f' => nil, # nil
|
69
|
+
'g' => 12345678901234567890123456789, # big number
|
70
|
+
'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
|
71
|
+
'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
|
72
|
+
}
|
73
|
+
|
74
|
+
Oj.default_options = { :indent => $indent, :mode => :compat }
|
75
|
+
|
76
|
+
$json = Oj.dump($obj)
|
77
|
+
$failed = {} # key is same as String used in tests later
|
78
|
+
|
79
|
+
def capture_error(tag, orig, load_key, dump_key, &blk)
|
80
|
+
begin
|
81
|
+
obj = blk.call(orig)
|
82
|
+
raise "#{tag} #{dump_key} and #{load_key} did not return the same object as the original." unless orig == obj
|
83
|
+
rescue Exception => e
|
84
|
+
$failed[tag] = "#{e.class}: #{e.message}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Verify that all packages dump and load correctly and return the same Object as the original.
|
89
|
+
capture_error('Yajl', $obj, 'encode', 'parse') { |o| Yajl::Parser.parse(Yajl::Encoder.encode(o)) }
|
90
|
+
capture_error('JSON::Ext', $obj, 'generate', 'parse') { |o| JSON.generator = JSON::Ext::Generator; JSON::Ext::Parser.new(JSON.generate(o)).parse }
|
91
|
+
|
92
|
+
if $verbose
|
93
|
+
puts "json:\n#{$json}\n"
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
puts '-' * 80
|
98
|
+
puts "Parse Performance"
|
99
|
+
perf = Perf.new()
|
100
|
+
perf.add('Oj::Saj', 'all') { Oj.saj_parse(saj_handler, $json) }
|
101
|
+
perf.add('Oj::Saj', 'none') { Oj.saj_parse(no_saj, $json) }
|
102
|
+
perf.add('Yajl', 'parse') { Yajl::Parser.parse($json) } unless $failed.has_key?('Yajl')
|
103
|
+
perf.add('JSON::Ext', 'parse') { JSON::Ext::Parser.new($json).parse } unless $failed.has_key?('JSON::Ext')
|
104
|
+
perf.run($iter)
|
105
|
+
|
106
|
+
unless $failed.empty?
|
107
|
+
puts "The following packages were not included for the reason listed"
|
108
|
+
$failed.each { |tag,msg| puts "***** #{tag}: #{msg}" }
|
109
|
+
end
|
data/test/test_fast.rb
CHANGED
data/test/test_saj.rb
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
# Ubuntu does not accept arguments to ruby when called using env. To get warnings to show up the -w options is
|
5
|
+
# required. That can be set in the RUBYOPT environment variable.
|
6
|
+
# export RUBYOPT=-w
|
7
|
+
|
8
|
+
$VERBOSE = true
|
9
|
+
|
10
|
+
$: << File.join(File.dirname(__FILE__), "../lib")
|
11
|
+
$: << File.join(File.dirname(__FILE__), "../ext")
|
12
|
+
|
13
|
+
require 'test/unit'
|
14
|
+
require 'oj'
|
15
|
+
require 'pp'
|
16
|
+
|
17
|
+
$json = %{{
|
18
|
+
"array": [
|
19
|
+
{
|
20
|
+
"num" : 3,
|
21
|
+
"string": "message",
|
22
|
+
"hash" : {
|
23
|
+
"h2" : {
|
24
|
+
"a" : [ 1, 2, 3 ]
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
],
|
29
|
+
"boolean" : true
|
30
|
+
}}
|
31
|
+
|
32
|
+
class AllSaj < Oj::Saj
|
33
|
+
attr_accessor :calls
|
34
|
+
|
35
|
+
def initialize()
|
36
|
+
@calls = []
|
37
|
+
end
|
38
|
+
|
39
|
+
def hash_start(key)
|
40
|
+
@calls << [:hash_start, key]
|
41
|
+
end
|
42
|
+
|
43
|
+
def hash_end(key)
|
44
|
+
@calls << [:hash_end, key]
|
45
|
+
end
|
46
|
+
|
47
|
+
def array_start(key)
|
48
|
+
@calls << [:array_start, key]
|
49
|
+
end
|
50
|
+
|
51
|
+
def array_end(key)
|
52
|
+
@calls << [:array_end, key]
|
53
|
+
end
|
54
|
+
|
55
|
+
def add_value(value, key)
|
56
|
+
@calls << [:add_value, value, key]
|
57
|
+
end
|
58
|
+
|
59
|
+
def error(message, line, column)
|
60
|
+
@calls << [:error, message, line, column]
|
61
|
+
end
|
62
|
+
|
63
|
+
end # AllSaj
|
64
|
+
|
65
|
+
class SajTest < ::Test::Unit::TestCase
|
66
|
+
def test_nil
|
67
|
+
handler = AllSaj.new()
|
68
|
+
json = %{null}
|
69
|
+
Oj.saj_parse(handler, json)
|
70
|
+
assert_equal([[:add_value, nil, nil]], handler.calls)
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_true
|
74
|
+
handler = AllSaj.new()
|
75
|
+
json = %{true}
|
76
|
+
Oj.saj_parse(handler, json)
|
77
|
+
assert_equal([[:add_value, true, nil]], handler.calls)
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_false
|
81
|
+
handler = AllSaj.new()
|
82
|
+
json = %{false}
|
83
|
+
Oj.saj_parse(handler, json)
|
84
|
+
assert_equal([[:add_value, false, nil]], handler.calls)
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_string
|
88
|
+
handler = AllSaj.new()
|
89
|
+
json = %{"a string"}
|
90
|
+
Oj.saj_parse(handler, json)
|
91
|
+
assert_equal([[:add_value, 'a string', nil]], handler.calls)
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_fixnum
|
95
|
+
handler = AllSaj.new()
|
96
|
+
json = %{12345}
|
97
|
+
Oj.saj_parse(handler, json)
|
98
|
+
assert_equal([[:add_value, 12345, nil]], handler.calls)
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_float
|
102
|
+
handler = AllSaj.new()
|
103
|
+
json = %{12345.6789}
|
104
|
+
Oj.saj_parse(handler, json)
|
105
|
+
assert_equal([[:add_value, 12345.6789, nil]], handler.calls)
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_float_exp
|
109
|
+
handler = AllSaj.new()
|
110
|
+
json = %{12345.6789e7}
|
111
|
+
Oj.saj_parse(handler, json)
|
112
|
+
assert_equal(1, handler.calls.size)
|
113
|
+
assert_equal(:add_value, handler.calls[0][0])
|
114
|
+
assert_equal((12345.6789e7 * 10000).to_i, (handler.calls[0][1] * 10000).to_i)
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_array_empty
|
118
|
+
handler = AllSaj.new()
|
119
|
+
json = %{[]}
|
120
|
+
Oj.saj_parse(handler, json)
|
121
|
+
assert_equal([[:array_start, nil],
|
122
|
+
[:array_end, nil]], handler.calls)
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_array
|
126
|
+
handler = AllSaj.new()
|
127
|
+
json = %{[true,false]}
|
128
|
+
Oj.saj_parse(handler, json)
|
129
|
+
assert_equal([[:array_start, nil],
|
130
|
+
[:add_value, true, nil],
|
131
|
+
[:add_value, false, nil],
|
132
|
+
[:array_end, nil]], handler.calls)
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_hash_empty
|
136
|
+
handler = AllSaj.new()
|
137
|
+
json = %{{}}
|
138
|
+
Oj.saj_parse(handler, json)
|
139
|
+
assert_equal([[:hash_start, nil],
|
140
|
+
[:hash_end, nil]], handler.calls)
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_hash
|
144
|
+
handler = AllSaj.new()
|
145
|
+
json = %{{"one":true,"two":false}}
|
146
|
+
Oj.saj_parse(handler, json)
|
147
|
+
assert_equal([[:hash_start, nil],
|
148
|
+
[:add_value, true, 'one'],
|
149
|
+
[:add_value, false, 'two'],
|
150
|
+
[:hash_end, nil]], handler.calls)
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_full
|
154
|
+
handler = AllSaj.new()
|
155
|
+
Oj.saj_parse(handler, $json)
|
156
|
+
assert_equal([[:hash_start, nil],
|
157
|
+
[:array_start, 'array'],
|
158
|
+
[:hash_start, nil],
|
159
|
+
[:add_value, 3, 'num'],
|
160
|
+
[:add_value, 'message', 'string'],
|
161
|
+
[:hash_start, 'hash'],
|
162
|
+
[:hash_start, 'h2'],
|
163
|
+
[:array_start, 'a'],
|
164
|
+
[:add_value, 1, nil],
|
165
|
+
[:add_value, 2, nil],
|
166
|
+
[:add_value, 3, nil],
|
167
|
+
[:array_end, 'a'],
|
168
|
+
[:hash_end, 'h2'],
|
169
|
+
[:hash_end, 'hash'],
|
170
|
+
[:hash_end, nil],
|
171
|
+
[:array_end, 'array'],
|
172
|
+
[:add_value, true, 'boolean'],
|
173
|
+
[:hash_end, nil]], handler.calls)
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_fixnum_bad
|
177
|
+
handler = AllSaj.new()
|
178
|
+
json = %{12345xyz}
|
179
|
+
Oj.saj_parse(handler, json)
|
180
|
+
assert_equal([[:add_value, 12345, nil],
|
181
|
+
[:error, "invalid format, extra characters at line 1, column 6 [saj.c:716]", 1, 6]], handler.calls)
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
|
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:
|
4
|
+
version: 2.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-18 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! 'The fastest JSON parser and object serializer. '
|
15
15
|
email: peter@ohler.com
|
@@ -22,6 +22,7 @@ files:
|
|
22
22
|
- lib/oj/bag.rb
|
23
23
|
- lib/oj/error.rb
|
24
24
|
- lib/oj/mimic.rb
|
25
|
+
- lib/oj/saj.rb
|
25
26
|
- lib/oj/version.rb
|
26
27
|
- lib/oj.rb
|
27
28
|
- ext/oj/extconf.rb
|
@@ -35,6 +36,8 @@ files:
|
|
35
36
|
- ext/oj/fast.c
|
36
37
|
- ext/oj/load.c
|
37
38
|
- ext/oj/oj.c
|
39
|
+
- ext/oj/saj.c
|
40
|
+
- test/a.rb
|
38
41
|
- test/files.rb
|
39
42
|
- test/perf.rb
|
40
43
|
- test/perf1.rb
|
@@ -42,6 +45,7 @@ files:
|
|
42
45
|
- test/perf_fast.rb
|
43
46
|
- test/perf_obj.rb
|
44
47
|
- test/perf_obj_old.rb
|
48
|
+
- test/perf_saj.rb
|
45
49
|
- test/perf_simple.rb
|
46
50
|
- test/perf_strict.rb
|
47
51
|
- test/sample/change.rb
|
@@ -60,6 +64,7 @@ files:
|
|
60
64
|
- test/sample_json.rb
|
61
65
|
- test/test_fast.rb
|
62
66
|
- test/test_mimic.rb
|
67
|
+
- test/test_saj.rb
|
63
68
|
- test/tests.rb
|
64
69
|
- LICENSE
|
65
70
|
- README.md
|