nosj 0.4.0-aarch64-linux → 0.5.0-aarch64-linux
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 +105 -0
- data/README.md +32 -15
- data/lib/nosj/3.3/nosj.so +0 -0
- data/lib/nosj/3.4/nosj.so +0 -0
- data/lib/nosj/4.0/nosj.so +0 -0
- data/lib/nosj/json.rb +105 -39
- data/lib/nosj/version.rb +1 -1
- data/lib/nosj.rb +36 -22
- data/sig/nosj.rbs +4 -3
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8bd202a41866bf66ced093153a4a0ca1166ed3a2dc495eaa8189d0a6e6b58aa7
|
|
4
|
+
data.tar.gz: 8c7c12413a1bff0d9ff9d72d5629700e14a5c922fd1790ebe2ec46879be45d25
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 045b0214d996b133b5c99ec958d5f929f12adf7e134671c9ff70895a4168d9a6a7ce78c261d6d8c5453b38af7363ded4a918b9d5fbb6c50dd8b06b15283de4af
|
|
7
|
+
data.tar.gz: d8717b79f4bddf22206fa248e57521282be0f197210683724adb8f831adf5a26581dd92e9d0192e3973070252f5acdc2968e6f8686ea5c916ebc5387a72602bc
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,108 @@
|
|
|
1
|
+
## [0.5.0] - 2026-09-25
|
|
2
|
+
|
|
3
|
+
**json 3.0 compatibility.** nosj now matches the behavior of the json
|
|
4
|
+
gem 3.0, and stays compatible with both the json 2.x and 3.0
|
|
5
|
+
interfaces: `NOSJ.parse`, `NOSJ.generate`, and the rest of nosj's own
|
|
6
|
+
API follow json 3.0 semantics, while the `nosj/json` drop-in follows
|
|
7
|
+
whichever json gem your application has installed, 2.x or 3.0, down to
|
|
8
|
+
its calling conventions and the documents it accepts. Upgrading json
|
|
9
|
+
(or not) is your choice; nosj works with either.
|
|
10
|
+
|
|
11
|
+
Behavior changes in nosj's own API, for input that was accepted
|
|
12
|
+
before:
|
|
13
|
+
|
|
14
|
+
- Duplicate object keys raise `NOSJ::ParserError` (positioned at the
|
|
15
|
+
object repeating the key, like json 3) in `parse`, `load_file`,
|
|
16
|
+
`valid?` (returns false), `minify`/`reformat`, and everything that
|
|
17
|
+
materializes values. `allow_duplicate_key: true` restores the old
|
|
18
|
+
behavior: the last value wins (in `minify`, repeated keys pass
|
|
19
|
+
through).
|
|
20
|
+
- Lone UTF-16 surrogates such as `"\udc00"` raise `NOSJ::ParserError`
|
|
21
|
+
everywhere, trailing ones included (they used to decode to raw
|
|
22
|
+
WTF-8 bytes, and `minify` re-escaped them).
|
|
23
|
+
- `generate` raises `NOSJ::GeneratorError` for keys that render alike
|
|
24
|
+
(`{"a" => 1, :a => 2}`, `{1 => 1, "1" => 2}`), with json 3's exact
|
|
25
|
+
message; `allow_duplicate_key: true` emits them as before. Hashes
|
|
26
|
+
whose keys are all of one kind are never checked. The Rails encoder
|
|
27
|
+
is unchanged.
|
|
28
|
+
- `stats` still describes such documents rather than refusing them.
|
|
29
|
+
- Unknown options raise ArgumentError with json 3's message
|
|
30
|
+
(`unknown keyword: foo`) in every entry point, instead of being
|
|
31
|
+
ignored. json options nosj does not implement (`object_class`,
|
|
32
|
+
`array_class`, `decimal_class`, `on_load`, `create_additions`,
|
|
33
|
+
`allow_comments`, `allow_control_characters`,
|
|
34
|
+
`allow_invalid_escape`, `sort_keys`, `as_json`) raise unless falsy;
|
|
35
|
+
`on_load` and the newer ones used to be silently ignored.
|
|
36
|
+
`escape_slash` is gone, as in json 3: use `script_safe`.
|
|
37
|
+
`quirks_mode` is no longer accepted. `stats` takes only the options
|
|
38
|
+
it documents (`max_nesting`, `allow_nan`, `allow_trailing_comma`).
|
|
39
|
+
|
|
40
|
+
The `nosj/json` drop-in follows the installed json gem:
|
|
41
|
+
|
|
42
|
+
- With json 3.0, `JSON.parse` takes keyword options only, `JSON.dump`
|
|
43
|
+
uses json 3's defaults (nesting capped at 100), and whatever json 3
|
|
44
|
+
refuses (`quirks_mode`, `escape_slash`, `create_additions`, unknown
|
|
45
|
+
options, positional option hashes) raises exactly as json 3 raises.
|
|
46
|
+
- With json 2.x, everything behaves as before, including json 2's
|
|
47
|
+
acceptance of duplicate keys, lone surrogates, and comments, and
|
|
48
|
+
its handling of keys that render alike.
|
|
49
|
+
- Whenever the fast path refuses a call, the installed gem runs it
|
|
50
|
+
again and decides: exceptions are now the gem's own (message,
|
|
51
|
+
`json_path`, `invalid_object`) rather than nosj's messages re-raised
|
|
52
|
+
as JSON classes. The second pass happens on failures only, and a
|
|
53
|
+
`generate` run twice this way calls `to_json` again on the objects
|
|
54
|
+
visited before the refusal.
|
|
55
|
+
- Fixed: `JSON.dump` raised NameError (`_dump_default_options`) with
|
|
56
|
+
json older than 2.11, which includes the json bundled with Ruby 3.3
|
|
57
|
+
and 3.4.
|
|
58
|
+
- Fixed: `JSON.generate` (and `pretty_generate`, `dump`) with both
|
|
59
|
+
`ascii_only` and `script_safe` raised ArgumentError; that combination,
|
|
60
|
+
which nosj does not implement, now goes to the gem.
|
|
61
|
+
|
|
62
|
+
## [0.4.1] - 2026-09-25
|
|
63
|
+
|
|
64
|
+
- Fixed a crash in `NOSJ.generate`: an object whose `to_json` or
|
|
65
|
+
`to_s` shrank the array being generated (for example with
|
|
66
|
+
`Array#clear`) made the generator read freed memory, usually a
|
|
67
|
+
segfault. The array length is now re-read for every element, like
|
|
68
|
+
the json gem, so elements a callback appends are emitted too.
|
|
69
|
+
- Fixed memory corruption in `NOSJ.splice`: a replacement value whose
|
|
70
|
+
`to_json` modified the source string, deduplicated a frozen String
|
|
71
|
+
subclass (`-str`), or removed entries from the edits hash could make
|
|
72
|
+
splice read freed memory, copying unrelated heap bytes into the
|
|
73
|
+
result or crashing. All values are now generated before the source
|
|
74
|
+
is read.
|
|
75
|
+
- Fixed `NOSJ.lazy` and `NOSJ.each_line` reading freed memory when the
|
|
76
|
+
source is a frozen String subclass (such as
|
|
77
|
+
`ActiveSupport::SafeBuffer`) or a frozen string carrying instance
|
|
78
|
+
variables, and it is deduplicated with `-str` while the lazy
|
|
79
|
+
document is alive or between lines: Ruby swaps such a string's
|
|
80
|
+
buffer, and the old one kept being read (wrong values, or a crash).
|
|
81
|
+
- Fixed a memory leak in `NOSJ.generate` and `NOSJ.write_file`: an
|
|
82
|
+
exception raised by user code the generator calls bypassed its
|
|
83
|
+
cleanup and leaked its output buffer (megabytes per call after large
|
|
84
|
+
documents). Affected: a raising `respond_to?` or
|
|
85
|
+
`respond_to_missing?`, a raising `to_s` on an encoding-conversion
|
|
86
|
+
error, a raising autoload of `JSON::Fragment` (strict and Rails
|
|
87
|
+
modes), and a raising `Errno` constructor for a failed write. The
|
|
88
|
+
exception still propagates unchanged.
|
|
89
|
+
- Fixed: after a `NoMemoryError` in the middle of a parse (or
|
|
90
|
+
`minify`/`reformat`), the next call on that thread aborted the whole
|
|
91
|
+
process. Per-thread parser state is now recovered instead.
|
|
92
|
+
- `NOSJ::Lazy` nodes now take part in generational GC: holding many
|
|
93
|
+
nodes no longer slows down every minor GC (200,000 live nodes: 2.9 ms
|
|
94
|
+
per minor GC before, 0.1 ms now), and they are freed immediately
|
|
95
|
+
when collected.
|
|
96
|
+
- Fixed: lazy documents opened with `allow_trailing_comma: true` or
|
|
97
|
+
`allow_nan: true` could not be walked. `size`, `keys`, `each`, and
|
|
98
|
+
any lookup that missed or stepped over a trailing comma or a `NaN`
|
|
99
|
+
raised `NOSJ::ParserError`, even though `value` worked.
|
|
100
|
+
- `NOSJ.at_pointer`, `NOSJ.at_pointers`, and `NOSJ.at_pointer_file`
|
|
101
|
+
now honor `allow_nan` and `allow_trailing_comma` while resolving the
|
|
102
|
+
pointer, not only when materializing the matched value.
|
|
103
|
+
- Updated the nosj crate to 0.2.2.
|
|
104
|
+
- Updated dependencies, Magnus bumped to 0.9.0.
|
|
105
|
+
|
|
1
106
|
## [0.4.0] - 2026-09-05
|
|
2
107
|
|
|
3
108
|
- Ractors: on Ruby 4.0+, `NOSJ.parse`, `NOSJ.generate`, and every
|
data/README.md
CHANGED
|
@@ -65,6 +65,10 @@ through nosj:
|
|
|
65
65
|
require "nosj/json"
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
+
It works with json 2.x and 3.0 alike and follows whichever your app
|
|
69
|
+
has installed: its calling conventions, its defaults, and the documents
|
|
70
|
+
it accepts.
|
|
71
|
+
|
|
68
72
|
In a Bundler app (Rails included) that can live entirely in the
|
|
69
73
|
Gemfile you can do this:
|
|
70
74
|
|
|
@@ -108,9 +112,11 @@ The `json` gem API, on the `NOSJ` module:
|
|
|
108
112
|
|
|
109
113
|
```ruby
|
|
110
114
|
NOSJ.parse(src, symbolize_names: true) # also: freeze, max_nesting,
|
|
111
|
-
# allow_nan, allow_trailing_comma
|
|
115
|
+
# allow_nan, allow_trailing_comma,
|
|
116
|
+
# allow_duplicate_key
|
|
112
117
|
NOSJ.generate(obj) # indent, space, object_nl, ...,
|
|
113
|
-
NOSJ.pretty_generate(obj) # ascii_only, script_safe, strict
|
|
118
|
+
NOSJ.pretty_generate(obj) # ascii_only, script_safe, strict,
|
|
119
|
+
# allow_duplicate_key
|
|
114
120
|
```
|
|
115
121
|
|
|
116
122
|
### Lazy documents
|
|
@@ -151,7 +157,8 @@ Example: an early field resolves in ~0.35µs where `JSON.parse(json).dig(...)`
|
|
|
151
157
|
costs ~980µs on the same document—three orders of magnitude. A field
|
|
152
158
|
at the far end of a 570 KB document costs ~71µs, still 13× faster
|
|
153
159
|
than parse-then-dig. Misses return nil; matched subtrees materialize
|
|
154
|
-
with the same options as `parse` (`symbolize_names:`, `freeze:`)
|
|
160
|
+
with the same options as `parse` (`symbolize_names:`, `freeze:`), and
|
|
161
|
+
`allow_nan:`/`allow_trailing_comma:` govern the walk to them too.
|
|
155
162
|
|
|
156
163
|
### Files API
|
|
157
164
|
|
|
@@ -188,10 +195,11 @@ NOSJ.reformat_file("big.json") # straight off a memory map
|
|
|
188
195
|
```
|
|
189
196
|
|
|
190
197
|
Output is exactly `generate(parse(json))`—canonical number spellings,
|
|
191
|
-
normalized escapes, same formatting options—
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
`
|
|
198
|
+
normalized escapes, same formatting options—and it accepts exactly what
|
|
199
|
+
`parse` does. Acceptance options apply too:
|
|
200
|
+
`minify(src, allow_trailing_comma: true)` normalizes the commas away,
|
|
201
|
+
and under `allow_duplicate_key: true` repeated keys pass through (a
|
|
202
|
+
reformatter must not silently drop data).
|
|
195
203
|
|
|
196
204
|
### Byte-splicing edits and JSON Patch
|
|
197
205
|
|
|
@@ -402,19 +410,28 @@ Reproduce with `rake bench` (the parity-gated comparison, after a PGO retrain—
|
|
|
402
410
|
|
|
403
411
|
## Switching from the json gem
|
|
404
412
|
|
|
405
|
-
You mostly don't have to do anything.
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
413
|
+
You mostly don't have to do anything. `NOSJ.*` follows json 3.0,
|
|
414
|
+
whichever json your app runs; the `nosj/json` drop-in follows the
|
|
415
|
+
installed one, 2.x or 3.0. Some differences:
|
|
416
|
+
|
|
417
|
+
- json 3.0 semantics: duplicate keys, lone surrogates, JS comments,
|
|
418
|
+
and invalid UTF-8 are errors (`allow_duplicate_key: true` restores
|
|
419
|
+
last-key-wins), keys that render alike raise in `generate`, and
|
|
420
|
+
unknown options raise ArgumentError. With json 2.x installed, the
|
|
421
|
+
drop-in keeps json 2's leniency: when nosj refuses a call, the
|
|
422
|
+
installed gem runs it and has the last word.
|
|
423
|
+
- The json options nosj doesn't implement (`create_additions`,
|
|
424
|
+
`object_class`, `array_class`, `decimal_class`, `on_load`,
|
|
425
|
+
`allow_comments`, `allow_control_characters`,
|
|
426
|
+
`allow_invalid_escape`, `sort_keys`, `as_json`) raise ArgumentError
|
|
427
|
+
unless falsy; the drop-in passes them to the original gem.
|
|
412
428
|
- Unlike `Array#dig`, negative indices in `NOSJ.dig` return nil (JSON
|
|
413
429
|
Pointer has no equivalent).
|
|
414
430
|
- Parse errors raise `NOSJ::ParserError` (`NOSJ::NestingError` past
|
|
415
431
|
`max_nesting`, like the gem); messages use byte offsets rather than
|
|
416
432
|
the gem's phrasing, and the exception carries `#line`, `#column`,
|
|
417
|
-
and a caret `#snippet`.
|
|
433
|
+
and a caret `#snippet`. Through the drop-in, exceptions are the
|
|
434
|
+
installed gem's own (message, `json_path`, `invalid_object`).
|
|
418
435
|
|
|
419
436
|
Everything else—including the gem's exact float formatting, which is
|
|
420
437
|
not the shortest-round-trip form most libraries emit—matches
|
data/lib/nosj/3.3/nosj.so
CHANGED
|
Binary file
|
data/lib/nosj/3.4/nosj.so
CHANGED
|
Binary file
|
data/lib/nosj/4.0/nosj.so
CHANGED
|
Binary file
|
data/lib/nosj/json.rb
CHANGED
|
@@ -12,12 +12,18 @@
|
|
|
12
12
|
# Entry points built on JSON.parse (JSON.load, JSON.parse!,
|
|
13
13
|
# JSON.load_file, JSON.unsafe_load) pick up the fast path automatically
|
|
14
14
|
# and keep their exact legacy behavior when they need unsupported options
|
|
15
|
-
# (JSON.load
|
|
15
|
+
# (json 2's JSON.load passes create_additions, so it always takes the
|
|
16
|
+
# fallback).
|
|
16
17
|
#
|
|
17
|
-
#
|
|
18
|
-
# (
|
|
19
|
-
#
|
|
20
|
-
#
|
|
18
|
+
# The drop-in follows whichever json is installed, 2.x or 3.x: its
|
|
19
|
+
# calling conventions (json 3's keyword-only parse, its dump defaults)
|
|
20
|
+
# and its semantics. NOSJ implements json 3's (duplicate keys and lone
|
|
21
|
+
# surrogates are errors), so whenever the fast path refuses a call, the
|
|
22
|
+
# original gem runs it again and has the last word: json 2 accepts what
|
|
23
|
+
# it always accepted, and every exception is the gem's own, message,
|
|
24
|
+
# json_path and invalid_object included. That second pass happens on
|
|
25
|
+
# failures only; a generate run twice this way calls to_json on the
|
|
26
|
+
# objects visited before the refusal twice.
|
|
21
27
|
#
|
|
22
28
|
# Not rerouted: obj.to_json (core extensions drive the gem's generator
|
|
23
29
|
# directly), and objects with a custom to_json inside a rerouted
|
|
@@ -30,15 +36,26 @@ module NOSJ
|
|
|
30
36
|
# Implementation detail of `require "nosj/json"`.
|
|
31
37
|
# @private
|
|
32
38
|
module JSONDropIn
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
|
|
39
|
+
# json 3 made parse's options keyword-only, fixed dump's defaults and
|
|
40
|
+
# raises for options json 2 ignored or aliased.
|
|
41
|
+
JSON3 = ::JSON::VERSION.to_i >= 3
|
|
42
|
+
|
|
36
43
|
PARSE_OPTS = %i[symbolize_names freeze max_nesting allow_nan
|
|
37
|
-
allow_trailing_comma
|
|
44
|
+
allow_trailing_comma allow_duplicate_key].freeze
|
|
45
|
+
# json 2 ignores quirks_mode, which Rails 7.x passes from
|
|
46
|
+
# ActiveSupport::JSON.decode, so its fast path takes the key and
|
|
47
|
+
# drops it (NOSJ.parse always parses top-level scalars, and refuses
|
|
48
|
+
# unknown keys). json 3 raises for it, so there it reaches the gem
|
|
49
|
+
# like any other unknown option.
|
|
50
|
+
QUIRKS_MODE = :quirks_mode
|
|
51
|
+
JSON2_PARSE_OPTS = (PARSE_OPTS + [QUIRKS_MODE]).freeze
|
|
38
52
|
GENERATE_OPTS = %i[indent space space_before object_nl array_nl
|
|
39
|
-
max_nesting allow_nan ascii_only script_safe
|
|
40
|
-
|
|
41
|
-
|
|
53
|
+
max_nesting allow_nan ascii_only script_safe strict depth
|
|
54
|
+
buffer_initial_length allow_duplicate_key].freeze
|
|
55
|
+
JSON3_DUMP_DEFAULTS = {allow_nan: true}.freeze
|
|
56
|
+
# json 2.10 and older accept only strict: in dump's options hash,
|
|
57
|
+
# through this private helper; later versions merge any option.
|
|
58
|
+
DUMP_MERGES_OPTIONS = !::JSON.respond_to?(:merge_dump_options, true)
|
|
42
59
|
|
|
43
60
|
module_function
|
|
44
61
|
|
|
@@ -52,6 +69,13 @@ module NOSJ
|
|
|
52
69
|
true
|
|
53
70
|
end
|
|
54
71
|
|
|
72
|
+
# Generate options the fast path handles: supported keys, minus the
|
|
73
|
+
# one combination NOSJ refuses (ascii_only with script_safe, which
|
|
74
|
+
# json supports).
|
|
75
|
+
def generate_supported?(opts)
|
|
76
|
+
supported?(opts, GENERATE_OPTS) && !(opts && opts[:ascii_only] && opts[:script_safe])
|
|
77
|
+
end
|
|
78
|
+
|
|
55
79
|
def parse(source, opts)
|
|
56
80
|
# NOSJ.parse is deliberately strict about encodings (json-3.0
|
|
57
81
|
# semantics), but the drop-in must match the installed gem, which
|
|
@@ -61,30 +85,60 @@ module NOSJ
|
|
|
61
85
|
# (copy-on-write bytes), and the validity scan is memoized
|
|
62
86
|
# coderange the parse would compute anyway. Anything else
|
|
63
87
|
# non-UTF-8 (UTF-16, ...) belongs to gem json, which transcodes.
|
|
88
|
+
input = source
|
|
64
89
|
if source.is_a?(String)
|
|
65
90
|
case source.encoding
|
|
66
91
|
when Encoding::UTF_8, Encoding::US_ASCII
|
|
67
92
|
# the fast path as-is
|
|
68
93
|
when Encoding::BINARY
|
|
69
94
|
utf8 = source.dup.force_encoding(Encoding::UTF_8)
|
|
70
|
-
|
|
95
|
+
input = utf8 if utf8.valid_encoding?
|
|
71
96
|
else
|
|
72
|
-
return
|
|
97
|
+
return original_parse(source, opts)
|
|
73
98
|
end
|
|
74
99
|
end
|
|
75
|
-
NOSJ.parse(
|
|
76
|
-
rescue NOSJ::NestingError
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
100
|
+
NOSJ.parse(input, opts)
|
|
101
|
+
rescue NOSJ::ParserError, NOSJ::NestingError
|
|
102
|
+
original_parse(source, opts)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# json 2's options without quirks_mode (see QUIRKS_MODE), allocating
|
|
106
|
+
# nothing for Rails' lone `quirks_mode: true`.
|
|
107
|
+
def without_quirks_mode(opts)
|
|
108
|
+
return opts unless opts&.key?(QUIRKS_MODE)
|
|
109
|
+
if opts.size == 1
|
|
110
|
+
nil
|
|
111
|
+
else
|
|
112
|
+
opts.except(QUIRKS_MODE)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# The installed gem's parse. json 3 takes keywords only; json 2's
|
|
117
|
+
# positional options hash receives them just the same.
|
|
118
|
+
def original_parse(source, opts)
|
|
119
|
+
::JSON.nosj_original_parse(source, **(opts || {}))
|
|
80
120
|
end
|
|
81
121
|
|
|
82
122
|
def generate(obj, opts, pretty)
|
|
83
123
|
pretty ? NOSJ.pretty_generate(obj, opts) : NOSJ.generate(obj, opts)
|
|
84
|
-
rescue NOSJ::NestingError
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
124
|
+
rescue NOSJ::GeneratorError, NOSJ::NestingError
|
|
125
|
+
if pretty
|
|
126
|
+
::JSON.nosj_original_pretty_generate(obj, opts)
|
|
127
|
+
else
|
|
128
|
+
::JSON.nosj_original_generate(obj, opts)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# The options JSON.dump generates with before the caller's own: fixed
|
|
133
|
+
# in json 3; json 2 reads its user-settable dump_default_options,
|
|
134
|
+
# through the internal reader 2.11 added when it deprecated the
|
|
135
|
+
# public one. Which one is decided here, once.
|
|
136
|
+
if JSON3
|
|
137
|
+
def dump_defaults = JSON3_DUMP_DEFAULTS
|
|
138
|
+
elsif ::JSON.respond_to?(:_dump_default_options)
|
|
139
|
+
def dump_defaults = ::JSON._dump_default_options
|
|
140
|
+
else
|
|
141
|
+
def dump_defaults = ::JSON.dump_default_options
|
|
88
142
|
end
|
|
89
143
|
end
|
|
90
144
|
end
|
|
@@ -101,16 +155,26 @@ module JSON
|
|
|
101
155
|
alias_method :nosj_original_pretty_generate, :pretty_generate
|
|
102
156
|
alias_method :nosj_original_dump, :dump
|
|
103
157
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
NOSJ::JSONDropIn.
|
|
107
|
-
|
|
108
|
-
|
|
158
|
+
if NOSJ::JSONDropIn::JSON3
|
|
159
|
+
def parse(source, **opts)
|
|
160
|
+
if NOSJ::JSONDropIn.supported?(opts, NOSJ::JSONDropIn::PARSE_OPTS)
|
|
161
|
+
NOSJ::JSONDropIn.parse(source, opts)
|
|
162
|
+
else
|
|
163
|
+
nosj_original_parse(source, **opts)
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
else
|
|
167
|
+
def parse(source, opts = nil)
|
|
168
|
+
if NOSJ::JSONDropIn.supported?(opts, NOSJ::JSONDropIn::JSON2_PARSE_OPTS)
|
|
169
|
+
NOSJ::JSONDropIn.parse(source, NOSJ::JSONDropIn.without_quirks_mode(opts))
|
|
170
|
+
else
|
|
171
|
+
nosj_original_parse(source, opts)
|
|
172
|
+
end
|
|
109
173
|
end
|
|
110
174
|
end
|
|
111
175
|
|
|
112
176
|
def generate(obj, opts = nil)
|
|
113
|
-
if NOSJ::JSONDropIn.
|
|
177
|
+
if NOSJ::JSONDropIn.generate_supported?(opts)
|
|
114
178
|
NOSJ::JSONDropIn.generate(obj, opts, false)
|
|
115
179
|
else
|
|
116
180
|
nosj_original_generate(obj, opts)
|
|
@@ -118,7 +182,7 @@ module JSON
|
|
|
118
182
|
end
|
|
119
183
|
|
|
120
184
|
def pretty_generate(obj, opts = nil)
|
|
121
|
-
if NOSJ::JSONDropIn.
|
|
185
|
+
if NOSJ::JSONDropIn.generate_supported?(opts)
|
|
122
186
|
NOSJ::JSONDropIn.generate(obj, opts, true)
|
|
123
187
|
else
|
|
124
188
|
nosj_original_pretty_generate(obj, opts)
|
|
@@ -127,17 +191,19 @@ module JSON
|
|
|
127
191
|
|
|
128
192
|
def dump(obj, an_io = nil, limit = nil, kwargs = nil)
|
|
129
193
|
# Fast path for the common shapes, dump(obj) and dump(obj, opts
|
|
130
|
-
# hash)
|
|
131
|
-
#
|
|
132
|
-
#
|
|
133
|
-
|
|
134
|
-
|
|
194
|
+
# hash): the installed gem's dump defaults merged under the
|
|
195
|
+
# caller's options. IO and limit arguments, and anything the
|
|
196
|
+
# fast path refuses, take gem json's own dump, which also turns
|
|
197
|
+
# json 2's NestingError into its ArgumentError.
|
|
198
|
+
if limit.nil? && kwargs.nil? &&
|
|
199
|
+
(an_io.nil? || NOSJ::JSONDropIn::DUMP_MERGES_OPTIONS && an_io.instance_of?(Hash))
|
|
200
|
+
opts = NOSJ::JSONDropIn.dump_defaults
|
|
135
201
|
opts = opts.merge(an_io) if an_io
|
|
136
|
-
if NOSJ::JSONDropIn.
|
|
202
|
+
if NOSJ::JSONDropIn.generate_supported?(opts)
|
|
137
203
|
begin
|
|
138
|
-
return NOSJ
|
|
139
|
-
rescue ::
|
|
140
|
-
|
|
204
|
+
return NOSJ.generate(obj, opts)
|
|
205
|
+
rescue NOSJ::GeneratorError, NOSJ::NestingError
|
|
206
|
+
# the gem's own dump below runs it again and decides
|
|
141
207
|
end
|
|
142
208
|
end
|
|
143
209
|
end
|
data/lib/nosj/version.rb
CHANGED
data/lib/nosj.rb
CHANGED
|
@@ -86,10 +86,13 @@ module NOSJ
|
|
|
86
86
|
# Parses a JSON document, JSON.parse-compatible: same values, same
|
|
87
87
|
# option names, same behavior, byte-for-byte.
|
|
88
88
|
#
|
|
89
|
-
#
|
|
90
|
-
# (
|
|
91
|
-
# +
|
|
92
|
-
#
|
|
89
|
+
# Options follow json 3: an unknown key raises ArgumentError
|
|
90
|
+
# (<code>unknown keyword: foo</code>). The json options nosj does not
|
|
91
|
+
# implement (+object_class+, +array_class+, +decimal_class+,
|
|
92
|
+
# +on_load+, +create_additions+, +allow_comments+,
|
|
93
|
+
# +allow_control_characters+, +allow_invalid_escape+) raise
|
|
94
|
+
# ArgumentError unless falsy, since their falsy default is nosj's
|
|
95
|
+
# behavior.
|
|
93
96
|
#
|
|
94
97
|
# @example
|
|
95
98
|
# NOSJ.parse('{"a":[1,true]}') #=> {"a" => [1, true]}
|
|
@@ -98,12 +101,14 @@ module NOSJ
|
|
|
98
101
|
# @param source [String] the JSON document (UTF-8 or US-ASCII)
|
|
99
102
|
# @param opts [Hash, nil] +symbolize_names+, +freeze+, +max_nesting+
|
|
100
103
|
# (Integer or +false+ for unlimited), +allow_nan+,
|
|
101
|
-
# +allow_trailing_comma+
|
|
104
|
+
# +allow_trailing_comma+, +allow_duplicate_key+ (json 3 semantics:
|
|
105
|
+
# a repeated key raises unless this is true, then the last one wins)
|
|
102
106
|
# @return [Object] the parsed value tree
|
|
103
|
-
# @raise [ParserError] when the document is malformed
|
|
104
|
-
#
|
|
107
|
+
# @raise [ParserError] when the document is malformed, repeats a key,
|
|
108
|
+
# holds a lone surrogate (+"\udc00"+), or is not UTF-8; carries the
|
|
109
|
+
# failure position ({ParserError#line} and friends)
|
|
105
110
|
# @raise [NestingError] when nesting exceeds +max_nesting+
|
|
106
|
-
# @raise [ArgumentError] for unsupported options
|
|
111
|
+
# @raise [ArgumentError] for unknown or unsupported options
|
|
107
112
|
def self.parse(source, opts = nil)
|
|
108
113
|
parse_native(source, opts)
|
|
109
114
|
end
|
|
@@ -119,12 +124,18 @@ module NOSJ
|
|
|
119
124
|
# @param obj [Object] the value tree to serialize
|
|
120
125
|
# @param opts [Hash, nil] +indent+, +space+, +space_before+,
|
|
121
126
|
# +object_nl+, +array_nl+, +max_nesting+ (Integer or +false+),
|
|
122
|
-
# +allow_nan+, +ascii_only+, +script_safe+
|
|
123
|
-
# +
|
|
127
|
+
# +allow_nan+, +ascii_only+, +script_safe+, +strict+, +depth+,
|
|
128
|
+
# +buffer_initial_length+, +allow_duplicate_key+ (json 3
|
|
129
|
+
# semantics: keys that render alike, like <code>"a"</code> and
|
|
130
|
+
# <code>:a</code>, raise unless true). As in json 3, an unknown
|
|
131
|
+
# key raises (+escape_slash+ is gone: use +script_safe+), and the
|
|
132
|
+
# unimplemented +sort_keys+ and +as_json+ raise unless falsy.
|
|
124
133
|
# @return [String] the JSON document
|
|
125
134
|
# @raise [GeneratorError] for non-finite floats without +allow_nan+,
|
|
126
|
-
# unsupported objects under +strict+,
|
|
135
|
+
# unsupported objects under +strict+, keys that render alike, or
|
|
136
|
+
# broken string encodings
|
|
127
137
|
# @raise [NestingError] when nesting exceeds +max_nesting+
|
|
138
|
+
# @raise [ArgumentError] for unknown or unsupported options
|
|
128
139
|
|
|
129
140
|
# Generates human-readable JSON, JSON.pretty_generate-compatible
|
|
130
141
|
# (two-space indent, newlines between elements). Options override the
|
|
@@ -156,7 +167,7 @@ module NOSJ
|
|
|
156
167
|
# @param source [String] the JSON document
|
|
157
168
|
# @param opts [Hash, nil] same options as {.parse}
|
|
158
169
|
# @return [Boolean]
|
|
159
|
-
# @raise [ArgumentError] for unsupported options
|
|
170
|
+
# @raise [ArgumentError] for unknown or unsupported options
|
|
160
171
|
def self.valid?(source, opts = nil)
|
|
161
172
|
valid_native(source, opts)
|
|
162
173
|
end
|
|
@@ -205,7 +216,8 @@ module NOSJ
|
|
|
205
216
|
|
|
206
217
|
# Partial parsing by JSON Pointer (with the standard +~0+/+~1+
|
|
207
218
|
# escapes). The matched subtree materializes under the same options
|
|
208
|
-
# as {.parse}
|
|
219
|
+
# as {.parse}; +allow_nan+ and +allow_trailing_comma+ also govern the
|
|
220
|
+
# walk to it.
|
|
209
221
|
#
|
|
210
222
|
# @example
|
|
211
223
|
# NOSJ.at_pointer(json, "/users/3/name") #=> "grace" or nil
|
|
@@ -322,18 +334,19 @@ module NOSJ
|
|
|
322
334
|
# Minifies a document without building any Ruby values: the parser's
|
|
323
335
|
# events pipe straight into the emission kernels, SIMD in and SIMD
|
|
324
336
|
# out. Output is exactly what <code>generate(parse(json))</code>
|
|
325
|
-
# would produce,
|
|
326
|
-
#
|
|
327
|
-
#
|
|
328
|
-
#
|
|
337
|
+
# would produce, and it accepts exactly what {.parse} accepts; under
|
|
338
|
+
# +allow_duplicate_key+, repeated keys pass through instead of being
|
|
339
|
+
# collapsed (a reformatter must not silently drop data). Numbers come
|
|
340
|
+
# out in the canonical spelling (+1.50+ becomes +1.5+) and string
|
|
341
|
+
# escapes are normalized.
|
|
329
342
|
#
|
|
330
343
|
# @example
|
|
331
344
|
# NOSJ.minify(%({ "a": [1, 2],\n "b": "x" })) #=> '{"a":[1,2],"b":"x"}'
|
|
332
345
|
#
|
|
333
346
|
# @param json [String] the document (UTF-8 or US-ASCII)
|
|
334
347
|
# @param opts [Hash, nil] acceptance options (+allow_nan+,
|
|
335
|
-
# +allow_trailing_comma+, +max_nesting+);
|
|
336
|
-
# normalized away when accepted
|
|
348
|
+
# +allow_trailing_comma+, +allow_duplicate_key+, +max_nesting+);
|
|
349
|
+
# trailing commas are normalized away when accepted
|
|
337
350
|
# @return [String] the minified document
|
|
338
351
|
# @raise [ParserError] when the document is malformed
|
|
339
352
|
# @raise [NestingError] past +max_nesting+
|
|
@@ -357,8 +370,7 @@ module NOSJ
|
|
|
357
370
|
# @return [String] the reformatted document
|
|
358
371
|
# @raise [ParserError] when the document is malformed
|
|
359
372
|
# @raise [NestingError] past +max_nesting+
|
|
360
|
-
# @raise [GeneratorError]
|
|
361
|
-
# string it cannot represent
|
|
373
|
+
# @raise [GeneratorError] for a non-finite float without +allow_nan+
|
|
362
374
|
def self.reformat(json, opts = nil)
|
|
363
375
|
if opts&.key?(:pretty)
|
|
364
376
|
pretty = opts[:pretty]
|
|
@@ -597,7 +609,9 @@ module NOSJ
|
|
|
597
609
|
#
|
|
598
610
|
# @param source [String] the JSON document (UTF-8 or US-ASCII)
|
|
599
611
|
# @param opts [Hash, nil] +max_nesting+, +allow_nan+,
|
|
600
|
-
# +allow_trailing_comma+ (acceptance options only)
|
|
612
|
+
# +allow_trailing_comma+ (acceptance options only). Being a
|
|
613
|
+
# diagnostic, stats also describes documents {.parse} would refuse
|
|
614
|
+
# for a repeated key or a lone surrogate.
|
|
601
615
|
# @return [Hash] the statistics described above
|
|
602
616
|
# @raise [ParserError] when the document is malformed or not UTF-8
|
|
603
617
|
def self.stats(source, opts = nil)
|
data/sig/nosj.rbs
CHANGED
|
@@ -14,9 +14,10 @@ module NOSJ
|
|
|
14
14
|
# Options arrive as a positional Hash (the JSON gem's own calling
|
|
15
15
|
# convention; an explicit **kwargs would allocate per call), nil when
|
|
16
16
|
# omitted. Parse: symbolize_names, freeze, max_nesting, allow_nan,
|
|
17
|
-
# allow_trailing_comma. Generate: indent, space,
|
|
18
|
-
# object_nl, array_nl, max_nesting, allow_nan,
|
|
19
|
-
# script_safe
|
|
17
|
+
# allow_trailing_comma, allow_duplicate_key. Generate: indent, space,
|
|
18
|
+
# space_before, object_nl, array_nl, max_nesting, allow_nan,
|
|
19
|
+
# ascii_only, script_safe, strict, depth, buffer_initial_length,
|
|
20
|
+
# allow_duplicate_key. Unknown keys raise ArgumentError (json 3).
|
|
20
21
|
type opts = Hash[Symbol, untyped]?
|
|
21
22
|
|
|
22
23
|
# One NOSJ.dig path element (negative Integer indices resolve to nil).
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: nosj
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Yaroslav Markin
|
|
@@ -66,7 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
67
|
version: 3.3.11
|
|
68
68
|
requirements: []
|
|
69
|
-
rubygems_version: 4.0.
|
|
69
|
+
rubygems_version: 4.0.20
|
|
70
70
|
specification_version: 4
|
|
71
71
|
summary: An extremely fast JSON parser and generator for Ruby, written in Rust and
|
|
72
72
|
SIMD-accelerated on every platform.
|