oj 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +17 -23
  3. data/README.md +74 -425
  4. data/ext/oj/buf.h +103 -0
  5. data/ext/oj/cache8.c +4 -0
  6. data/ext/oj/circarray.c +68 -0
  7. data/ext/oj/circarray.h +23 -0
  8. data/ext/oj/code.c +227 -0
  9. data/ext/oj/code.h +40 -0
  10. data/ext/oj/compat.c +243 -0
  11. data/ext/oj/custom.c +1097 -0
  12. data/ext/oj/dump.c +766 -1534
  13. data/ext/oj/dump.h +92 -0
  14. data/ext/oj/dump_compat.c +937 -0
  15. data/ext/oj/dump_leaf.c +254 -0
  16. data/ext/oj/dump_object.c +810 -0
  17. data/ext/oj/dump_rails.c +329 -0
  18. data/ext/oj/dump_strict.c +416 -0
  19. data/ext/oj/encode.h +51 -0
  20. data/ext/oj/err.c +57 -0
  21. data/ext/oj/err.h +70 -0
  22. data/ext/oj/extconf.rb +17 -7
  23. data/ext/oj/fast.c +213 -180
  24. data/ext/oj/hash.c +163 -0
  25. data/ext/oj/hash.h +46 -0
  26. data/ext/oj/hash_test.c +512 -0
  27. data/ext/oj/mimic_json.c +817 -0
  28. data/ext/oj/mimic_rails.c +806 -0
  29. data/ext/oj/mimic_rails.h +17 -0
  30. data/ext/oj/object.c +752 -0
  31. data/ext/oj/odd.c +230 -0
  32. data/ext/oj/odd.h +44 -0
  33. data/ext/oj/oj.c +1288 -929
  34. data/ext/oj/oj.h +240 -69
  35. data/ext/oj/parse.c +1014 -0
  36. data/ext/oj/parse.h +92 -0
  37. data/ext/oj/reader.c +223 -0
  38. data/ext/oj/reader.h +151 -0
  39. data/ext/oj/resolve.c +127 -0
  40. data/ext/oj/{cache.h → resolve.h} +6 -13
  41. data/ext/oj/rxclass.c +133 -0
  42. data/ext/oj/rxclass.h +27 -0
  43. data/ext/oj/saj.c +77 -175
  44. data/ext/oj/scp.c +224 -0
  45. data/ext/oj/sparse.c +911 -0
  46. data/ext/oj/stream_writer.c +301 -0
  47. data/ext/oj/strict.c +162 -0
  48. data/ext/oj/string_writer.c +480 -0
  49. data/ext/oj/val_stack.c +98 -0
  50. data/ext/oj/val_stack.h +188 -0
  51. data/lib/oj/active_support_helper.rb +41 -0
  52. data/lib/oj/bag.rb +6 -10
  53. data/lib/oj/easy_hash.rb +52 -0
  54. data/lib/oj/json.rb +172 -0
  55. data/lib/oj/mimic.rb +260 -5
  56. data/lib/oj/saj.rb +13 -10
  57. data/lib/oj/schandler.rb +142 -0
  58. data/lib/oj/state.rb +131 -0
  59. data/lib/oj/version.rb +1 -1
  60. data/lib/oj.rb +11 -23
  61. data/pages/Advanced.md +22 -0
  62. data/pages/Compatibility.md +25 -0
  63. data/pages/Custom.md +23 -0
  64. data/pages/Encoding.md +65 -0
  65. data/pages/JsonGem.md +79 -0
  66. data/pages/Modes.md +140 -0
  67. data/pages/Options.md +250 -0
  68. data/pages/Rails.md +60 -0
  69. data/pages/Security.md +20 -0
  70. data/test/_test_active.rb +76 -0
  71. data/test/_test_active_mimic.rb +96 -0
  72. data/test/_test_mimic_rails.rb +126 -0
  73. data/test/activesupport4/decoding_test.rb +105 -0
  74. data/test/activesupport4/encoding_test.rb +531 -0
  75. data/test/activesupport4/test_helper.rb +41 -0
  76. data/test/activesupport5/decoding_test.rb +125 -0
  77. data/test/activesupport5/encoding_test.rb +483 -0
  78. data/test/activesupport5/encoding_test_cases.rb +90 -0
  79. data/test/activesupport5/test_helper.rb +50 -0
  80. data/test/activesupport5/time_zone_test_helpers.rb +24 -0
  81. data/test/helper.rb +27 -0
  82. data/test/isolated/shared.rb +310 -0
  83. data/test/isolated/test_mimic_after.rb +13 -0
  84. data/test/isolated/test_mimic_alone.rb +12 -0
  85. data/test/isolated/test_mimic_as_json.rb +45 -0
  86. data/test/isolated/test_mimic_before.rb +13 -0
  87. data/test/isolated/test_mimic_define.rb +28 -0
  88. data/test/isolated/test_mimic_rails_after.rb +22 -0
  89. data/test/isolated/test_mimic_rails_before.rb +21 -0
  90. data/test/isolated/test_mimic_redefine.rb +15 -0
  91. data/test/json_gem/json_addition_test.rb +216 -0
  92. data/test/json_gem/json_common_interface_test.rb +143 -0
  93. data/test/json_gem/json_encoding_test.rb +109 -0
  94. data/test/json_gem/json_ext_parser_test.rb +20 -0
  95. data/test/json_gem/json_fixtures_test.rb +35 -0
  96. data/test/json_gem/json_generator_test.rb +383 -0
  97. data/test/json_gem/json_generic_object_test.rb +90 -0
  98. data/test/json_gem/json_parser_test.rb +470 -0
  99. data/test/json_gem/json_string_matching_test.rb +42 -0
  100. data/test/json_gem/test_helper.rb +18 -0
  101. data/test/perf_compat.rb +130 -0
  102. data/test/perf_fast.rb +9 -9
  103. data/test/perf_file.rb +64 -0
  104. data/test/{perf_obj.rb → perf_object.rb} +24 -10
  105. data/test/perf_scp.rb +151 -0
  106. data/test/perf_strict.rb +32 -113
  107. data/test/sample.rb +2 -3
  108. data/test/test_compat.rb +474 -0
  109. data/test/test_custom.rb +355 -0
  110. data/test/test_debian.rb +53 -0
  111. data/test/test_fast.rb +66 -16
  112. data/test/test_file.rb +237 -0
  113. data/test/test_gc.rb +49 -0
  114. data/test/test_hash.rb +29 -0
  115. data/test/test_null.rb +376 -0
  116. data/test/test_object.rb +1010 -0
  117. data/test/test_saj.rb +16 -16
  118. data/test/test_scp.rb +417 -0
  119. data/test/test_strict.rb +410 -0
  120. data/test/test_various.rb +815 -0
  121. data/test/test_writer.rb +308 -0
  122. data/test/tests.rb +9 -902
  123. data/test/tests_mimic.rb +14 -0
  124. data/test/tests_mimic_addition.rb +7 -0
  125. metadata +253 -38
  126. data/ext/oj/cache.c +0 -148
  127. data/ext/oj/foo.rb +0 -6
  128. data/ext/oj/load.c +0 -1049
  129. data/test/a.rb +0 -38
  130. data/test/perf1.rb +0 -64
  131. data/test/perf2.rb +0 -76
  132. data/test/perf_obj_old.rb +0 -213
  133. data/test/test_mimic.rb +0 -208
