oj 3.11.0 → 3.16.5

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 (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1421 -0
  3. data/README.md +20 -5
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +48 -38
  6. data/ext/oj/cache.c +329 -0
  7. data/ext/oj/cache.h +22 -0
  8. data/ext/oj/cache8.c +60 -62
  9. data/ext/oj/cache8.h +8 -7
  10. data/ext/oj/circarray.c +35 -35
  11. data/ext/oj/circarray.h +11 -9
  12. data/ext/oj/code.c +156 -174
  13. data/ext/oj/code.h +19 -18
  14. data/ext/oj/compat.c +140 -197
  15. data/ext/oj/custom.c +737 -879
  16. data/ext/oj/debug.c +126 -0
  17. data/ext/oj/dump.c +830 -835
  18. data/ext/oj/dump.h +65 -53
  19. data/ext/oj/dump_compat.c +566 -642
  20. data/ext/oj/dump_leaf.c +95 -182
  21. data/ext/oj/dump_object.c +518 -659
  22. data/ext/oj/dump_strict.c +301 -334
  23. data/ext/oj/encode.h +3 -4
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +27 -24
  26. data/ext/oj/err.h +38 -13
  27. data/ext/oj/extconf.rb +23 -7
  28. data/ext/oj/fast.c +1043 -1073
  29. data/ext/oj/intern.c +313 -0
  30. data/ext/oj/intern.h +22 -0
  31. data/ext/oj/mem.c +318 -0
  32. data/ext/oj/mem.h +53 -0
  33. data/ext/oj/mimic_json.c +449 -423
  34. data/ext/oj/object.c +530 -576
  35. data/ext/oj/odd.c +155 -138
  36. data/ext/oj/odd.h +24 -22
  37. data/ext/oj/oj.c +1331 -993
  38. data/ext/oj/oj.h +306 -292
  39. data/ext/oj/parse.c +934 -938
  40. data/ext/oj/parse.h +73 -70
  41. data/ext/oj/parser.c +1600 -0
  42. data/ext/oj/parser.h +101 -0
  43. data/ext/oj/rails.c +795 -845
  44. data/ext/oj/rails.h +7 -7
  45. data/ext/oj/reader.c +132 -140
  46. data/ext/oj/reader.h +67 -78
  47. data/ext/oj/resolve.c +40 -59
  48. data/ext/oj/resolve.h +3 -2
  49. data/ext/oj/rxclass.c +67 -67
  50. data/ext/oj/rxclass.h +11 -9
  51. data/ext/oj/saj.c +441 -480
  52. data/ext/oj/saj2.c +584 -0
  53. data/ext/oj/saj2.h +23 -0
  54. data/ext/oj/scp.c +78 -111
  55. data/ext/oj/sparse.c +726 -730
  56. data/ext/oj/stream_writer.c +146 -165
  57. data/ext/oj/strict.c +103 -123
  58. data/ext/oj/string_writer.c +241 -253
  59. data/ext/oj/trace.c +29 -33
  60. data/ext/oj/trace.h +41 -11
  61. data/ext/oj/usual.c +1218 -0
  62. data/ext/oj/usual.h +69 -0
  63. data/ext/oj/util.c +103 -103
  64. data/ext/oj/util.h +3 -2
  65. data/ext/oj/val_stack.c +60 -49
  66. data/ext/oj/val_stack.h +79 -85
  67. data/ext/oj/validate.c +46 -0
  68. data/ext/oj/wab.c +307 -350
  69. data/lib/oj/active_support_helper.rb +1 -3
  70. data/lib/oj/bag.rb +8 -1
  71. data/lib/oj/easy_hash.rb +9 -9
  72. data/lib/oj/error.rb +1 -2
  73. data/lib/oj/json.rb +162 -150
  74. data/lib/oj/mimic.rb +9 -19
  75. data/lib/oj/saj.rb +20 -6
  76. data/lib/oj/schandler.rb +5 -4
  77. data/lib/oj/state.rb +12 -8
  78. data/lib/oj/version.rb +1 -2
  79. data/lib/oj.rb +2 -0
  80. data/pages/Compatibility.md +1 -1
  81. data/pages/InstallOptions.md +20 -0
  82. data/pages/JsonGem.md +15 -0
  83. data/pages/Modes.md +8 -3
  84. data/pages/Options.md +43 -5
  85. data/pages/Parser.md +309 -0
  86. data/pages/Rails.md +14 -2
  87. data/test/_test_active.rb +8 -9
  88. data/test/_test_active_mimic.rb +7 -8
  89. data/test/_test_mimic_rails.rb +17 -20
  90. data/test/activerecord/result_test.rb +12 -8
  91. data/test/activesupport6/encoding_test.rb +63 -28
  92. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  93. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  94. data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
  95. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  96. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  97. data/test/files.rb +15 -15
  98. data/test/foo.rb +17 -43
  99. data/test/helper.rb +16 -3
  100. data/test/isolated/shared.rb +3 -2
  101. data/test/json_gem/json_addition_test.rb +2 -2
  102. data/test/json_gem/json_common_interface_test.rb +8 -6
  103. data/test/json_gem/json_encoding_test.rb +0 -0
  104. data/test/json_gem/json_ext_parser_test.rb +1 -0
  105. data/test/json_gem/json_fixtures_test.rb +3 -2
  106. data/test/json_gem/json_generator_test.rb +71 -41
  107. data/test/json_gem/json_generic_object_test.rb +11 -11
  108. data/test/json_gem/json_parser_test.rb +54 -47
  109. data/test/json_gem/json_string_matching_test.rb +9 -9
  110. data/test/json_gem/test_helper.rb +12 -0
  111. data/test/mem.rb +34 -0
  112. data/test/perf.rb +22 -27
  113. data/test/perf_compat.rb +31 -33
  114. data/test/perf_dump.rb +50 -0
  115. data/test/perf_fast.rb +80 -82
  116. data/test/perf_file.rb +27 -29
  117. data/test/perf_object.rb +65 -69
  118. data/test/perf_once.rb +59 -0
  119. data/test/perf_parser.rb +183 -0
  120. data/test/perf_saj.rb +46 -54
  121. data/test/perf_scp.rb +58 -69
  122. data/test/perf_simple.rb +41 -39
  123. data/test/perf_strict.rb +74 -82
  124. data/test/perf_wab.rb +67 -69
  125. data/test/prec.rb +5 -5
  126. data/test/sample/change.rb +0 -1
  127. data/test/sample/dir.rb +0 -1
  128. data/test/sample/doc.rb +0 -1
  129. data/test/sample/file.rb +0 -1
  130. data/test/sample/group.rb +0 -1
  131. data/test/sample/hasprops.rb +0 -1
  132. data/test/sample/layer.rb +0 -1
  133. data/test/sample/rect.rb +0 -1
  134. data/test/sample/shape.rb +0 -1
  135. data/test/sample/text.rb +0 -1
  136. data/test/sample.rb +16 -16
  137. data/test/sample_json.rb +8 -8
  138. data/test/test_compat.rb +97 -45
  139. data/test/test_custom.rb +73 -51
  140. data/test/test_debian.rb +7 -10
  141. data/test/test_fast.rb +135 -79
  142. data/test/test_file.rb +41 -30
  143. data/test/test_gc.rb +16 -5
  144. data/test/test_generate.rb +21 -0
  145. data/test/test_hash.rb +15 -5
  146. data/test/test_integer_range.rb +9 -9
  147. data/test/test_null.rb +20 -20
  148. data/test/test_object.rb +99 -96
  149. data/test/test_parser.rb +11 -0
  150. data/test/test_parser_debug.rb +27 -0
  151. data/test/test_parser_saj.rb +337 -0
  152. data/test/test_parser_usual.rb +251 -0
  153. data/test/test_rails.rb +2 -2
  154. data/test/test_saj.rb +10 -8
  155. data/test/test_scp.rb +38 -40
  156. data/test/test_strict.rb +40 -32
  157. data/test/test_various.rb +165 -84
  158. data/test/test_wab.rb +48 -44
  159. data/test/test_writer.rb +47 -47
  160. data/test/tests.rb +13 -5
  161. data/test/tests_mimic.rb +12 -3
  162. data/test/tests_mimic_addition.rb +12 -3
  163. metadata +75 -127
  164. data/ext/oj/hash.c +0 -135
  165. data/ext/oj/hash.h +0 -18
  166. data/ext/oj/hash_test.c +0 -484
  167. data/test/activesupport4/decoding_test.rb +0 -108
  168. data/test/activesupport4/encoding_test.rb +0 -531
  169. data/test/activesupport4/test_helper.rb +0 -41
  170. data/test/activesupport5/test_helper.rb +0 -72
  171. data/test/bar.rb +0 -35
  172. data/test/baz.rb +0 -16
  173. data/test/zoo.rb +0 -13
data/test/perf_file.rb CHANGED
@@ -1,58 +1,57 @@
1
1
  #!/usr/bin/env ruby -wW1
2
+ # frozen_string_literal: true
2
3
 
3
- $: << '.'
4
- $: << '../lib'
5
- $: << '../ext'
4
+ $LOAD_PATH << '.'
5
+ $LOAD_PATH << '../lib'
6
+ $LOAD_PATH << '../ext'
6
7
 
7
- if __FILE__ == $0
8
- if (i = ARGV.index('-I'))
9
- x,path = ARGV.slice!(i, 2)
10
- $: << path
11
- end
8
+ if __FILE__ == $PROGRAM_NAME && (i = ARGV.index('-I'))
9
+ _, path = ARGV.slice!(i, 2)
10
+ $LOAD_PATH << path
12
11
  end
13
12
 
14
13
  require 'optparse'
15
14
  require 'oj'
16
15
  require 'perf'
17
16
 
18
- $indent = 0
19
- $iter = 1
20
- $size = 1
17
+ @indent = 0
18
+ @iter = 1
19
+ @size = 1
21
20
 
22
21
  opts = OptionParser.new
23
22
 
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 }
23
+ opts.on('-r', 'read') { true }
24
+ opts.on('-c', '--count [Int]', Integer, 'iterations') { |v| @iter = v }
25
+ opts.on('-i', '--indent [Int]', Integer, 'indent') { |v| @indent = v }
26
+ opts.on('-s', '--size [Int]', Integer, 'size in Mbytes') { |s| @size = s }
28
27
 
