oj 2.9.0 → 2.9.1

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.

@@ -145,7 +145,11 @@ oj_strict_parse(int argc, VALUE *argv, VALUE self) {
145
145
  pi.options = oj_default_options;
146
146
  oj_set_strict_callbacks(&pi);
147
147
 
148
- return oj_pi_parse(argc, argv, &pi, 0, 0);
148
+ if (T_STRING == rb_type(*argv)) {
149
+ return oj_pi_parse(argc, argv, &pi, 0, 0, 1);
150
+ } else {
151
+ return oj_pi_sparse(argc, argv, &pi, 0);
152
+ }
149
153
  }
150
154
 
151
155
  VALUE
@@ -155,5 +159,5 @@ oj_strict_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
155
159
  pi.options = oj_default_options;
156
160
  oj_set_strict_callbacks(&pi);
157
161
 
158
- return oj_pi_parse(argc, argv, &pi, json, len);
162
+ return oj_pi_parse(argc, argv, &pi, json, len, 1);
159
163
  }
@@ -55,6 +55,7 @@ typedef enum {
55
55
  typedef struct _Val {
56
56
  VALUE val;
57
57
  const char *key;
58
+ char karray[32];
58
59
  union {
59
60
  const char *classname;
60
61
  OddArgs odd_args;
@@ -63,6 +64,7 @@ typedef struct _Val {
63
64
  uint16_t clen;
64
65
  char next; // ValNext
65
66
  char k1; // first original character in the key
67
+ char kalloc;
66
68
  } *Val;
67
69
 
68
70
  typedef struct _ValStack {
@@ -127,6 +129,7 @@ stack_push(ValStack stack, VALUE val, ValNext next) {
127
129
  stack->tail->key = 0;
128
130
  stack->tail->clen = 0;
129
131
  stack->tail->klen = 0;
132
+ stack->tail->kalloc = 0;
130
133
  stack->tail++;
131
134
  }
132
135
 
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '2.9.0'
4
+ VERSION = '2.9.1'
5
5
  end
@@ -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
@@ -0,0 +1,17 @@
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 'oj'
14
+
15
+ obj = Oj.load_file('bug.json', :mode => :object)
16
+
17
+ puts Oj.dump(obj, :mode => :object, :indent => 0)
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.join(File.dirname(__FILE__), "../lib")
4
+ $: << File.join(File.dirname(__FILE__), "../ext")
5
+
6
+ require 'oj'
7
+
8
+ json = %{"\xc2\xa9\xc3\x98"}
9
+ puts "original:\n#{json}"
10
+
11
+ str = Oj.load(json)
12
+ puts "out: #{str}"
@@ -0,0 +1,24 @@
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 'oj'
14
+
15
+ class Foo < String
16
+ def initialize(str, safe)
17
+ super(str)
18
+ @safe = safe
19
+ end
20
+ end
21
+
22
+ f = Foo.new("z")
23
+
24
+ puts f
@@ -0,0 +1,68 @@
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 'oj'
14
+
15
+ module One
16
+ module Two
17
+ module Three
18
+ class Empty
19
+
20
+ def initialize()
21
+ end
22
+
23
+ def eql?(o)
24
+ self.class == o.class
25
+ end
26
+ alias == eql?
27
+
28
+ def to_hash()
29
+ {'json_class' => "#{self.class.name}"}
30
+ end
31
+
32
+ def to_json(*a)
33
+ %{{"json_class":"#{self.class.name}"}}
34
+ end
35
+
36
+ def self.json_create(h)
37
+ self.new()
38
+ end
39
+ end # Empty
40
+ end # Three
41
+ end # Two
42
+ end # One
43
+
44
+ $obj = {
45
+ 'a' => 'Alpha', # string
46
+ 'b' => true, # boolean
47
+ 'c' => 12345, # number
48
+ 'd' => [ true, [false, [-123456789, nil], 3.9676, ['Something else.', false], nil]], # mix it up array
49
+ 'e' => { 'zero' => nil, 'one' => 1, 'two' => 2, 'three' => [3], 'four' => [0, 1, 2, 3, 4] }, # hash
50
+ 'f' => nil, # nil
51
+ 'g' => One::Two::Three::Empty.new(),
52
+ 'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
53
+ 'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
54
+ }
55
+
56
+ $obj = [$obj]*10000
57
+
58
+ Oj.default_options = { :indent => 2, :mode => :compat }
59
+
60
+ $json = Oj.dump($obj, :mode => :compat)
61
+
62
+ $result = nil
63
+ 100.times { |i|
64
+ print(".") if (0 == i % 10)
65
+ $result = Oj.compat_load($json)
66
+ }
67
+
68
+
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ $: << File.join(File.dirname(__FILE__), "../lib")
5
+ $: << File.join(File.dirname(__FILE__), "../ext")
6
+ # $: << File.join(File.dirname(__FILE__), "../../multi_json/lib")
7
+
8
+ require 'multi_json'
9
+ require 'benchmark'
10
+ require 'yajl'
11
+ require 'json'
12
+ require 'oj'
13
+
14
+ iter = 1_000_000
15
+ iter = 100_000
16
+
17
+ json = %({"k1":"val1","k2":"val2","k3":"val3"})
18
+ obj = { k1: "val1", k2: "val2", k3: "val3" }
19
+
20
+ puts "Benchmarks for different JSON handlers with MultiJson."
21
+ puts " Ruby #{RUBY_VERSION}"
22
+ puts " #{iter} iterations"
23
+
24
+ MultiJson.engine = :oj
25
+ dt = Benchmark.realtime { iter.times { MultiJson.decode(json) }}
26
+ et = Benchmark.realtime { iter.times { MultiJson.encode(obj) }}
27
+ puts " Oj decode: #{dt} encode: #{et}"
28
+
29
+ MultiJson.engine = :yajl
30
+ dt = Benchmark.realtime { iter.times { MultiJson.decode(json) }}
31
+ et = Benchmark.realtime { iter.times { MultiJson.encode(obj) }}
32
+ puts " Yajl decode: #{dt} encode: #{et}"
33
+
34
+ MultiJson.engine = :json_gem
35
+ dt = Benchmark.realtime { iter.times { MultiJson.decode(json) }}
36
+ et = Benchmark.realtime { iter.times { MultiJson.encode(obj) }}
37
+ puts " Json decode: #{dt} encode: #{et}"
38
+
39
+ Oj.default_options = { :mode => :compat, :time_format => :ruby }
40
+ dt = Benchmark.realtime { iter.times { Oj.load(json) }}
41
+ et = Benchmark.realtime { iter.times { Oj.dump(obj) }}
42
+ puts "Raw Oj decode: #{dt} encode: #{et}"
43
+
44
+ ye = Yajl::Encoder.new
45
+ dt = Benchmark.realtime { iter.times { Yajl::Parser.parse(json) }}
46
+ et = Benchmark.realtime { iter.times { Yajl::Encoder.encode(obj) }}
47
+ e2 = Benchmark.realtime { iter.times { ye.encode(obj) }}
48
+ puts "Raw Yajl decode: #{dt} encode: #{et}, encoder: #{e2}"
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby -wW1
2
+
3
+ $: << '.'
4
+ $: << '../lib'
5
+ $: << '../ext'
6
+
7
+ if __FILE__ == $0
8
+ if (i = ARGV.index('-I'))
9
+ x,path = ARGV.slice!(i, 2)
10
+ $: << path
11
+ end
12
+ end
13
+
14
+ require 'optparse'
15
+ require 'oj'
16
+ require 'perf'
17
+
18
+ $indent = 0
19
+ $iter = 1
20
+ $size = 1
21
+
22
+ opts = OptionParser.new
23
+
24
+ opts.on("-r", "read") { do_read = true }
25
+ opts.on("-c", "--count [Int]", Integer, "iterations") { |i| $iter = i }
26
+ opts.on("-i", "--indent [Int]", Integer, "indent") { |i| $indent = i }
27
+ opts.on("-s", "--size [Int]", Integer, "size in Mbytes") { |s| $size = s }
28
+
29
+ opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
30
+ files = opts.parse(ARGV)
31
+
32
+ $obj = {
33
+ 'a' => 'Alpha', # string
34
+ 'b' => true, # boolean
35
+ 'c' => 12345, # number
36
+ 'd' => [ true, [false, [-123456789, nil], 3.9676, ['Something else.', false], nil]], # mix it up array
37
+ 'e' => { 'zero' => nil, 'one' => 1, 'two' => 2, 'three' => [3], 'four' => [0, 1, 2, 3, 4] }, # hash
38
+ 'f' => nil, # nil
39
+ 'g' => 12345678901234567890123456789, #_bignum
40
+ 'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
41
+ 'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
42
+ }
43
+
44
+ json = Oj.dump($obj, :indent => $indent)
45
+ cnt = ($size * 1024 * 1024 + json.size) / json.size
46
+ cnt = 1 if 0 == $size
47
+
48
+ filename = 'tmp.json'
49
+ File.open(filename, "w") { |f|
50
+ cnt.times do
51
+ Oj.to_stream(f, $obj, :indent => $indent)
52
+ end
53
+ }
54
+
55
+ Oj.default_options = { :mode => :strict, :indent => $indent }
56
+
57
+ puts '-' * 80
58
+ puts "Read from #{cnt * json.size / (1024 * 1024)} Mb file Performance"
59
+ perf = Perf.new()
60
+ perf.add('Oj.load_file', '') { Oj.load_file(filename) }
61
+ perf.add('Oj.load(string)', '') { Oj.load(File.read(filename)) }
62
+ perf.add('Oj.load(file)', '') { File.open(filename, 'r') { |f| Oj.load(f) } }
63
+ perf.run($iter)
64
+
@@ -74,7 +74,7 @@ if files.empty?
74
74
 
75
75
  $mars = Marshal.dump($obj)
76
76
  $xml = Ox.dump($obj, :indent => $indent, :circular => $circular)
77
- $json = Oj.dump($obj, :indent => $indent, :circular => $circular)
77
+ $json = Oj.dump($obj, :indent => $indent, :circular => $circular, :mode => :object)
78
78
  File.open('sample.xml', 'w') { |f| f.write($xml) }
79
79
  File.open('sample.json', 'w') { |f| f.write($json) }
80
80
  File.open('sample.marshal', 'w') { |f| f.write($mars) }
@@ -119,6 +119,7 @@ if do_read
119
119
  puts "Read from file Performance"
120
120
  perf = Perf.new()
121
121
  perf.add('Oj', 'load') { Oj.load_file('sample.json') }
122
+ #perf.add('Oj', 'load') { Oj.load(File.read('sample.json')) }
122
123
  perf.add('Ox', 'load_file') { Ox.load_file('sample.xml', :mode => :object) }
123
124
  perf.add('Marshal', 'load') { Marshal.load(File.new('sample.marshal')) }
124
125
  perf.run($iter)
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby -wW1
2
+
3
+ $: << '.'
4
+ $: << '../lib'
5
+ $: << '../ext'
6
+
7
+ if __FILE__ == $0
8
+ if (i = ARGV.index('-I'))
9
+ x,path = ARGV.slice!(i, 2)
10
+ $: << path
11
+ end
12
+ end
13
+
14
+ require 'optparse'
15
+ require 'ox'
16
+ require 'oj'
17
+ require 'perf'
18
+
19
+ $indent = 0
20
+ $iter = 1000
21
+
22
+ opts = OptionParser.new
23
+
24
+ opts.on("-i", "--iterations [Int]", Integer, "iterations") { |i| $iter = i }
25
+ opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
26
+ files = opts.parse(ARGV)
27
+
28
+ $obj = "x" * 50_000
29
+
30
+ Oj.default_options = { :mode => :strict, :indent => $indent }
31
+
32
+ puts '-' * 80
33
+ puts "Dump Performance"
34
+ perf = Perf.new()
35
+ perf.add('Oj', 'dump') { Oj.dump($obj) }
36
+ perf.add('Ox', 'dump') { Ox.dump($obj, :indent => $indent, :circular => $circular) }
37
+ perf.add('Marshal', 'dump') { Marshal.dump($obj) }
38
+ perf.run($iter)
@@ -0,0 +1,97 @@
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 'stringio'
9
+ require 'optparse'
10
+ require 'perf'
11
+ require 'oj'
12
+
13
+ $verbose = false
14
+ $indent = 0
15
+ $iter = 20000
16
+ $with_bignum = false
17
+ $with_nums = true
18
+ $size = 0
19
+
20
+ opts = OptionParser.new
21
+ opts.on("-v", "verbose") { $verbose = true }
22
+ opts.on("-c", "--count [Int]", Integer, "iterations") { |i| $iter = i }
23
+ opts.on("-i", "--indent [Int]", Integer, "indentation") { |i| $indent = i }
24
+ opts.on("-s", "--size [Int]", Integer, "size (~Kbytes)") { |i| $size = i }
25
+ opts.on("-b", "with bignum") { $with_bignum = true }
26
+ opts.on("-n", "without numbers") { $with_nums = false }
27
+ opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
28
+ files = opts.parse(ARGV)
29
+
30
+ if $with_nums
31
+ $obj = {
32
+ 'a' => 'Alpha', # string
33
+ 'b' => true, # boolean
34
+ 'c' => 12345, # number
35
+ 'd' => [ true, [false, [-123456789, nil], 3.9676, ['Something else.', false], nil]], # mix it up array
36
+ 'e' => { 'zero' => nil, 'one' => 1, 'two' => 2, 'three' => [3], 'four' => [0, 1, 2, 3, 4] }, # hash
37
+ 'f' => nil, # nil
38
+ 'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
39
+ 'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
40
+ }
41
+ $obj['g'] = 12345678901234567890123456789 if $with_bignum
42
+ else
43
+ $obj = {
44
+ 'a' => 'Alpha',
45
+ 'b' => true,
46
+ 'c' => '12345',
47
+ 'd' => [ true, [false, ['12345', nil], '3.967', ['something', false], nil]],
48
+ 'e' => { 'zero' => '0', 'one' => '1', 'two' => '2' },
49
+ 'f' => nil,
50
+ 'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
51
+ 'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
52
+ }
53
+ end
54
+
55
+ Oj.default_options = { :indent => $indent, :mode => :strict }
56
+
57
+ if 0 < $size
58
+ o = $obj
59
+ $obj = []
60
+ (4 * $size).times do
61
+ $obj << o
62
+ end
63
+ end
64
+
65
+ $json = Oj.dump($obj)
66
+ $obj_json = Oj.dump($obj, :mode => :object)
67
+ #puts "*** size: #{$obj_json.size}"
68
+ $failed = {} # key is same as String used in tests later
69
+
70
+ def capture_error(tag, orig, load_key, dump_key, &blk)
71
+ begin
72
+ obj = blk.call(orig)
73
+ raise "#{tag} #{dump_key} and #{load_key} did not return the same object as the original." unless orig == obj
74
+ rescue Exception => e
75
+ $failed[tag] = "#{e.class}: #{e.message}"
76
+ end
77
+ end
78
+
79
+ # Verify that all packages dump and load correctly and return the same Object as the original.
80
+ capture_error('Oj:strict-str', $obj, 'load', 'dump') { |o| Oj.strict_load(Oj.dump(o, :mode => :strict)) }
81
+ capture_error('Oj:strict', $obj, 'load', 'dump') { |o| Oj.strict_load(StringIO.new(Oj.dump(o, :mode => :strict))) }
82
+
83
+ puts '-' * 80
84
+ puts "Strict Parse Performance"
85
+ perf = Perf.new()
86
+ perf.add('Oj:strict-str', 'strict_load-str') { Oj.strict_load($json) }
87
+ perf.add('Oj:strict-io', 'strict_load') { Oj.strict_load(StringIO.new($json)) }
88
+ perf.run($iter)
89
+
90
+ puts
91
+ puts '-' * 80
92
+ puts
93
+
94
+ unless $failed.empty?
95
+ puts "The following packages were not included for the reason listed"
96
+ $failed.each { |tag,msg| puts "***** #{tag}: #{msg}" }
97
+ end