data/test/perf_fast.rb CHANGED
@@ -6,7 +6,7 @@ $: << File.join(File.dirname(__FILE__), "../lib")
6
6
  $: << File.join(File.dirname(__FILE__), "../ext")
7
7
 
8
8
  require 'optparse'
9
- require 'yajl'
9
+ #require 'yajl'
10
10
  require 'perf'
11
11
  require 'json'
12
12
  require 'json/ext'
@@ -14,7 +14,7 @@ require 'oj'
14
14
 
15
15
  $verbose = false
16
16
  $indent = 0
17
- $iter = 10000
17
+ $iter = 100000
18
18
  $gets = 0
19
19
  $fetch = false
20
20
  $write = false
@@ -71,7 +71,7 @@ end
71
71
 
72
72
  # Verify that all packages dump and load correctly and return the same Object as the original.
73
73
  capture_error('Oj::Doc', $obj, 'load', 'dump') { |o| Oj::Doc.open(Oj.dump(o, :mode => :strict)) { |f| f.fetch() } }
74
- capture_error('Yajl', $obj, 'encode', 'parse') { |o| Yajl::Parser.parse(Yajl::Encoder.encode(o)) }
74
+ #capture_error('Yajl', $obj, 'encode', 'parse') { |o| Yajl::Parser.parse(Yajl::Encoder.encode(o)) }
75
75
  capture_error('JSON::Ext', $obj, 'generate', 'parse') { |o| JSON.generator = JSON::Ext::Generator; JSON::Ext::Parser.new(JSON.generate(o)).parse }
76
76
 
77
77
  if $verbose
@@ -82,7 +82,7 @@ puts '-' * 80
82
82
  puts "Parse Performance"
83
83
  perf = Perf.new()
84
84
  perf.add('Oj::Doc', 'parse') { Oj::Doc.open($json) {|f| } } unless $failed.has_key?('Oj::Doc')