29
- opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
30
- files = opts.parse(ARGV)
28
+ opts.on('-h', '--help', 'Show this display') { puts opts; Process.exit!(0) }
29
+ opts.parse(ARGV)
31
30
 
32
- $obj = {
31
+ @obj = {
33
32
  'a' => 'Alpha', # string
34
33
  'b' => true, # boolean
35
- 'c' => 12345, # number
36
- 'd' => [ true, [false, [-123456789, nil], 3.9676, ['Something else.', false], nil]], # mix it up array
34
+ 'c' => 12_345, # number
35
+ 'd' => [ true, [false, [-123_456_789, nil], 3.9676, ['Something else.', false], nil]], # mix it up array
37
36
  'e' => { 'zero' => nil, 'one' => 1, 'two' => 2, 'three' => [3], 'four' => [0, 1, 2, 3, 4] }, # hash
38
37
  'f' => nil, # nil
39
- 'g' => 12345678901234567890123456789, #_bignum
38
+ 'g' => 12_345_678_901_234_567_890_123_456_789, # _bignum
40
39
  'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
41
40
  'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
42
41
  }
43
42
 
44
- json = Oj.dump($obj, :indent => $indent)
45
- cnt = ($size * 1024 * 1024 + json.size) / json.size
46
- cnt = 1 if 0 == $size
43
+ json = Oj.dump(@obj, :indent => @indent)
44
+ cnt = ((@size * 1024 * 1024) + json.size) / json.size
45
+ cnt = 1 if 0 == @size
47
46
 
48
47
  filename = 'tmp.json'
49
- File.open(filename, "w") { |f|
48
+ File.open(filename, 'w') { |f|
50
49
  cnt.times do
51
- Oj.to_stream(f, $obj, :indent => $indent)
50
+ Oj.to_stream(f, @obj, :indent => @indent)
52
51
  end
53
52
  }
54
53
 
55
- Oj.default_options = { :mode => :strict, :indent => $indent }
54
+ Oj.default_options = { :mode => :strict, :indent => @indent }
56
55
 
57
56
  puts '-' * 80
58
57
  puts "Read from #{cnt * json.size / (1024 * 1024)} Mb file Performance"
@@ -60,5 +59,4 @@ perf = Perf.new()
60
59
  perf.add('Oj.load_file', '') { Oj.load_file(filename) }
61
60
  perf.add('Oj.load(string)', '') { Oj.load(File.read(filename)) }
62
61
  perf.add('Oj.load(file)', '') { File.open(filename, 'r') { |f| Oj.load(f) } }
63
- perf.run($iter)
64
-
62
+ perf.run(@iter)
data/test/perf_object.rb CHANGED
@@ -1,14 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- $: << '.'
4
- $: << '../lib'
5
- $: << '../ext'
4
+ $LOAD_PATH << '.'
5
+ $LOAD_PATH << '../lib'
6
+ $LOAD_PATH << '../ext'
6
7
 
7
- if __FILE__ == $0
8
- if (i = ARGV.index('-I'))
9
- x,path = ARGV.slice!(i, 2)
10
- $: << path
11
- end
8
+ if __FILE__ == $PROGRAM_NAME && (i = ARGV.index('-I'))
9
+ _, path = ARGV.slice!(i, 2)
10
+ $LOAD_PATH << path
12
11
  end
13
12
 
14
13
  require 'optparse'
@@ -18,9 +17,9 @@ require 'perf'
18
17
  require 'sample'
19
18
  require 'files'
20
19
 
21
- $circular = false
22
- $indent = 0
23
- $allow_gc = true
20
+ @circular = false
21
+ @indent = 0
22
+ @allow_gc = true
24
23
 
25
24
  do_sample = false
26
25
  do_files = false
@@ -29,34 +28,34 @@ do_load = false
29
28
  do_dump = false
30
29
  do_read = false
31
30
  do_write = false
32
- $iter = 1000
33
- $mult = 1
31
+ @iter = 1000
32
+ @mult = 1
34
33
 
35
34
  opts = OptionParser.new
36
- opts.on("-c", "circular options") { $circular = true }
35
+ opts.on('-c', 'circular options') { @circular = true }
37
36
 
38
- opts.on("-x", "use sample instead of files") { do_sample = true }
39
- opts.on("-g", "no GC during parsing") { $allow_gc = false }
37
+ opts.on('-x', 'use sample instead of files') { do_sample = true }
38
+ opts.on('-g', 'no GC during parsing') { @allow_gc = false }
40
39
 
41
- opts.on("-s", "load and dump as sample Ruby object") { do_sample = true }
42
- opts.on("-f", "load and dump as files Ruby object") { do_files = true }
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 }
43
42
 
44
- opts.on("-l", "load") { do_load = true }
45
- opts.on("-d", "dump") { do_dump = true }
46
- opts.on("-r", "read") { do_read = true }
47
- opts.on("-w", "write") { do_write = true }
48
- opts.on("-a", "load, dump, read and write") { do_load = true; do_dump = true; do_read = true; do_write = true }
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 }
49
48
 
