oj 3.13.9 → 3.13.12
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +9 -0
- data/ext/oj/circarray.c +1 -1
- data/ext/oj/code.c +15 -22
- data/ext/oj/custom.c +32 -59
- data/ext/oj/dump.c +129 -175
- data/ext/oj/dump.h +25 -8
- data/ext/oj/dump_compat.c +44 -81
- data/ext/oj/dump_leaf.c +14 -58
- data/ext/oj/dump_object.c +68 -129
- data/ext/oj/dump_strict.c +14 -26
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/fast.c +15 -9
- data/ext/oj/intern.c +9 -2
- data/ext/oj/intern.h +1 -1
- data/ext/oj/mimic_json.c +73 -73
- data/ext/oj/object.c +1 -1
- data/ext/oj/odd.c +83 -63
- data/ext/oj/odd.h +13 -13
- data/ext/oj/oj.c +29 -17
- data/ext/oj/oj.h +20 -2
- data/ext/oj/parse.c +3 -2
- data/ext/oj/parser.c +10 -15
- data/ext/oj/rails.c +43 -62
- data/ext/oj/rails.h +1 -1
- data/ext/oj/reader.c +2 -0
- data/ext/oj/saj.c +11 -23
- data/ext/oj/stream_writer.c +3 -1
- data/ext/oj/string_writer.c +12 -5
- data/ext/oj/wab.c +9 -9
- data/lib/oj/version.rb +1 -1
- data/pages/JsonGem.md +15 -0
- data/pages/Modes.md +6 -3
- data/pages/Rails.md +12 -0
- data/test/bar.rb +1 -8
- data/test/foo.rb +70 -13
- data/test/perf_dump.rb +50 -0
- data/test/test_fast.rb +19 -0
- data/test/test_object.rb +12 -7
- data/test/test_saj.rb +1 -1
- data/test/test_various.rb +27 -2
- data/test/tests.rb +0 -1
- metadata +6 -3
data/lib/oj/version.rb
CHANGED
data/pages/JsonGem.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
# JSON Quickstart
|
2
|
+
|
3
|
+
To have Oj universally "take over" many methods on the JSON constant (`load`, `parse`, etc.) with
|
4
|
+
their faster Oj counterparts, in a mode that is compatible with the json gem:
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
Oj.mimic_JSON()
|
8
|
+
```
|
9
|
+
|
10
|
+
If the project does not already use the json gem, `JSON` will become available.
|
11
|
+
If the project does require the json gem, `Oj.mimic_JSON()` should be invoked after the
|
12
|
+
json gem has been required.
|
13
|
+
|
14
|
+
For more details and options, read on...
|
15
|
+
|
1
16
|
# Oj JSON Gem Compatibility
|
2
17
|
|
3
18
|
The `:compat` mode mimics the json gem. The json gem is built around the use
|
data/pages/Modes.md
CHANGED
@@ -39,7 +39,8 @@ if a non-native type is encountered instead of raising an Exception.
|
|
39
39
|
The `:compat` mode mimics the json gem. The json gem is built around the use
|
40
40
|
of the `to_json(*)` method defined for a class. Oj attempts to provide the
|
41
41
|
same functionality by being a drop in replacement with a few
|
42
|
-
exceptions.
|
42
|
+
exceptions. To universally replace many `JSON` methods with their faster Oj counterparts,
|
43
|
+
simply run `Oj.mimic_json`. [{file:JsonGem.md}](JsonGem.md) includes more details on
|
43
44
|
compatibility and use.
|
44
45
|
|
45
46
|
## :rails Mode
|
@@ -108,11 +109,11 @@ information.
|
|
108
109
|
| :float_precision | Fixnum | x | x | | | | x | |
|
109
110
|
| :hash_class | Class | | | x | x | | x | |
|
110
111
|
| :ignore | Array | | | | | x | x | |
|
111
|
-
| :indent | Integer | x | x |
|
112
|
+
| :indent | Integer | x | x | 4 | 4 | x | x | x |
|
112
113
|
| :indent_str | String | | | x | x | | x | |
|
113
114
|
| :integer_range | Range | x | x | x | x | x | x | x |
|
114
115
|
| :match_string | Hash | | | x | x | | x | |
|
115
|
-
| :max_nesting | Fixnum |
|
116
|
+
| :max_nesting | Fixnum | 5 | 5 | x | | 5 | 5 | |
|
116
117
|
| :mode | Symbol | - | - | - | - | - | - | |
|
117
118
|
| :nan | Symbol | | | | | | x | |
|
118
119
|
| :nilnil | Boolean | | | | | | x | |
|
@@ -140,6 +141,8 @@ information.
|
|
140
141
|
3. By default the bigdecimal_as decimal is not set and the default encoding
|
141
142
|
for Rails is as a string. Setting the value to true will encode a
|
142
143
|
BigDecimal as a number which breaks compatibility.
|
144
|
+
Note: after version 3.11.3 both `Oj.generate` and `JSON.generate`
|
145
|
+
will not honour this option in Rails Mode, detais on https://github.com/ohler55/oj/pull/716.
|
143
146
|
|
144
147
|
4. The integer indent value in the default options will be honored by since
|
145
148
|
the json gem expects a String type the indent in calls to 'to_json()',
|
data/pages/Rails.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
# Rails Quickstart
|
2
|
+
|
3
|
+
To universally replace Rails' use of the json gem with Oj, and also
|
4
|
+
have Oj "take over" many methods on the JSON constant (`load`, `parse`, etc.) with
|
5
|
+
their faster Oj counterparts, add this to an initializer:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
Oj.optimize_rails()
|
9
|
+
```
|
10
|
+
|
11
|
+
For more details and options, read on...
|
12
|
+
|
1
13
|
# Oj Rails Compatibility
|
2
14
|
|
3
15
|
The `:rails` mode mimics the ActiveSupport version 5 encoder. Rails and
|
data/test/bar.rb
CHANGED
@@ -6,11 +6,4 @@ $: << File.join(File.dirname(__FILE__), "../ext")
|
|
6
6
|
|
7
7
|
require 'oj'
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
p = Oj::Parser.new(:usual)
|
12
|
-
p.cache_keys = false
|
13
|
-
p.symbol_keys = true
|
14
|
-
x = p.parse(json)
|
15
|
-
|
16
|
-
pp x
|
9
|
+
Oj.load(%|{"time":"2021-08-16 12:12:15","a":"5","b":"5"|)
|
data/test/foo.rb
CHANGED
@@ -4,17 +4,74 @@ $: << '.'
|
|
4
4
|
$: << File.join(File.dirname(__FILE__), "../lib")
|
5
5
|
$: << File.join(File.dirname(__FILE__), "../ext")
|
6
6
|
|
7
|
-
|
8
|
-
require
|
9
|
-
|
7
|
+
require "oj"
|
8
|
+
require "socket"
|
9
|
+
require 'io/nonblock'
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
#pid = spawn("nc -d 0.1 -l 5000", out: "/dev/null")
|
12
|
+
pid = spawn("nc -i 1 -l 7777", out: "/dev/null")
|
13
|
+
at_exit { Process.kill 9, pid }
|
14
|
+
sleep 0.2
|
15
|
+
s = Socket.tcp("localhost", 7777)
|
16
|
+
s.nonblock = false
|
17
|
+
1_000_000.times do |x|
|
18
|
+
Oj.to_stream(s, { x: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]})
|
19
|
+
end
|
20
|
+
|
21
|
+
=begin
|
22
|
+
IO.pipe do |r, w|
|
23
|
+
if fork
|
24
|
+
r.close
|
25
|
+
#w.nonblock = false
|
26
|
+
1_000_000.times do |i|
|
27
|
+
begin
|
28
|
+
Oj.to_stream(w, { x: i})
|
29
|
+
rescue IOError => e
|
30
|
+
puts "*** #{i} raised #{e.class}: #{e}"
|
31
|
+
IO.select(nil, [w])
|
32
|
+
retry
|
33
|
+
end
|
34
|
+
w.puts
|
35
|
+
end
|
36
|
+
else
|
37
|
+
w.close
|
38
|
+
sleep(0.1)
|
39
|
+
r.each_line { |b|
|
40
|
+
#print b
|
41
|
+
}
|
42
|
+
r.close
|
43
|
+
Process.exit(0)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
=end
|
47
|
+
|
48
|
+
=begin
|
49
|
+
IO.pipe do |r, w|
|
50
|
+
if fork
|
51
|
+
r.close
|
52
|
+
#w.nonblock = false
|
53
|
+
a = []
|
54
|
+
10_000.times do |i|
|
55
|
+
a << i
|
56
|
+
end
|
57
|
+
begin
|
58
|
+
Oj.to_stream(w, a, indent: 2)
|
59
|
+
rescue IOError => e
|
60
|
+
puts "*** raised #{e.class}: #{e}"
|
61
|
+
puts "*** fileno: #{w.fileno}"
|
62
|
+
puts "*** is an IO?: #{w.kind_of?(IO)}"
|
63
|
+
IO.select(nil, [w])
|
64
|
+
retry
|
65
|
+
end
|
66
|
+
w.puts
|
67
|
+
else
|
68
|
+
w.close
|
69
|
+
sleep(0.5)
|
70
|
+
r.each_line { |b|
|
71
|
+
#print b
|
72
|
+
}
|
73
|
+
r.close
|
74
|
+
Process.exit(0)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
=end
|
data/test/perf_dump.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
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 'oj'
|
10
|
+
|
11
|
+
$verbose = false
|
12
|
+
$indent = 2
|
13
|
+
$iter = 100_000
|
14
|
+
$size = 2
|
15
|
+
|
16
|
+
opts = OptionParser.new
|
17
|
+
opts.on("-v", "verbose") { $verbose = true }
|
18
|
+
opts.on("-c", "--count [Int]", Integer, "iterations") { |i| $iter = i }
|
19
|
+
opts.on("-i", "--indent [Int]", Integer, "indentation") { |i| $indent = i }
|
20
|
+
opts.on("-s", "--size [Int]", Integer, "size (~Kbytes)") { |i| $size = i }
|
21
|
+
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
|
22
|
+
files = opts.parse(ARGV)
|
23
|
+
|
24
|
+
$obj = {
|
25
|
+
'a' => 'Alpha', # string
|
26
|
+
'b' => true, # boolean
|
27
|
+
'c' => 12345, # number
|
28
|
+
'd' => [ true, [false, [-123456789, nil], 3.9676, ['Something else.', false], nil]], # mix it up array
|
29
|
+
'e' => { 'zero' => nil, 'one' => 1, 'two' => 2, 'three' => [3], 'four' => [0, 1, 2, 3, 4] }, # hash
|
30
|
+
'f' => nil, # nil
|
31
|
+
'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
|
32
|
+
'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
|
33
|
+
}
|
34
|
+
|
35
|
+
Oj.default_options = { :indent => $indent, :mode => :strict }
|
36
|
+
|
37
|
+
if 0 < $size
|
38
|
+
o = $obj
|
39
|
+
$obj = []
|
40
|
+
(4 * $size).times do
|
41
|
+
$obj << o
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
$json = Oj.dump($obj)
|
46
|
+
GC.start
|
47
|
+
start = Time.now
|
48
|
+
$iter.times { Oj.dump($obj) }
|
49
|
+
duration = Time.now - start
|
50
|
+
puts "Dumped #{$json.length} byte JSON #{$iter} times in %0.3f seconds or %0.3f iteration/sec." % [duration, $iter / duration]
|
data/test/test_fast.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
2
3
|
# frozen_string_literal: true
|
3
4
|
|
4
5
|
$: << File.dirname(__FILE__)
|
@@ -395,6 +396,19 @@ class DocTest < Minitest::Test
|
|
395
396
|
end
|
396
397
|
end
|
397
398
|
|
399
|
+
def test_nested_each_child
|
400
|
+
h = {}
|
401
|
+
Oj::Doc.open('{"a":1,"c":[2],"d":3}') do |doc|
|
402
|
+
doc.each_child('/') do |child|
|
403
|
+
h[child.path] = child.fetch
|
404
|
+
child.each_child do |grandchild|
|
405
|
+
h[grandchild.path] = grandchild.fetch
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
409
|
+
assert_equal({"/a"=>1, "/c"=>[2], "/c/1"=>2, "/d"=>3}, h)
|
410
|
+
end
|
411
|
+
|
398
412
|
def test_size
|
399
413
|
Oj::Doc.open('[1,2,3]') do |doc|
|
400
414
|
assert_equal(4, doc.size)
|
@@ -491,6 +505,11 @@ class DocTest < Minitest::Test
|
|
491
505
|
assert_equal({'/a/x' => 2, '/b/y' => 4}, results)
|
492
506
|
end
|
493
507
|
|
508
|
+
def test_doc_empty
|
509
|
+
result = Oj::Doc.open("") { |doc| doc.each_child {} }
|
510
|
+
assert_nil(result)
|
511
|
+
end
|
512
|
+
|
494
513
|
def test_comment
|
495
514
|
json = %{{
|
496
515
|
"x"/*one*/:/*two*/true,//three
|
data/test/test_object.rb
CHANGED
@@ -221,6 +221,13 @@ class ObjectJuice < Minitest::Test
|
|
221
221
|
|
222
222
|
def teardown
|
223
223
|
Oj.default_options = @default_options
|
224
|
+
#=begin
|
225
|
+
if '3.1.0' <= RUBY_VERSION && !(RbConfig::CONFIG['host_os'] =~ /(mingw|mswin)/)
|
226
|
+
#Oj::debug_odd("teardown before GC.verify_compaction_references")
|
227
|
+
GC.verify_compaction_references(double_heap: true, toward: :empty)
|
228
|
+
#Oj::debug_odd("teardown after GC.verify_compaction_references")
|
229
|
+
end
|
230
|
+
#=end
|
224
231
|
end
|
225
232
|
|
226
233
|
def test_nil
|
@@ -948,6 +955,11 @@ class ObjectJuice < Minitest::Test
|
|
948
955
|
|
949
956
|
def test_odd_date
|
950
957
|
dump_and_load(Date.new(2012, 6, 19), false)
|
958
|
+
|
959
|
+
Oj.register_odd(Date, Date, :jd, :jd)
|
960
|
+
json = Oj.dump(Date.new(2015, 3, 7), :mode => :object)
|
961
|
+
assert_equal(%|{"^O":"Date","jd":2457089}|, json)
|
962
|
+
dump_and_load(Date.new(2012, 6, 19), false)
|
951
963
|
end
|
952
964
|
|
953
965
|
def test_odd_datetime
|
@@ -972,13 +984,6 @@ class ObjectJuice < Minitest::Test
|
|
972
984
|
dump_and_load(s, false)
|
973
985
|
end
|
974
986
|
|
975
|
-
def test_odd_date_replaced
|
976
|
-
Oj.register_odd(Date, Date, :jd, :jd)
|
977
|
-
json = Oj.dump(Date.new(2015, 3, 7), :mode => :object)
|
978
|
-
assert_equal(%|{"^O":"Date","jd":2457089}|, json)
|
979
|
-
dump_and_load(Date.new(2012, 6, 19), false)
|
980
|
-
end
|
981
|
-
|
982
987
|
def test_odd_raw
|
983
988
|
Oj.register_odd_raw(Raw, Raw, :create, :to_json)
|
984
989
|
json = Oj.dump(Raw.new(%|{"a":1}|), :mode => :object)
|
data/test/test_saj.rb
CHANGED
@@ -180,7 +180,7 @@ class SajTest < Minitest::Test
|
|
180
180
|
assert_equal([:add_value, 12345, nil], handler.calls.first)
|
181
181
|
type, message, line, column = handler.calls.last
|
182
182
|
assert_equal([:error, 1, 6], [type, line, column])
|
183
|
-
assert_match(%r{invalid format, extra characters at line 1, column 6 \[(?:[a-z\.]+/)*saj\.c:\d+\]}, message)
|
183
|
+
assert_match(%r{invalid format, extra characters at line 1, column 6 \[(?:[A-Za-z]:\/)?(?:[a-z\.]+/)*saj\.c:\d+\]}, message)
|
184
184
|
end
|
185
185
|
|
186
186
|
end
|
data/test/test_various.rb
CHANGED
@@ -528,7 +528,7 @@ class Juice < Minitest::Test
|
|
528
528
|
assert_equal(58, obj.y)
|
529
529
|
end
|
530
530
|
|
531
|
-
# Stream Deeply Nested
|
531
|
+
# Stream Deeply Nested
|
532
532
|
def test_deep_nest_dump
|
533
533
|
begin
|
534
534
|
a = []
|
@@ -541,7 +541,7 @@ class Juice < Minitest::Test
|
|
541
541
|
assert(false, "*** expected an exception")
|
542
542
|
end
|
543
543
|
|
544
|
-
# Stream IO
|
544
|
+
# Stream IO
|
545
545
|
def test_io_string
|
546
546
|
src = { 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}
|
547
547
|
output = StringIO.open("", "w+")
|
@@ -553,6 +553,9 @@ class Juice < Minitest::Test
|
|
553
553
|
end
|
554
554
|
|
555
555
|
def test_io_file
|
556
|
+
# Windows does not support fork
|
557
|
+
return if RbConfig::CONFIG['host_os'] =~ /(mingw|mswin)/
|
558
|
+
|
556
559
|
src = { 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}
|
557
560
|
filename = File.join(File.dirname(__FILE__), 'open_file_test.json')
|
558
561
|
File.open(filename, "w") { |f|
|
@@ -564,6 +567,28 @@ class Juice < Minitest::Test
|
|
564
567
|
assert_equal(src, obj)
|
565
568
|
end
|
566
569
|
|
570
|
+
def test_io_stream
|
571
|
+
IO.pipe do |r, w|
|
572
|
+
if fork
|
573
|
+
r.close
|
574
|
+
#w.nonblock = false
|
575
|
+
a = []
|
576
|
+
10_000.times do |i|
|
577
|
+
a << i
|
578
|
+
end
|
579
|
+
Oj.to_stream(w, a, indent: 2)
|
580
|
+
w.close
|
581
|
+
else
|
582
|
+
w.close
|
583
|
+
sleep(0.1) # to force a busy
|
584
|
+
cnt = 0
|
585
|
+
r.each_line { cnt += 1 }
|
586
|
+
r.close
|
587
|
+
Process.exit(0)
|
588
|
+
end
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
567
592
|
# comments
|
568
593
|
def test_comment_slash
|
569
594
|
json = %{{
|
data/test/tests.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oj
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.13.
|
4
|
+
version: 3.13.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Ohler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -117,6 +117,7 @@ files:
|
|
117
117
|
- ext/oj/dump_object.c
|
118
118
|
- ext/oj/dump_strict.c
|
119
119
|
- ext/oj/encode.h
|
120
|
+
- ext/oj/encoder.c
|
120
121
|
- ext/oj/err.c
|
121
122
|
- ext/oj/err.h
|
122
123
|
- ext/oj/extconf.rb
|
@@ -227,6 +228,7 @@ files:
|
|
227
228
|
- test/mem.rb
|
228
229
|
- test/perf.rb
|
229
230
|
- test/perf_compat.rb
|
231
|
+
- test/perf_dump.rb
|
230
232
|
- test/perf_fast.rb
|
231
233
|
- test/perf_file.rb
|
232
234
|
- test/perf_object.rb
|
@@ -306,7 +308,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
306
308
|
- !ruby/object:Gem::Version
|
307
309
|
version: '0'
|
308
310
|
requirements: []
|
309
|
-
rubygems_version: 3.
|
311
|
+
rubygems_version: 3.3.3
|
310
312
|
signing_key:
|
311
313
|
specification_version: 4
|
312
314
|
summary: A fast JSON parser and serializer.
|
@@ -359,6 +361,7 @@ test_files:
|
|
359
361
|
- test/mem.rb
|
360
362
|
- test/perf.rb
|
361
363
|
- test/perf_compat.rb
|
364
|
+
- test/perf_dump.rb
|
362
365
|
- test/perf_fast.rb
|
363
366
|
- test/perf_file.rb
|
364
367
|
- test/perf_object.rb
|