85
- perf.add('Yajl', 'parse') { Yajl::Parser.parse($json) } unless $failed.has_key?('Yajl')
85
+ #perf.add('Yajl', 'parse') { Yajl::Parser.parse($json) } unless $failed.has_key?('Yajl')
86
86
  perf.add('JSON::Ext', 'parse') { JSON::Ext::Parser.new($json).parse } unless $failed.has_key?('JSON::Ext')
87
87
  perf.run($iter)
88
88
 
@@ -91,7 +91,7 @@ puts "JSON generation Performance"
91
91
  Oj::Doc.open($json) do |doc|
92
92
  perf = Perf.new()
93
93
  perf.add('Oj::Doc', 'dump') { doc.dump() }
94
- perf.add('Yajl', 'encode') { Yajl::Encoder.encode($obj) }
94
+ # perf.add('Yajl', 'encode') { Yajl::Encoder.encode($obj) }
95
95
  perf.add('JSON::Ext', 'fast_generate') { JSON.fast_generate($obj) }
96
96
  perf.before('JSON::Ext') { JSON.generator = JSON::Ext::Generator }
97
97
  perf.run($iter)
@@ -102,7 +102,7 @@ if 0 < $gets
102
102
  puts "Parse and get all values Performance"
103
103
  perf = Perf.new()
104
104
  perf.add('Oj::Doc', 'parse') { Oj::Doc.open($json) {|f| $gets.times { f.each_value() {} } } } unless $failed.has_key?('Oj::Doc')
105
- perf.add('Yajl', 'parse') { $gets.times { dig(Yajl::Parser.parse($json)) {} } } unless $failed.has_key?('Yajl')
105
+ # perf.add('Yajl', 'parse') { $gets.times { dig(Yajl::Parser.parse($json)) {} } } unless $failed.has_key?('Yajl')
106
106
  perf.add('JSON::Ext', 'parse') { $gets.times { dig(JSON::Ext::Parser.new($json).parse) {} } } unless $failed.has_key?('JSON::Ext')
107
107
  perf.run($iter)
108
108
  end
@@ -134,7 +134,7 @@ if $write
134
134
  Oj::Doc.open($json) do |doc|
135
135
  perf = Perf.new()
136
136
  perf.add('Oj::Doc', 'dump') { doc.dump(nil, 'oj.json') }
137
- perf.add('Yajl', 'encode') { File.open('yajl.json', 'w') { |f| Yajl::Encoder.encode($obj, f) } }
137
+ # perf.add('Yajl', 'encode') { File.open('yajl.json', 'w') { |f| Yajl::Encoder.encode($obj, f) } }
138
138
  perf.add('JSON::Ext', 'fast_generate') { File.open('json_ext.json', 'w') { |f| f.write(JSON.fast_generate($obj)) } }
139
139
  perf.before('JSON::Ext') { JSON.generator = JSON::Ext::Generator }
140
140
  perf.run($iter)
@@ -145,13 +145,13 @@ if $read
145
145
  puts '-' * 80
146
146
  puts "JSON read from file Performance"
147
147
  Oj::Doc.open($json) { |doc| doc.dump(nil, 'oj.json') }
148
- File.open('yajl.json', 'w') { |f| Yajl::Encoder.encode($obj, f) }
148
+ # File.open('yajl.json', 'w') { |f| Yajl::Encoder.encode($obj, f) }
149
149
  JSON.generator = JSON::Ext::Generator
150
150
  File.open('json_ext.json', 'w') { |f| f.write(JSON.fast_generate($obj)) }
151
151
  Oj::Doc.open($json) do |doc|
152
152
  perf = Perf.new()
153
153
  perf.add('Oj::Doc', 'open_file') { ::Oj::Doc.open_file('oj.json') }
154
- perf.add('Yajl', 'decode') { Yajl::decoder.decode(File.read('yajl.json')) }
154
+ # perf.add('Yajl', 'decode') { Yajl::decoder.decode(File.read('yajl.json')) }
155
155
  perf.add('JSON::Ext', '') { JSON.parse(File.read('json_ext.json')) }
156
156
  perf.before('JSON::Ext') { JSON.parser = JSON::Ext::Parser }
157
157
  perf.run($iter)
data/test/perf_file.rb ADDED
@@ -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
+
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby -wW1
1
+ #!/usr/bin/env ruby
2
2
 
3
3
  $: << '.'
4
4
  $: << '../lib'
@@ -20,6 +20,7 @@ require 'files'
20
20
 
21
21
  $circular = false
22
22
  $indent = 0
23
+ $allow_gc = true
23
24
 
24
25
  do_sample = false
25
26
  do_files = false