50
- opts.on("-i", "--iterations [Int]", Integer, "iterations") { |i| $iter = i }
51
- opts.on("-m", "--multiply [Int]", Integer, "multiplier") { |i| $mult = i }
49
+ opts.on('-i', '--iterations [Int]', Integer, 'iterations') { |v| @iter = v }
50
+ opts.on('-m', '--multiply [Int]', Integer, 'multiplier') { |v| @mult = v }
52
51
 
53
- opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
52
+ opts.on('-h', '--help', 'Show this display') { puts opts; Process.exit!(0) }
54
53
  files = opts.parse(ARGV)
55
54
 
56
- $obj = nil
57
- $xml = nil
58
- $mars = nil
59
- $json = nil
55
+ @obj = nil
56
+ @xml = nil
57
+ @mars = nil
58
+ @json = nil
60
59
 
61
60
  unless do_load || do_dump || do_read || do_write
62
61
  do_load = true
@@ -67,72 +66,69 @@ end
67
66
 
68
67
  # prepare all the formats for input
69
68
  if files.empty?
70
- $obj = []
71
- $mult.times do
72
- $obj << (do_sample ? sample_doc(2) : files('..'))
69
+ @obj = []
70
+ @mult.times do
71
+ @obj << (do_sample ? sample_doc(2) : files('..'))
73
72
  end