@@ -29,10 +30,14 @@ do_dump = false
29
30
  do_read = false
30
31
  do_write = false
31
32
  $iter = 1000
33
+ $mult = 1
32
34
 
33
35
  opts = OptionParser.new
34
36
  opts.on("-c", "circular options") { $circular = true }
35
37
 
38
+ opts.on("-x", "use sample instead of files") { do_sample = true }
39
+ opts.on("-g", "no GC during parsing") { $allow_gc = false }
40
+
36
41
  opts.on("-s", "load and dump as sample Ruby object") { do_sample = true }
37
42
  opts.on("-f", "load and dump as files Ruby object") { do_files = true }
38
43
 
@@ -43,6 +48,7 @@ opts.on("-w", "write") { do_write = true }
43
48
  opts.on("-a", "load, dump, read and write") { do_load = true; do_dump = true; do_read = true; do_write = true }
44
49
 
45
50
  opts.on("-i", "--iterations [Int]", Integer, "iterations") { |i| $iter = i }
51
+ opts.on("-m", "--multiply [Int]", Integer, "multiplier") { |i| $mult = i }
46
52
 
47
53
  opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
48
54
  files = opts.parse(ARGV)
@@ -61,32 +67,39 @@ end
61
67
 
62
68
  # prepare all the formats for input
63
69
  if files.empty?
64
- $obj = do_sample ? sample_doc(2) : files('..')
70
+ $obj = []
71
+ $mult.times do
72
+ $obj << (do_sample ? sample_doc(2) : files('..'))
73
+ end
74
+
65
75
  $mars = Marshal.dump($obj)
66
76
  $xml = Ox.dump($obj, :indent => $indent, :circular => $circular)
67
- $json = Oj.dump($obj, :indent => $indent, :circular => $circular)
77
+ $json = Oj.dump($obj, :indent => $indent, :circular => $circular, :mode => :object)
68
78
  File.open('sample.xml', 'w') { |f| f.write($xml) }
69
79
  File.open('sample.json', 'w') { |f| f.write($json) }
70
80
  File.open('sample.marshal', 'w') { |f| f.write($mars) }
71
81
  else
72
82
  puts "loading and parsing #{files}\n\n"
73
- # TBD change to allow xml and json
74
83
  data = files.map do |f|
75
84
  $xml = File.read(f)
76
85
  $obj = Ox.load($xml);
77
86
  $mars = Marshal.dump($obj)
78
- $json = Oj.dump($obj, :indent => $indent, circular: $circular)
87
+ $json = Oj.dump($obj, :indent => $indent, :circular => $circular)
79
88
  end
80
89
  end
81
90
 
82
- Oj.default_options = { :mode => :object, :indent => $indent, :circular => $circular }
91
+ Oj.default_options = { :mode => :object, :indent => $indent, :circular => $circular, :allow_gc => $allow_gc }
92
+ #puts "json: #{$json.size}"
93
+ #puts "xml: #{$xml.size}"
94
+ #puts "marshal: #{$mars.size}"
95
+
83
96
 
84
97
  if do_load
85
98
  puts '-' * 80
86
99
  puts "Load Performance"
87
100
  perf = Perf.new()
101
+ perf.add('Oj.object', 'load') { Oj.object_load($json) }
88
102
  perf.add('Ox', 'load') { Ox.load($xml, :mode => :object) }
89
- perf.add('Oj', 'load') { Oj.load($json) }
90
103
  perf.add('Marshal', 'load') { Marshal.load($mars) }
91
104
  perf.run($iter)
92
105
  end
@@ -95,8 +108,8 @@ if do_dump
95
108
  puts '-' * 80
96
109
  puts "Dump Performance"
97
110
  perf = Perf.new()
98
- perf.add('Ox', 'dump') { Ox.dump($obj, :indent => $indent, :circular => $circular) }
99
111
  perf.add('Oj', 'dump') { Oj.dump($obj) }
112
+ perf.add('Ox', 'dump') { Ox.dump($obj, :indent => $indent, :circular => $circular) }
100
113
  perf.add('Marshal', 'dump') { Marshal.dump($obj) }
101
114
  perf.run($iter)
102
115
  end
@@ -105,8 +118,9 @@ if do_read
105
118
  puts '-' * 80
106
119
  puts "Read from file Performance"
107
120
  perf = Perf.new()
108
- perf.add('Ox', 'load_file') { Ox.load_file('sample.xml', :mode => :object) }
109
121
  perf.add('Oj', 'load') { Oj.load_file('sample.json') }
122
+ #perf.add('Oj', 'load') { Oj.load(File.read('sample.json')) }
123
+ perf.add('Ox', 'load_file') { Ox.load_file('sample.xml', :mode => :object) }
110
124
  perf.add('Marshal', 'load') { Marshal.load(File.new('sample.marshal')) }
111
125
  perf.run($iter)
112
126
  end
@@ -115,8 +129,8 @@ if do_write
115
129
  puts '-' * 80
116
130
  puts "Write to file Performance"
117
131
  perf = Perf.new()
118
- perf.add('Ox', 'to_file') { Ox.to_file('sample.xml', $obj, :indent => $indent, :circular => $circular) }
119
132
  perf.add('Oj', 'to_file') { Oj.to_file('sample.json', $obj) }
133
+ perf.add('Ox', 'to_file') { Ox.to_file('sample.xml', $obj, :indent => $indent, :circular => $circular) }
120
134
  perf.add('Marshal', 'dump') { Marshal.dump($obj, File.new('sample.marshal', 'w')) }
121
135
  perf.run($iter)
122
136
  end
data/test/perf_scp.rb ADDED
@@ -0,0 +1,151 @@
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 = 50000
18
+ $with_bignum = false
19
+ $size = 0
20
+
21
+ opts = OptionParser.new
22
+ opts.on("-v", "verbose") { $verbose = true }
23
+ opts.on("-c", "--count [Int]", Integer, "iterations") { |i| $iter = i }
24
+ opts.on("-i", "--indent [Int]", Integer, "indentation") { |i| $indent = i }
25
+ opts.on("-s", "--size [Int]", Integer, "size (~Kbytes)") { |i| $size = i }
26
+ opts.on("-b", "with bignum") { $with_bignum = true }
27
+ opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
28
+ files = opts.parse(ARGV)
29
+
30
+ $obj = {
31
+ 'a' => 'Alpha', # string
32
+ 'b' => true, # boolean
33
+ 'c' => 12345, # number
34
+ 'd' => [ true, [false, [-123456789, nil], 3.9676, ['Something else.', false], nil]], # mix it up array
35
+ 'e' => { 'zero' => nil, 'one' => 1, 'two' => 2, 'three' => [3], 'four' => [0, 1, 2, 3, 4] }, # hash
36
+ 'f' => nil, # nil
37
+ 'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
38
+ 'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
39
+ }
40
+ $obj['g'] = 12345678901234567890123456789 if $with_bignum
41
+
42
+ if 0 < $size
43
+ o = $obj
44
+ $obj = []
45
+ (4 * $size).times do
46
+ $obj << o
47
+ end
48
+ end
49
+
50
+ Oj.default_options = { :indent => $indent, :mode => :compat }
51
+
52
+ $json = Oj.dump($obj)
53
+ $failed = {} # key is same as String used in tests later
54
+
55
+ class AllSaj < Oj::Saj
56
+ def initialize()
57
+ end
58
+
59
+ def hash_start(key)
60
+ end
61
+
62
+ def hash_end(key)
63
+ end
64
+
65
+ def array_start(key)
66
+ end
67
+
68
+ def array_end(key)
69
+ end
70
+
71
+ def add_value(value, key)
72
+ end
73
+ end # AllSaj
74
+
75
+ class NoSaj < Oj::Saj
76
+ def initialize()
77
+ end
78
+ end # NoSaj
79
+
80
+ class NoHandler < Oj::ScHandler
81
+ def initialize()
82
+ end
83
+ end # NoHandler
84
+
85
+ class AllHandler < Oj::ScHandler
86
+ def initialize()
87
+ end
88
+
89
+ def hash_start()
90
+ return nil
91
+ end
92
+
93
+ def hash_end()
94
+ end
95
+
96
+ def array_start()
97
+ return nil
98
+ end
99
+
100
+ def array_end()
101
+ end
102
+
103
+ def add_value(value)
104
+ end
105
+
106
+ def hash_set(h, key, value)
107
+ end
108
+
109
+ def array_append(a, value)
110
+ end
111
+
112
+ end # AllHandler
113
+
114
+ saj_handler = AllSaj.new()
115
+ no_saj = NoSaj.new()
116
+
117
+ sc_handler = AllHandler.new()
118
+ no_handler = NoHandler.new()
119
+
120
+ def capture_error(tag, orig, load_key, dump_key, &blk)
121
+ begin
122
+ obj = blk.call(orig)
123
+ raise "#{tag} #{dump_key} and #{load_key} did not return the same object as the original." unless orig == obj
124
+ rescue Exception => e
125
+ $failed[tag] = "#{e.class}: #{e.message}"
126
+ end
127
+ end
128
+
129
+ # Verify that all packages dump and load correctly and return the same Object as the original.
130
+ capture_error('Yajl', $obj, 'encode', 'parse') { |o| Yajl::Parser.parse(Yajl::Encoder.encode(o)) }
131
+ capture_error('JSON::Ext', $obj, 'generate', 'parse') { |o| JSON.generator = JSON::Ext::Generator; JSON::Ext::Parser.new(JSON.generate(o)).parse }
132
+
133
+ if $verbose
134
+ puts "json:\n#{$json}\n"
135
+ end
136
+
137
+ puts '-' * 80
138
+ puts "Parse Performance"
139
+ perf = Perf.new()
140
+ perf.add('Oj::Saj', 'all') { Oj.saj_parse(saj_handler, $json) }
141
+ perf.add('Oj::Saj', 'none') { Oj.saj_parse(no_saj, $json) }
142
+ perf.add('Oj::Scp', 'all') { Oj.sc_parse(sc_handler, $json) }
143
+ perf.add('Oj::Scp', 'none') { Oj.sc_parse(no_handler, $json) }
144
+ perf.add('Yajl', 'parse') { Yajl::Parser.parse($json) } unless $failed.has_key?('Yajl')
145
+ perf.add('JSON::Ext', 'parse') { JSON::Ext::Parser.new($json).parse } unless $failed.has_key?('JSON::Ext')
146
+ perf.run($iter)
147
+
148
+ unless $failed.empty?
149
+ puts "The following packages were not included for the reason listed"
150
+ $failed.each { |tag,msg| puts "***** #{tag}: #{msg}" }
151
+ end
data/test/perf_strict.rb CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby -wW1
1
+ #!/usr/bin/env ruby
2
2
  # encoding: UTF-8