74
73
 
75
- $mars = Marshal.dump($obj)
76
- $xml = Ox.dump($obj, :indent => $indent, :circular => $circular)
77
- $json = Oj.dump($obj, :indent => $indent, :circular => $circular, :mode => :object)
78
- File.open('sample.xml', 'w') { |f| f.write($xml) }
79
- File.open('sample.json', 'w') { |f| f.write($json) }
80
- File.open('sample.marshal', 'w') { |f| f.write($mars) }
74
+ @mars = Marshal.dump(@obj)
75
+ @xml = Ox.dump(@obj, :indent => @indent, :circular => @circular)
76
+ @json = Oj.dump(@obj, :indent => @indent, :circular => @circular, :mode => :object)
77
+ File.write('sample.xml', @xml)
78
+ File.write('sample.json', @json)
79
+ File.write('sample.marshal', @mars)
81
80
  else
82
81
  puts "loading and parsing #{files}\n\n"
83
- data = files.map do |f|
84
- $xml = File.read(f)
85
- $obj = Ox.load($xml);
86
- $mars = Marshal.dump($obj)
87
- $json = Oj.dump($obj, :indent => $indent, :circular => $circular)
82
+ files.map do |f|
83
+ @xml = File.read(f)
84
+ @obj = Ox.load(@xml)
85
+ @mars = Marshal.dump(@obj)
86
+ @json = Oj.dump(@obj, :indent => @indent, :circular => @circular)
88
87
  end