3
3
 
4
4
  $: << '.'
@@ -6,76 +6,22 @@ $: << File.join(File.dirname(__FILE__), "../lib")
6
6
  $: << File.join(File.dirname(__FILE__), "../ext")
7
7
 
8
8
  require 'optparse'
9
- #require 'yajl'
10
9
  require 'perf'
11
- #require 'json'
12
- #require 'json/pure'
13
- #require 'json/ext'
14
- #require 'msgpack'
15
10
  require 'oj'
16
- #require 'ox'
17
-
18
- class Jazz
19
- attr_accessor :boolean, :number, :string
20
-
21
- def initialize()
22
- @boolean = true
23
- @number = 58
24
- @string = "A string"
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
-
35
- def to_json(*) # Yajl and JSON have different signatures
36
- %{
37
- { "json_class":"Jazz",
38
- "boolean":#{@boolean},
39
- "number":#{@number},
40
- "string":"#{@string}"
41
- }}
42
- end
43
-
44
- def to_hash()
45
- { 'json_class' => "Jazz",
46
- 'boolean' => @boolean,
47
- 'number' => @number,
48
- 'string' => @string
49
- }
50
- end
51
- alias as_json to_hash
52
-
53
- def to_msgpack(out='')
54
- to_hash().to_msgpack(out)
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
64
- end
65
11
 
66
12
  $verbose = false
67
13
  $indent = 0
68
- $iter = 10000
69
- $with_object = true
70
- $with_bignum = true
14
+ $iter = 20000
15
+ $with_bignum = false
71
16
  $with_nums = true
17
+ $size = 0
72
18
 
73
19
  opts = OptionParser.new
74
20
  opts.on("-v", "verbose") { $verbose = true }
75
21
  opts.on("-c", "--count [Int]", Integer, "iterations") { |i| $iter = i }
76
22
  opts.on("-i", "--indent [Int]", Integer, "indentation") { |i| $indent = i }
77
- opts.on("-o", "without objects") { $with_object = false }
78
- opts.on("-b", "without bignum") { $with_bignum = false }
23
+ opts.on("-s", "--size [Int]", Integer, "size (~Kbytes)") { |i| $size = i }
24
+ opts.on("-b", "with bignum") { $with_bignum = true }
79
25
  opts.on("-n", "without numbers") { $with_nums = false }
80
26
  opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
81
27
  files = opts.parse(ARGV)
@@ -85,10 +31,9 @@ if $with_nums
85
31
  'a' => 'Alpha', # string
86
32
  'b' => true, # boolean
87
33
  'c' => 12345, # number
88
- 'd' => [ true, [false, [12345, nil], 3.967, ['something', false], nil]], # mix it up array
89
- 'e' => { 'one' => 1, 'two' => 2 }, # hash
34
+ 'd' => [ true, [false, [-123456789, nil], 3.9676, ['Something else.', false], nil]], # mix it up array
35
+ 'e' => { 'zero' => nil, 'one' => 1, 'two' => 2, 'three' => [3], 'four' => [0, 1, 2, 3, 4] }, # hash
90
36
  'f' => nil, # nil
91
- #'g' => 12345678901234567890123456789, # big number
92
37
  'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
93
38
  'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
94
39
  }
@@ -99,18 +44,27 @@ else
99
44
  'b' => true,
100
45
  'c' => '12345',
101
46
  'd' => [ true, [false, ['12345', nil], '3.967', ['something', false], nil]],
102
- 'e' => { 'one' => '1', 'two' => '2' },
47
+ 'e' => { 'zero' => '0', 'one' => '1', 'two' => '2' },
103
48
  'f' => nil,
104
49
  'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
105
50
  'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
106
51
  }
107
52
  end
108
- $obj['j'] = Jazz.new() if $with_object
109
53
 
110
- Oj.default_options = { :indent => $indent, :mode => :compat }
54
+ Oj.default_options = { :indent => $indent, :mode => :strict }
55
+
56
+ if 0 < $size
57
+ o = $obj
58
+ $obj = []
59
+ (4 * $size).times do
60
+ $obj << o
61
+ end
62
+ end
111
63
 
112
64
  $json = Oj.dump($obj)
113
65
  $obj_json = Oj.dump($obj, :mode => :object)
66
+ #puts "*** size: #{$obj_json.size}"
67
+ #puts "*** #{$obj_json}"
114
68
  $failed = {} # key is same as String used in tests later
115
69
 
116
70
  def capture_error(tag, orig, load_key, dump_key, &blk)
@@ -123,15 +77,7 @@ def capture_error(tag, orig, load_key, dump_key, &blk)
123
77
  end
124
78
 
125
79
  # Verify that all packages dump and load correctly and return the same Object as the original.
126
- capture_error('Oj:compat', $obj, 'load', 'dump') { |o| Oj.load(Oj.dump(o)) }
127
- capture_error('Oj', $obj, 'load', 'dump') { |o| Oj.load(Oj.dump(o, :mode => :compat), :mode => :compat) }
128
- capture_error('Ox', $obj, 'load', 'dump') { |o|
129
- require 'ox'
130
- Ox.default_options = { :indent => $indent, :mode => :object }
131
- $xml = Ox.dump($obj, :indent => $indent)
132
- Ox.load(Ox.dump(o, :mode => :object), :mode => :object)
133
- }
134
- capture_error('MessagePack', $obj, 'unpack', 'pack') { |o| require 'msgpack'; MessagePack.unpack(MessagePack.pack($obj)) }
80
+ capture_error('Oj:strict', $obj, 'load', 'dump') { |o| Oj.strict_load(Oj.dump(o, :mode => :strict)) }
135
81
  capture_error('Yajl', $obj, 'encode', 'parse') { |o| require 'yajl'; Yajl::Parser.parse(Yajl::Encoder.encode(o)) }