89
88
  end
90
89
 
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
-
90
+ Oj.default_options = { :mode => :object, :indent => @indent, :circular => @circular, :allow_gc => @allow_gc }
91
+ # puts "json: #{@json.size}"
92
+ # puts "xml: #{@xml.size}"
93
+ # puts "marshal: #{@mars.size}"
96
94
 
97
95
  if do_load
98
96
  puts '-' * 80
99
- puts "Load Performance"
97
+ puts 'Load Performance'
100
98
  perf = Perf.new()
101
- perf.add('Oj.object', 'load') { Oj.object_load($json) }
102
- perf.add('Ox', 'load') { Ox.load($xml, :mode => :object) }
103
- perf.add('Marshal', 'load') { Marshal.load($mars) }
104
- perf.run($iter)
99
+ perf.add('Oj.object', 'load') { Oj.object_load(@json) }
100
+ perf.add('Ox', 'load') { Ox.load(@xml, :mode => :object) }
101
+ perf.add('Marshal', 'load') { Marshal.load(@mars) }
102
+ perf.run(@iter)
105
103
  end
106
104
 
107
105
  if do_dump
108
106
  puts '-' * 80
109
- puts "Dump Performance"
107
+ puts 'Dump Performance'
110
108
  perf = Perf.new()
111
- perf.add('Oj', 'dump') { Oj.dump($obj) }
112
- perf.add('Ox', 'dump') { Ox.dump($obj, :indent => $indent, :circular => $circular) }
113
- perf.add('Marshal', 'dump') { Marshal.dump($obj) }
114
- perf.run($iter)
109
+ perf.add('Oj', 'dump') { Oj.dump(@obj) }
110
+ perf.add('Ox', 'dump') { Ox.dump(@obj, :indent => @indent, :circular => @circular) }
111
+ perf.add('Marshal', 'dump') { Marshal.dump(@obj) }
112
+ perf.run(@iter)
115
113
  end
116
114
 
117
115
  if do_read
118
116
  puts '-' * 80
119
- puts "Read from file Performance"
117
+ puts 'Read from file Performance'
120
118
  perf = Perf.new()
121
119
  perf.add('Oj', 'load') { Oj.load_file('sample.json') }
122
- #perf.add('Oj', 'load') { Oj.load(File.read('sample.json')) }
120
+ # perf.add('Oj', 'load') { Oj.load(File.read('sample.json')) }
123
121
  perf.add('Ox', 'load_file') { Ox.load_file('sample.xml', :mode => :object) }
124
122
  perf.add('Marshal', 'load') { Marshal.load(File.new('sample.marshal')) }
125
- perf.run($iter)
123
+ perf.run(@iter)
126
124
  end
127
125
 
128
126
  if do_write
129
127
  puts '-' * 80
130
- puts "Write to file Performance"
128
+ puts 'Write to file Performance'
131
129
  perf = Perf.new()
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) }
134
- perf.add('Marshal', 'dump') { Marshal.dump($obj, File.new('sample.marshal', 'w')) }
135
- perf.run($iter)
130
+ perf.add('Oj', 'to_file') { Oj.to_file('sample.json', @obj) }
131
+ perf.add('Ox', 'to_file') { Ox.to_file('sample.xml', @obj, :indent => @indent, :circular => @circular) }
132
+ perf.add('Marshal', 'dump') { Marshal.dump(@obj, File.new('sample.marshal', 'w')) }
133
+ perf.run(@iter)
136
134
  end