136
82
  capture_error('JSON::Ext', $obj, 'generate', 'parse') { |o|
137
83
  require 'json'
@@ -147,22 +93,16 @@ capture_error('JSON::Pure', $obj, 'generate', 'parse') { |o|
147
93
  JSON.parse(JSON.generate(o))
148
94
  }
149
95
 
150
- begin
151
- $msgpack = MessagePack.pack($obj)
152
- rescue Exception => e
153
- $msgpack = nil
154
- end
155
-
156
96
  if $verbose
157
97
  puts "json:\n#{$json}\n"
158
98
  puts "object json:\n#{$obj_json}\n"
159
- puts "Oj loaded object:\n#{Oj.load($json)}\n"
99
+ puts "Oj loaded object:\n#{Oj.strict_load($json)}\n"
160
100
  puts "Yajl loaded object:\n#{Yajl::Parser.parse($json)}\n"
161
101
  puts "JSON loaded object:\n#{JSON::Ext::Parser.new($json).parse}\n"
162
102
  end
163
103
 
164
104
  puts '-' * 80
165
- puts "Load/Parse Performance"
105
+ puts "Strict Parse Performance"
166
106
  perf = Perf.new()
167
107
  unless $failed.has_key?('JSON::Ext')
168
108
  perf.add('JSON::Ext', 'parse') { JSON.parse($json) }
@@ -172,52 +112,31 @@ unless $failed.has_key?('JSON::Pure')
172
112
  perf.add('JSON::Pure', 'parse') { JSON.parse($json) }
173
113
  perf.before('JSON::Pure') { JSON.parser = JSON::Pure::Parser }
174
114
  end
175
- unless $failed.has_key?('Oj:compat')
176
- perf.add('Oj:compat', 'load') { Oj.load($json) }
177
- perf.before('Oj:compat') { Oj.default_options = { :mode => :compat} }
178
- end
179
- unless $failed.has_key?('Oj')
180
- perf.add('Oj', 'load') { Oj.load($obj_json) }
181
- perf.before('Oj') { Oj.default_options = { :mode => :object} }
115
+ unless $failed.has_key?('Oj:strict')
116
+ perf.add('Oj:strict', 'strict_load') { Oj.strict_load($json) }
182
117
  end
183
118
  perf.add('Yajl', 'parse') { Yajl::Parser.parse($json) } unless $failed.has_key?('Yajl')
184
- perf.add('Ox', 'load') { Ox.load($xml) } unless $failed.has_key?('Ox')
185
- perf.add('MessagePack', 'unpack') { MessagePack.unpack($msgpack) } unless $failed.has_key?('MessagePack')
186
119
  perf.run($iter)
187
120
 
188
- puts
189
121
  puts '-' * 80
190
- puts "Dump/Encode/Generate Performance"
122
+ puts "Strict Dump Performance"
191
123
  perf = Perf.new()
192
124
  unless $failed.has_key?('JSON::Ext')
193
- if 0 == $indent
194
- perf.add('JSON::Ext', 'generate') { JSON.generate($obj) }
195
- else
196
- perf.add('JSON::Ext', 'generate') { JSON.pretty_generate($obj) }
197
- end
125
+ perf.add('JSON::Ext', 'dump') { JSON.generate($obj) }
198
126
  perf.before('JSON::Ext') { JSON.generator = JSON::Ext::Generator }
199
127
  end
200
128
  unless $failed.has_key?('JSON::Pure')
201
- if 0 == $indent
202
- perf.add('JSON::Pure', 'generate') { JSON.generate($obj) }
203
- else
204
- perf.add('JSON::Pure', 'generate') { JSON.pretty_generate($obj) }
205
- end
129
+ perf.add('JSON::Pure', 'generate') { JSON.generate($obj) }
206
130
  perf.before('JSON::Pure') { JSON.generator = JSON::Pure::Generator }
207
131
  end
208
- unless $failed.has_key?('Oj')
209
- perf.add('Oj', 'dump') { Oj.dump($obj) }
210
- perf.before('Oj') { Oj.default_options = { :mode => :object} }
211
- end
212
- unless $failed.has_key?('Oj:compat')
213
- perf.add('Oj:compat', 'dump') { Oj.dump($obj) }
214
- perf.before('Oj:compat') { Oj.default_options = { :mode => :compat} }
132
+ unless $failed.has_key?('Oj:strict')
133
+ perf.add('Oj:strict', 'dump') { Oj.dump($obj, :mode => :strict) }
215
134
  end
216
135
  perf.add('Yajl', 'encode') { Yajl::Encoder.encode($obj) } unless $failed.has_key?('Yajl')
217
- perf.add('Ox', 'dump') { Ox.dump($obj) } unless $failed.has_key?('Ox')
218
- perf.add('MessagePack', 'pack') { MessagePack.pack($obj) } unless $failed.has_key?('MessagePack')
219
136
  perf.run($iter)
220
137
 
138
+ puts
139
+ puts '-' * 80
221
140
  puts
222
141
 
223
142
  unless $failed.empty?
data/test/sample.rb CHANGED
@@ -10,7 +10,6 @@ end
10
10
  require 'pp'
11
11
  require 'sample/doc'
12
12
 
13
-
14
13
  def sample_doc(size=3)
15
14
  colors = [ :black, :gray, :white, :red, :blue, :yellow, :green, :purple, :orange ]
16
15
 
@@ -29,7 +28,7 @@ def sample_doc(size=3)
29
28
  (1..size).each do |k|
30
29
  g2 = ::Sample::Group.new
31
30
  r = ::Sample::Rect.new(j * 40 + 10.0, i * 10.0,
32
- 10.123456 / k, 10.0 / k, colors[(i + j + k) % colors.size])
31
+ 10.123456 / k, 10.0 / k, colors[(i + j + k) % colors.size])
33
32
  r.add_prop(:part_of, layer.name)
34
33
  g2 << r
35
34
  g2 << ::Sample::Text.new("#{k} in #{j}", r.left, r.top, r.width, r.height)
@@ -38,7 +37,7 @@ def sample_doc(size=3)
38
37
  g2 = ::Sample::Group.new
39
38
  (1..size).each do |k|
40
39
  o = ::Sample::Oval.new(j * 40 + 12.0, i * 10.0 + 2.0,
41
- 6.0 / k, 6.0 / k, colors[(i + j + k) % colors.size])
40
+ 6.0 / k, 6.0 / k, colors[(i + j + k) % colors.size])
42
41
  o.add_prop(:inside, true)
43
42
  g << o
44
43
  end