137
-
138
-
data/test/perf_once.rb ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'English'
5
+ $LOAD_PATH << '.'
6
+ $LOAD_PATH << File.join(__dir__, '../lib')
7
+ $LOAD_PATH << File.join(__dir__, '../ext')
8
+
9
+ require 'oj'
10
+
11
+ filename = 'tmp.json'
12
+ File.open(filename, 'w') { |f|
13
+ cnt = 0
14
+ f.puts('{')
15
+ ('a'..'z').each { |a|
16
+ ('a'..'z').each { |b|
17
+ ('a'..'z').each { |c|
18
+ ('a'..'z').each { |d|
19
+ f.puts(%|"#{a}#{b}#{c}#{d}":#{cnt},|)
20
+ cnt += 1
21
+ }
22
+ }
23
+ }
24
+ }
25
+ f.puts('"_last":0}')
26
+ }
27
+
28
+ def mem
29
+ `ps -o rss= -p #{$PROCESS_ID}`.to_i
30
+ end
31
+
32
+ Oj.default_options = { mode: :strict, cache_keys: false, cache_str: -1 }
33
+ start = Time.now
34
+ Oj.load_file('tmp.json')
35
+ dur = Time.now - start
36
+ GC.start
37
+ puts "no cache duration: #{dur} @ #{mem}"
38
+
39
+ Oj.default_options = { cache_keys: true }
40
+ start = Time.now
41
+ Oj.load_file('tmp.json')
42
+ dur = Time.now - start
43
+ GC.start
44
+ puts "initial cache duration: #{dur} @ #{mem}"
45
+
46
+ start = Time.now
47
+ Oj.load_file('tmp.json')
48
+ dur = Time.now - start
49
+ GC.start
50
+ puts "second cache duration: #{dur} @ #{mem}"
51
+
52
+ 10.times { GC.start }
53
+ start = Time.now
54
+ Oj.load_file('tmp.json')
55
+ dur = Time.now - start
56
+ GC.start
57
+ puts "after several GCs cache duration: #{dur} @ #{mem}"
58
+
59
+ # TBD check memory use
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH << '.'
5
+ $LOAD_PATH << File.join(__dir__, '../lib')
6
+ $LOAD_PATH << File.join(__dir__, '../ext')
7
+
8
+ require 'optparse'
9
+ require 'perf'
10
+ require 'oj'
11
+ require 'json'
12
+
13
+ $verbose = false
14
+ $iter = 50_000
15
+ $with_bignum = false
16
+ $size = 1
17
+ $cache_keys = true
18
+ $symbol_keys = false
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('-s', '--size [Int]', Integer, 'size (~Kbytes)') { |i| $size = i }
24
+ opts.on('-b', 'with bignum') { $with_bignum = true }
25
+ opts.on('-k', 'no cache') { $cache_keys = false }
26
+ opts.on('-sym', 'symbol keys') { $symbol_keys = true }
27
+ opts.on('-h', '--help', 'Show this display') { puts opts; Process.exit!(0) }
28
+ opts.parse(ARGV)
29
+
30
+ $obj = {
31
+ 'a' => 'Alpha', # string
32
+ 'b' => true, # boolean
33
+ 'c' => 12_345, # number
34
+ 'd' => [ true, [false, [-123_456_789, nil], 3.9676, ['Something else.', false, 1, nil], 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'] = 12_345_678_901_234_567_890_123_456_789 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
+ $json = Oj.dump($obj)
51
+ $failed = {} # key is same as String used in tests later
52
+ Oj.default_options = {create_id: '^', create_additions: true, class_cache: true}
53
+ Oj.default_options = if $cache_keys
54
+ {cache_keys: true, cache_str: 6, symbol_keys: $symbol_keys}
55
+ else
56
+ {cache_keys: false, cache_str: -1, symbol_keys: $symbol_keys}
57
+ end
58
+ JSON.parser = JSON::Ext::Parser
59
+
60
+ class AllSaj
61
+
62
+ def hash_start(key)
63
+ end
64
+
65
+ def hash_end(key)
66
+ end
67
+
68
+ def array_start(key)
69
+ end
70
+
71
+ def array_end(key)
72
+ end
73
+
74
+ def add_value(value, key)
75
+ end
76
+ end # AllSaj
77
+
78
+ no_handler = Object.new()
79
+ all_handler = AllSaj.new()
80
+
81
+ if $verbose
82
+ puts "json:\n#{$json}\n"
83
+ end
84
+
85
+ ### Validate ######################
86
+ p_val = Oj::Parser.new(:validate)
87
+
88
+ puts '-' * 80
89
+ puts 'Validate Performance'
90
+ perf = Perf.new()
91
+ perf.add('Oj::Parser.validate', 'none') { p_val.parse($json) }
92
+ perf.add('Oj::Saj.none', 'none') { Oj.saj_parse(no_handler, $json) }
93
+ perf.run($iter)
94
+
95
+ ### SAJ ######################
96
+ p_all = Oj::Parser.new(:saj)
97
+ p_all.handler = all_handler
98
+ p_all.cache_keys = $cache_keys
99
+ p_all.cache_strings = 6
100
+
101
+ puts '-' * 80
102
+ puts 'Parse Callback Performance'
103
+ perf = Perf.new()
104
+ perf.add('Oj::Parser.saj', 'all') { p_all.parse($json) }
105
+ perf.add('Oj::Saj.all', 'all') { Oj.saj_parse(all_handler, $json) }
106
+ perf.run($iter)
107
+
108
+ ### Usual ######################
109
+ p_usual = Oj::Parser.new(:usual)
110
+ p_usual.cache_keys = $cache_keys
111
+ p_usual.cache_strings = ($cache_keys ? 6 : 0)
112
+ p_usual.symbol_keys = $symbol_keys
113
+
114
+ puts '-' * 80
115
+ puts 'Parse Usual Performance'
116
+ perf = Perf.new()
117
+ perf.add('Oj::Parser.usual', '') { p_usual.parse($json) }
118
+ perf.add('Oj::strict_load', '') { Oj.strict_load($json) }
119
+ perf.add('JSON::Ext', 'parse') { JSON.parse($json) }
120
+ perf.run($iter)
121
+
122
+ ### Usual Objects ######################
123
+
124
+ # Original Oj follows the JSON gem for creating objects which uses the class
125
+ # json_create(arg) method. Oj::Parser in usual mode supprts the same but also
126
+ # handles populating the object variables directly which is faster.
127
+
128
+ class Stuff
129
+ attr_accessor :alpha, :bravo, :charlie, :delta, :echo, :foxtrot, :golf, :hotel, :india, :juliet
130
+
131
+ def self.json_create(arg)
132
+ obj = new
133
+ obj.alpha = arg['alpha']
134
+ obj.bravo = arg['bravo']
135
+ obj.charlie = arg['charlie']
136
+ obj.delta = arg['delta']
137
+ obj.echo = arg['echo']
138
+ obj.foxtrot = arg['foxtrot']
139
+ obj.golf = arg['golf']
140
+ obj.hotel = arg['hotel']
141
+ obj.india = arg['india']
142
+ obj.juliet = arg['juliet']
143
+ obj
144
+ end
145
+ end
146
+
147
+ $obj_json = %|{
148
+ "alpha": [0, 1,2,3,4,5,6,7,8,9],
149
+ "bravo": true,
150
+ "charlie": 123,
151
+ "delta": "some string",
152
+ "echo": null,
153
+ "^": "Stuff",
154
+ "foxtrot": false,
155
+ "golf": "gulp",
156
+ "hotel": {"x": true, "y": false},
157
+ "india": [null, true, 123],
158
+ "juliet": "junk"
159
+ }|
160
+
161
+ p_usual = Oj::Parser.new(:usual)
162
+ p_usual.cache_keys = $cache_keys
163
+ p_usual.cache_strings = ($cache_keys ? 6 : 0)
164
+ p_usual.symbol_keys = $symbol_keys
165
+ p_usual.create_id = '^'
166
+ p_usual.class_cache = true
167
+ p_usual.ignore_json_create = true
168
+
169
+ JSON.create_id = '^'
170
+
171
+ puts '-' * 80
172
+ puts 'Parse Usual Object Performance'
173
+ perf = Perf.new()
174
+ perf.add('Oj::Parser.usual', '') { p_usual.parse($obj_json) }
175
+ perf.add('Oj::compat_load', '') { Oj.compat_load($obj_json) }
176
+ perf.add('JSON::Ext', 'parse') { JSON.parse($obj_json) }
177
+
178
+ perf.run($iter)
179
+
180
+ unless $failed.empty?
181
+ puts 'The following packages were not included for the reason listed'
182
+ $failed.each { |tag, msg| puts "***** #{tag}: #{msg}" }
183
+ end