nosj 0.1.0-x86_64-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 +7 -0
- data/CHANGELOG.md +10 -0
- data/LICENSE.txt +21 -0
- data/NOTICE +13 -0
- data/README.md +214 -0
- 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 +124 -0
- data/lib/nosj/multi_json.rb +51 -0
- data/lib/nosj/native.rb +11 -0
- data/lib/nosj/version.rb +6 -0
- data/lib/nosj.rb +193 -0
- data/sig/nosj.rbs +61 -0
- metadata +67 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 0a0fd640bbecb91b12ed17a8ee5edc5b87befe85b1fcdcd124c58624255b3d02
|
|
4
|
+
data.tar.gz: 6cc111ee1c0a1d55640325d48e5b71fad155f18d218211a9fcaf2f3f2a3a54b7
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 6dcc90744851a53f59a088e2ea4429ece7df99e2b72cbe81d049818641beb500b6847b9a3d9f703094c6d2f9aec669c89ab3ae652d47d29a8f3cefe0ee195ba9
|
|
7
|
+
data.tar.gz: 1f50198d497a46a8abbd281934ce3a04e5a704a1cbec221e2cf1dc0d570de817e447c4eb580c61e288960d5c797ba8f3f7b5e9215e85f90b439ae02e9dce57db
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## [0.1.0] - 2026-07-15
|
|
2
|
+
|
|
3
|
+
Initial release.
|
|
4
|
+
|
|
5
|
+
- `NOSJ.parse`, `NOSJ.generate`, and `NOSJ.pretty_generate`: `json`-gem-compatible parsing and generation—same output bytes, same option names, same error classes and messages—built on the first-party SIMD [nosj](https://crates.io/crates/nosj) crate (NEON on Apple Silicon; SSE2/AVX2 on x86-64, selected at runtime). Faster than the `json` gem and the third-party parsers (Oj, RapidJSON, FastJsonparser, Yajl) across the benchmark corpus, in both directions.
|
|
6
|
+
- Partial parsing: `NOSJ.dig` and `NOSJ.at_pointer` resolve a JSON Pointer and materialize only the matched subtree; `NOSJ.dig_many` and `NOSJ.at_pointers` resolve whole batches of paths in a single pass over the document.
|
|
7
|
+
- `NOSJ.valid?`: full-strictness validation that allocates no Ruby objects.
|
|
8
|
+
- Drop-in acceleration: `require "nosj/json"` reroutes `JSON.parse`, `JSON.generate`, `JSON.pretty_generate`, and `JSON.dump` through nosj, falling back to the original implementation for unsupported options; `require "nosj/multi_json"` adds a MultiJson adapter.
|
|
9
|
+
- Precompiled platform gems, each built natively with profile-guided optimization: Linux x86-64 and arm64 (glibc and musl), macOS (Apple Silicon), Windows (x64), for Ruby 3.3 through 4.0. Other platforms compile the source gem.
|
|
10
|
+
- RBS signatures and full YARD documentation.
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yaroslav Markin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/NOTICE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
nosj (Ruby gem)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yaroslav Markin. Released under the MIT License
|
|
4
|
+
(see LICENSE.txt).
|
|
5
|
+
|
|
6
|
+
Every distribution of this gem embeds the nosj Rust crate
|
|
7
|
+
(https://github.com/yaroslav/nosj), compiled into the native
|
|
8
|
+
extension: precompiled platform gems ship the compiled binary, and the
|
|
9
|
+
source gem compiles the crate at install time. The crate is licensed
|
|
10
|
+
MIT AND BSL-1.0 AND Apache-2.0; its NOTICE file itemizes the derived
|
|
11
|
+
components (the fpconv/Grisu2 float formatter under BSL-1.0; the
|
|
12
|
+
fast_float decimal conversion and simdjson structural-indexing
|
|
13
|
+
techniques under Apache-2.0) and reproduces each component license.
|
data/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# gem nosj
|
|
2
|
+
|
|
3
|
+
**gem nosj** is an **very fast JSON parser and generator for Ruby**, written in Rust on the first-party [nosj](https://github.com/yaroslav/nosj) crate and **SIMD-accelerated** on every platform (NEON on Apple Silicon, SSE2/AVX2 on x86-64).
|
|
4
|
+
|
|
5
|
+
> gem nosj is the powerful evil twin of the json gem.
|
|
6
|
+
|
|
7
|
+
[](https://github.com/yaroslav/nosj-ruby/releases)
|
|
8
|
+
[](https://rubydoc.info/gems/nosj)
|
|
9
|
+
|
|
10
|
+
- It is **faster** than gem json and every
|
|
11
|
+
third-party parser, including Oj, RapidJSON, FastJsonparser, Yajl. 1.0–1.8× faster than the bundled json gem, 1.3–11× faster than Oj, and up to 17×
|
|
12
|
+
faster than Yajl—[see Benchmarks](#benchmarks).
|
|
13
|
+
- It comes **precompiled** (platform gems built with per-platform optimizations,
|
|
14
|
+
nothing to compile on install).
|
|
15
|
+
- It has a **partial parsing mode**: JSON Pointer lookups that pull single values out of big documents in microseconds, skipping everything else.
|
|
16
|
+
- Same API and option names as gem json.
|
|
17
|
+
|
|
18
|
+
**And there's more**: validate documents without building a single Ruby object, resolve whole batches of paths in one pass, and accelerate an entire application with a one-line drop-in.
|
|
19
|
+
|
|
20
|
+
- [Requirements](#requirements)
|
|
21
|
+
- [Getting started](#getting-started)
|
|
22
|
+
- [What's in the box](#whats-in-the-box)
|
|
23
|
+
- [Benchmarks](#benchmarks)
|
|
24
|
+
- [Switching from the json gem](#switching-from-the-json-gem)
|
|
25
|
+
- [How it works](#how-it-works)
|
|
26
|
+
- [Development](#development)
|
|
27
|
+
- [License](#license)
|
|
28
|
+
|
|
29
|
+
## Requirements
|
|
30
|
+
|
|
31
|
+
- **Ruby 3.3 or newer** (CRuby; tested on 3.3, 3.4, and 4.0).
|
|
32
|
+
- **Linux** (x86-64 and arm64, glibc and musl), **macOS** (Apple
|
|
33
|
+
Silicon), or **Windows** (x64): these platforms install precompiled,
|
|
34
|
+
per-platform-optimized gems with nothing to build.
|
|
35
|
+
|
|
36
|
+
## Getting started
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
bundle add nosj
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
require "nosj"
|
|
44
|
+
|
|
45
|
+
NOSJ.parse('{"a":[1,true]}') #=> {"a" => [1, true]}
|
|
46
|
+
NOSJ.generate({"a" => [1, true]}) #=> '{"a":[1,true]}'
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
That's it—if you know the `json` gem, you already know `nosj`.
|
|
50
|
+
|
|
51
|
+
Want the speedup without touching your code? One line reroutes
|
|
52
|
+
`JSON.parse`, `JSON.generate`, `JSON.pretty_generate`, and `JSON.dump`
|
|
53
|
+
through nosj:
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
require "nosj/json"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
In a Bundler app (Rails included) that can live entirely in the
|
|
60
|
+
Gemfile you can do this:
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
gem "nosj", require: "nosj/json"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Options nosj supports take the fast path; anything exotic
|
|
67
|
+
(`create_additions`, `object_class`, `JSON::State`, procs, IO
|
|
68
|
+
arguments) falls back to the original implementation, so `JSON.load`,
|
|
69
|
+
`JSON.parse!`, and `JSON.load_file` keep their exact behavior.
|
|
70
|
+
Exceptions re-raise as the JSON classes, so your rescue clauses keep
|
|
71
|
+
working. Measured through the patch: parse 1.11×, generate 1.05× over
|
|
72
|
+
the original gem. (A MultiJson adapter ships too:
|
|
73
|
+
`require "nosj/multi_json"`, then `MultiJson.use NOSJ::MultiJsonAdapter`.)
|
|
74
|
+
|
|
75
|
+
## What's in the box
|
|
76
|
+
|
|
77
|
+
**The `json` gem API**, on the `NOSJ` module:
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
NOSJ.parse(src, symbolize_names: true) # also: freeze, max_nesting,
|
|
81
|
+
# allow_nan, allow_trailing_comma
|
|
82
|
+
NOSJ.generate(obj) # indent, space, object_nl, ...,
|
|
83
|
+
NOSJ.pretty_generate(obj) # ascii_only, script_safe, strict
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Validation without parsing.** `NOSJ.valid?` runs the full
|
|
87
|
+
parser—tokenizers, string decode, number validation—into a null sink
|
|
88
|
+
and allocates no Ruby objects at all. It is 2-4× faster than
|
|
89
|
+
`NOSJ.parse`, which already leads every parser above:
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
NOSJ.valid?('{"a":1}') #=> true
|
|
93
|
+
NOSJ.valid?('{"a":}') #=> false
|
|
94
|
+
NOSJ.valid?(src, max_nesting: false) # same options as parse
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Partial parsing.** Pull values out of a document without
|
|
98
|
+
materializing the rest—skipped content is stepped over at SIMD block
|
|
99
|
+
speed, so a lookup costs what it skips, not what the document weighs:
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
NOSJ.dig(json, "users", 3, "name") # Hash#dig-shaped
|
|
103
|
+
NOSJ.at_pointer(json, "/users/3/name") # JSON Pointer
|
|
104
|
+
|
|
105
|
+
# Many lookups in one pass. A batch costs about as much as its
|
|
106
|
+
# single deepest member:
|
|
107
|
+
NOSJ.at_pointers(json, ["/users/3/name", "/meta/count"])
|
|
108
|
+
NOSJ.dig_many(json, [["users", 3, "name"], ["meta", "count"]])
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Example: an early field resolves in ~0.35µs where `JSON.parse(json).dig(...)`
|
|
112
|
+
costs ~980µs on the same document—three orders of magnitude. A field
|
|
113
|
+
at the far end of a 570 KB document costs ~71µs, still 13× faster
|
|
114
|
+
than parse-then-dig. Misses return nil; matched subtrees materialize
|
|
115
|
+
with the same options as `parse` (`symbolize_names:`, `freeze:`).
|
|
116
|
+
|
|
117
|
+
## Benchmarks
|
|
118
|
+
|
|
119
|
+
Every installed JSON gem, benchmark-ips: AWS EC2 c7a.2xlarge (AMD EPYC 9R14, Zen 4), Ruby 4.0.6 + YJIT, json 2.21.1, Oj 3.17.4, RapidJSON 0.4.0, FastJsonparser 0.6.0, Yajl 1.4.3, PGO build, 2026-07-16. `×N` = times slower than nosj.
|
|
120
|
+
|
|
121
|
+
Parse:
|
|
122
|
+
|
|
123
|
+
| file | nosj (i/s) | json | Oj | FastJsonparser | RapidJSON | Yajl |
|
|
124
|
+
|---|---:|---:|---:|---:|---:|---:|
|
|
125
|
+
| activitypub | **12.4k** | ×1.18 | ×1.53 | ×1.89 | ×1.99 | ×4.57 |
|
|
126
|
+
| canada | **248** | ×1.10 | ×8.28 | ×1.45 | ×1.51 | ×4.96 |
|
|
127
|
+
| citm_catalog | **504** | ×1.03 | ×1.97 | ×2.07 | ×1.83 | ×4.93 |
|
|
128
|
+
| gsoc-2018 | **397** | ×1.30 | ×1.47 | ×1.81 | ×1.80 | ×4.78 |
|
|
129
|
+
| homebrew-formula | **15.2** | ×1.13 | ×1.54 | ×2.42 | ×2.02 | ×4.30 |
|
|
130
|
+
| homebrew-llvm | **49.3k** | ×1.60 | ×1.48 | ×1.50 | ×1.85 | ×5.11 |
|
|
131
|
+
| mesh | **1.1k** | ×1.30 | ×3.93 | ×1.82 | ×1.95 | ×6.96 |
|
|
132
|
+
| numbers | **5.9k** | ×1.19 | ×4.64 | ×1.43 | ×1.75 | ×7.04 |
|
|
133
|
+
| ohai | **14.4k** | ×1.47 | ×1.61 | ×2.11 | ×1.97 | ×4.71 |
|
|
134
|
+
| simple | **977k** | ×1.31 | ×1.77 | ×2.08 | ×1.63 | ×5.15 |
|
|
135
|
+
| small_mixed | **3.2M** | ×1.48 | ×2.85 | ×2.44 | ×1.82 | ×6.75 |
|
|
136
|
+
| tolstoy | **8.9k** | ×1.79 | ×1.96 | ×2.29 | ×2.10 | ×17.31 |
|
|
137
|
+
| twitter | **1.1k** | ×1.09 | ×1.83 | ×2.25 | ×2.61 | ×5.40 |
|
|
138
|
+
|
|
139
|
+
Generate:
|
|
140
|
+
|
|
141
|
+
| file | nosj (i/s) | json | Oj | RapidJSON | Yajl |
|
|
142
|
+
|---|---:|---:|---:|---:|---:|
|
|
143
|
+
| activitypub | **34.8k** | ×1.20 | ×1.78 | ×2.41 | ×5.84 |
|
|
144
|
+
| canada | **150** | ×0.98\* | ×10.98 | ×11.20 | ×10.87 |
|
|
145
|
+
| citm_catalog | **1.3k** | ×1.04 | ×1.44 | ×1.55 | ×2.85 |
|
|
146
|
+
| gsoc-2018 | **1.1k** | ×1.28 | ×2.64 | ×3.64 | ×11.00 |
|
|
147
|
+
| homebrew-formula | **20.9** | ×1.07 | ×1.25 | ×1.62 | ×3.03 |
|
|
148
|
+
| homebrew-llvm | **71.5k** | ×1.23 | ×2.22 | ×3.04 | ×5.80 |
|
|
149
|
+
| mesh | **613** | ×1.08 | ×9.24 | ×9.40 | ×9.26 |
|
|
150
|
+
| numbers | **2.1k** | ×1.03 | ×10.63 | ×11.00 | ×10.69 |
|
|
151
|
+
| ohai | **39.4k** | ×1.07 | ×1.29 | ×1.50 | ×3.37 |
|
|
152
|
+
| simple | **2.2M** | ×1.03 | ×1.58 | ×1.62 | ×4.36 |
|
|
153
|
+
| small_mixed | **5.6M** | ×1.09 | ×2.26 | ×1.83 | ×7.16 |
|
|
154
|
+
| tolstoy | **8.3k** | ×1.30 | ×4.15 | ×6.50 | ×14.54 |
|
|
155
|
+
| twitter | **2.9k** | ×1.09 | ×1.46 | ×2.01 | ×4.05 |
|
|
156
|
+
|
|
157
|
+
\* canada-generate is a statistical tie with the json gem (within
|
|
158
|
+
measurement error).
|
|
159
|
+
|
|
160
|
+
Reproduce with `rake bench` (the parity-gated comparison, after a PGO retrain—the shipping configuration) or `rake bench:ips` (the multi-gem shoot-out).
|
|
161
|
+
|
|
162
|
+
## Switching from the json gem
|
|
163
|
+
|
|
164
|
+
You mostly don't have to do anything. Some differences:
|
|
165
|
+
|
|
166
|
+
- The legacy object-deserialization options (`create_additions`,
|
|
167
|
+
`object_class`, `array_class`, `decimal_class`) raise ArgumentError;
|
|
168
|
+
the `nosj/json` drop-in falls back to the original gem for them.
|
|
169
|
+
- Behaviors the `json` gem itself deprecates (JS comments, raw invalid
|
|
170
|
+
UTF-8) follow the strict semantics instead.
|
|
171
|
+
- Unlike `Array#dig`, negative indices in `NOSJ.dig` return nil (JSON
|
|
172
|
+
Pointer has no equivalent).
|
|
173
|
+
- Parse error *messages* use byte offsets rather than the gem's
|
|
174
|
+
phrasing (classes match).
|
|
175
|
+
|
|
176
|
+
Everything else—including the gem's exact float formatting, which is
|
|
177
|
+
not the shortest-round-trip form most libraries emit—matches
|
|
178
|
+
byte-for-byte and is verified continuously against the full corpus.
|
|
179
|
+
|
|
180
|
+
## How it works
|
|
181
|
+
|
|
182
|
+
Most fast parsers build their own tree first and convert it into Ruby
|
|
183
|
+
objects second, paying for every string and container twice. nosj is
|
|
184
|
+
built on the [nosj](https://github.com/yaroslav/nosj) Rust crate, an
|
|
185
|
+
event parser with no tree of its own:
|
|
186
|
+
|
|
187
|
+
- **No intermediate tree.** The crate parses with NEON/SSE2/AVX2 SIMD
|
|
188
|
+
kernels and emits *events*; the extension builds interned hash keys,
|
|
189
|
+
strings, and containers directly on Ruby's heap during the parse,
|
|
190
|
+
with GC-safe value stacks and epoch-evicted key caches. Generation
|
|
191
|
+
walks Ruby objects once, streaming through fused scan-and-store
|
|
192
|
+
escape kernels.
|
|
193
|
+
- **Byte-exact floats.** Output reproduces the json gem's fpconv
|
|
194
|
+
(Grisu2) float format digit for digit—round-tripping is verified,
|
|
195
|
+
not assumed.
|
|
196
|
+
- **PGO everywhere.** Local builds, CI, and every precompiled platform
|
|
197
|
+
gem train on the benchmark corpus before the shipping compile; the
|
|
198
|
+
precompiled binaries use portable codegen with SIMD tiers detected at
|
|
199
|
+
runtime.
|
|
200
|
+
|
|
201
|
+
## Development
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
bundle exec rake compile # build the extension (applies a PGO profile if present)
|
|
205
|
+
bundle exec rake spec # the gem-parity suite
|
|
206
|
+
bundle exec rake bench # PGO retrain + the parity-gated sweep vs the json gem
|
|
207
|
+
bundle exec rake bench:fast # the sweep without retraining
|
|
208
|
+
bundle exec rake "bench:ips[twitter]" # multi-gem shoot-out (benchmark-ips); no args = full corpus
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
MIT. The underlying Rust crate is `MIT AND BSL-1.0 AND Apache-2.0`; its
|
|
214
|
+
NOTICE file itemizes the derived components.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/lib/nosj/json.rb
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Drop-in acceleration for the JSON module:
|
|
4
|
+
#
|
|
5
|
+
# require "nosj/json"
|
|
6
|
+
#
|
|
7
|
+
# reroutes JSON.parse, JSON.generate, JSON.pretty_generate and JSON.dump
|
|
8
|
+
# through NOSJ whenever the requested options fall within NOSJ's
|
|
9
|
+
# supported set, and falls back to the original json implementation for
|
|
10
|
+
# everything else (create_additions, object_class/array_class,
|
|
11
|
+
# decimal_class, on_load procs, JSON::State instances, IO arguments).
|
|
12
|
+
# Entry points built on JSON.parse (JSON.load, JSON.parse!,
|
|
13
|
+
# JSON.load_file, JSON.unsafe_load) pick up the fast path automatically
|
|
14
|
+
# and keep their exact legacy behavior when they need unsupported options
|
|
15
|
+
# (JSON.load's create_additions default always takes the fallback).
|
|
16
|
+
#
|
|
17
|
+
# Exceptions from the fast path are re-raised as the JSON classes
|
|
18
|
+
# (JSON::ParserError, JSON::GeneratorError, JSON::NestingError), so
|
|
19
|
+
# existing rescue clauses keep working. Parse error MESSAGES are
|
|
20
|
+
# NOSJ's (byte offsets rather than the gem's phrasing).
|
|
21
|
+
#
|
|
22
|
+
# Not rerouted: obj.to_json (core extensions drive the gem's generator
|
|
23
|
+
# directly), and objects with a custom to_json inside a rerouted
|
|
24
|
+
# generate receive no State argument (documented NOSJ divergence).
|
|
25
|
+
|
|
26
|
+
require "json"
|
|
27
|
+
require "nosj"
|
|
28
|
+
|
|
29
|
+
module NOSJ
|
|
30
|
+
# Implementation detail of `require "nosj/json"`.
|
|
31
|
+
# @private
|
|
32
|
+
module JSONDropIn
|
|
33
|
+
PARSE_OPTS = %i[symbolize_names freeze max_nesting allow_nan
|
|
34
|
+
allow_trailing_comma].freeze
|
|
35
|
+
GENERATE_OPTS = %i[indent space space_before object_nl array_nl
|
|
36
|
+
max_nesting allow_nan ascii_only script_safe
|
|
37
|
+
escape_slash strict depth
|
|
38
|
+
buffer_initial_length].freeze
|
|
39
|
+
|
|
40
|
+
module_function
|
|
41
|
+
|
|
42
|
+
# The fast path handles nil or a plain Hash whose every key NOSJ
|
|
43
|
+
# implements; anything else (JSON::State, exotic options, string
|
|
44
|
+
# keys) belongs to the original implementation.
|
|
45
|
+
def supported?(opts, allowed)
|
|
46
|
+
return true if opts.nil?
|
|
47
|
+
return false unless opts.instance_of?(Hash)
|
|
48
|
+
opts.each_key { |k| return false unless allowed.include?(k) }
|
|
49
|
+
true
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def parse(source, opts)
|
|
53
|
+
NOSJ.parse(source, opts)
|
|
54
|
+
rescue RuntimeError => e
|
|
55
|
+
raise ::JSON::ParserError, e.message
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def generate(obj, opts, pretty)
|
|
59
|
+
pretty ? NOSJ.pretty_generate(obj, opts) : NOSJ.generate(obj, opts)
|
|
60
|
+
rescue NOSJ::NestingError => e
|
|
61
|
+
raise ::JSON::NestingError, e.message
|
|
62
|
+
rescue NOSJ::GeneratorError => e
|
|
63
|
+
raise ::JSON::GeneratorError, e.message
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Reopened by `require "nosj/json"` to reroute the module functions
|
|
69
|
+
# through NOSJ; behavior is documented on the require and in the
|
|
70
|
+
# README, not here.
|
|
71
|
+
# @private
|
|
72
|
+
module JSON
|
|
73
|
+
class << self
|
|
74
|
+
unless method_defined?(:nosj_original_parse) || private_method_defined?(:nosj_original_parse)
|
|
75
|
+
alias_method :nosj_original_parse, :parse
|
|
76
|
+
alias_method :nosj_original_generate, :generate
|
|
77
|
+
alias_method :nosj_original_pretty_generate, :pretty_generate
|
|
78
|
+
alias_method :nosj_original_dump, :dump
|
|
79
|
+
|
|
80
|
+
def parse(source, opts = nil)
|
|
81
|
+
if NOSJ::JSONDropIn.supported?(opts, NOSJ::JSONDropIn::PARSE_OPTS)
|
|
82
|
+
NOSJ::JSONDropIn.parse(source, opts)
|
|
83
|
+
else
|
|
84
|
+
nosj_original_parse(source, opts)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def generate(obj, opts = nil)
|
|
89
|
+
if NOSJ::JSONDropIn.supported?(opts, NOSJ::JSONDropIn::GENERATE_OPTS)
|
|
90
|
+
NOSJ::JSONDropIn.generate(obj, opts, false)
|
|
91
|
+
else
|
|
92
|
+
nosj_original_generate(obj, opts)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def pretty_generate(obj, opts = nil)
|
|
97
|
+
if NOSJ::JSONDropIn.supported?(opts, NOSJ::JSONDropIn::GENERATE_OPTS)
|
|
98
|
+
NOSJ::JSONDropIn.generate(obj, opts, true)
|
|
99
|
+
else
|
|
100
|
+
nosj_original_pretty_generate(obj, opts)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def dump(obj, an_io = nil, limit = nil, kwargs = nil)
|
|
105
|
+
# Fast path for the common shapes, dump(obj) and dump(obj, opts
|
|
106
|
+
# hash), mirroring the gem: dump defaults merged under the
|
|
107
|
+
# user's options, NestingError surfaced as ArgumentError. IO and
|
|
108
|
+
# limit arguments take the original implementation.
|
|
109
|
+
if limit.nil? && kwargs.nil? && (an_io.nil? || an_io.instance_of?(Hash))
|
|
110
|
+
opts = _dump_default_options
|
|
111
|
+
opts = opts.merge(an_io) if an_io
|
|
112
|
+
if NOSJ::JSONDropIn.supported?(opts, NOSJ::JSONDropIn::GENERATE_OPTS)
|
|
113
|
+
begin
|
|
114
|
+
return NOSJ::JSONDropIn.generate(obj, opts, false)
|
|
115
|
+
rescue ::JSON::NestingError
|
|
116
|
+
raise ArgumentError, "exceed depth limit"
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
nosj_original_dump(obj, an_io, limit, kwargs)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# MultiJson adapter:
|
|
4
|
+
#
|
|
5
|
+
# require "nosj/multi_json"
|
|
6
|
+
# MultiJson.use NOSJ::MultiJsonAdapter
|
|
7
|
+
#
|
|
8
|
+
# Anything speaking MultiJson (Faraday middleware and friends) then
|
|
9
|
+
# parses and generates through NOSJ.
|
|
10
|
+
|
|
11
|
+
require "json"
|
|
12
|
+
require "multi_json"
|
|
13
|
+
require "multi_json/adapter"
|
|
14
|
+
require "nosj"
|
|
15
|
+
|
|
16
|
+
module NOSJ
|
|
17
|
+
# MultiJson adapter routing +MultiJson.load+/+dump+ through nosj.
|
|
18
|
+
#
|
|
19
|
+
# multi_json 2.x renamed its namespace MultiJson -> MultiJSON; the
|
|
20
|
+
# adapter inherits from whichever this installation defines.
|
|
21
|
+
#
|
|
22
|
+
# @example
|
|
23
|
+
# require "nosj/multi_json"
|
|
24
|
+
# MultiJson.use NOSJ::MultiJsonAdapter
|
|
25
|
+
class MultiJsonAdapter < (defined?(::MultiJSON) ? ::MultiJSON::Adapter : ::MultiJson::Adapter)
|
|
26
|
+
# MultiJson wraps whatever the adapter's ParseError names.
|
|
27
|
+
ParseError = ::JSON::ParserError
|
|
28
|
+
|
|
29
|
+
SYMBOLIZE = {symbolize_names: true}.freeze
|
|
30
|
+
private_constant :SYMBOLIZE
|
|
31
|
+
|
|
32
|
+
# @param string [String] the JSON document
|
|
33
|
+
# @param options [Hash] multi_json load options; +symbolize_keys+
|
|
34
|
+
# arrives normalized as +symbolize_names+
|
|
35
|
+
# @return [Object] the parsed value tree
|
|
36
|
+
# @raise [JSON::ParserError] when the document is malformed
|
|
37
|
+
def load(string, options = {})
|
|
38
|
+
::NOSJ.parse(string, options[:symbolize_names] ? SYMBOLIZE : nil)
|
|
39
|
+
rescue RuntimeError => e
|
|
40
|
+
raise ParseError, e.message
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @param object [Object] the value tree to serialize
|
|
44
|
+
# @param options [Hash] multi_json dump options; +pretty+ selects
|
|
45
|
+
# pretty-printing
|
|
46
|
+
# @return [String] the JSON document
|
|
47
|
+
def dump(object, options = {})
|
|
48
|
+
options[:pretty] ? ::NOSJ.pretty_generate(object) : ::NOSJ.generate(object)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
data/lib/nosj/native.rb
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Precompiled platform gems ship one extension per Ruby minor under
|
|
4
|
+
# lib/nosj/<major.minor>/; the source gem compiles straight to
|
|
5
|
+
# lib/nosj/nosj.<dlext>.
|
|
6
|
+
begin
|
|
7
|
+
ruby_version = RUBY_VERSION[/\d+\.\d+/]
|
|
8
|
+
require_relative "#{ruby_version}/nosj"
|
|
9
|
+
rescue LoadError
|
|
10
|
+
require_relative "nosj"
|
|
11
|
+
end
|
data/lib/nosj/version.rb
ADDED
data/lib/nosj.rb
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "nosj/version"
|
|
4
|
+
require_relative "nosj/native"
|
|
5
|
+
|
|
6
|
+
# nosj is the evil twin of the +json+ gem: the same API, output bytes,
|
|
7
|
+
# option names, and error messages, backed by the Rust
|
|
8
|
+
# {https://github.com/yaroslav/nosj nosj} crate with SIMD-accelerated
|
|
9
|
+
# parsing and generation. Beyond the +json+ gem's surface it adds
|
|
10
|
+
# zero-allocation validation ({.valid?}) and partial parsing
|
|
11
|
+
# ({.dig}, {.at_pointer}, and their batch forms).
|
|
12
|
+
#
|
|
13
|
+
# Options arrive as a positional Hash (the +json+ gem's own calling
|
|
14
|
+
# convention); an explicit +**kwargs+ would allocate per call.
|
|
15
|
+
#
|
|
16
|
+
# @example The json gem API
|
|
17
|
+
# NOSJ.parse('{"a":[1,true]}') #=> {"a" => [1, true]}
|
|
18
|
+
# NOSJ.generate({"a" => [1, true]}) #=> '{"a":[1,true]}'
|
|
19
|
+
#
|
|
20
|
+
# @example Drop-in acceleration for the JSON module
|
|
21
|
+
# require "nosj/json"
|
|
22
|
+
# JSON.parse(src) # routed through nosj
|
|
23
|
+
module NOSJ
|
|
24
|
+
# Base class for nosj errors.
|
|
25
|
+
class Error < StandardError; end
|
|
26
|
+
|
|
27
|
+
# Raised when a value cannot be generated (non-finite floats without
|
|
28
|
+
# +allow_nan+, unsupported objects under +strict+, broken encodings).
|
|
29
|
+
# Message-compatible with +JSON::GeneratorError+.
|
|
30
|
+
class GeneratorError < Error; end
|
|
31
|
+
|
|
32
|
+
# Raised when generation exceeds +max_nesting+. Message-compatible
|
|
33
|
+
# with +JSON::NestingError+.
|
|
34
|
+
class NestingError < Error; end
|
|
35
|
+
|
|
36
|
+
PRETTY_GENERATE_OPTS = {
|
|
37
|
+
indent: " ", space: " ", object_nl: "\n", array_nl: "\n"
|
|
38
|
+
}.freeze
|
|
39
|
+
private_constant :PRETTY_GENERATE_OPTS
|
|
40
|
+
|
|
41
|
+
# Parses a JSON document, JSON.parse-compatible: same values, same
|
|
42
|
+
# option names, same behavior, byte-for-byte.
|
|
43
|
+
#
|
|
44
|
+
# The +json+ gem's legacy object-deserialization options
|
|
45
|
+
# (+object_class+, +array_class+, +decimal_class+,
|
|
46
|
+
# +create_additions+) are deliberately unsupported and raise
|
|
47
|
+
# ArgumentError.
|
|
48
|
+
#
|
|
49
|
+
# @example
|
|
50
|
+
# NOSJ.parse('{"a":[1,true]}') #=> {"a" => [1, true]}
|
|
51
|
+
# NOSJ.parse('{"a":1}', symbolize_names: true) #=> {a: 1}
|
|
52
|
+
#
|
|
53
|
+
# @param source [String] the JSON document (UTF-8 or US-ASCII)
|
|
54
|
+
# @param opts [Hash, nil] +symbolize_names+, +freeze+, +max_nesting+
|
|
55
|
+
# (Integer or +false+ for unlimited), +allow_nan+,
|
|
56
|
+
# +allow_trailing_comma+
|
|
57
|
+
# @return [Object] the parsed value tree
|
|
58
|
+
# @raise [RuntimeError] when the document is malformed or not UTF-8
|
|
59
|
+
# @raise [ArgumentError] for unsupported options
|
|
60
|
+
def self.parse(source, opts = nil)
|
|
61
|
+
parse_native(source, opts)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @!method self.generate(obj, opts = nil)
|
|
65
|
+
# Generates JSON, JSON.generate-compatible: identical output bytes,
|
|
66
|
+
# including the gem's exact float formatting. Implemented natively
|
|
67
|
+
# (no Ruby forwarder frame; the definition lives in the extension).
|
|
68
|
+
#
|
|
69
|
+
# @example
|
|
70
|
+
# NOSJ.generate({"a" => [1, true]}) #=> '{"a":[1,true]}'
|
|
71
|
+
#
|
|
72
|
+
# @param obj [Object] the value tree to serialize
|
|
73
|
+
# @param opts [Hash, nil] +indent+, +space+, +space_before+,
|
|
74
|
+
# +object_nl+, +array_nl+, +max_nesting+ (Integer or +false+),
|
|
75
|
+
# +allow_nan+, +ascii_only+, +script_safe+ (alias +escape_slash+),
|
|
76
|
+
# +strict+, +depth+, +buffer_initial_length+
|
|
77
|
+
# @return [String] the JSON document
|
|
78
|
+
# @raise [GeneratorError] for non-finite floats without +allow_nan+,
|
|
79
|
+
# unsupported objects under +strict+, or broken string encodings
|
|
80
|
+
# @raise [NestingError] when nesting exceeds +max_nesting+
|
|
81
|
+
|
|
82
|
+
# Generates human-readable JSON, JSON.pretty_generate-compatible
|
|
83
|
+
# (two-space indent, newlines between elements). Options override the
|
|
84
|
+
# pretty defaults and are otherwise the same as {.generate}.
|
|
85
|
+
#
|
|
86
|
+
# @param obj [Object] the value tree to serialize
|
|
87
|
+
# @param opts [Hash, nil] see {.generate}
|
|
88
|
+
# @return [String] the pretty-printed JSON document
|
|
89
|
+
# @raise [GeneratorError] (see {.generate})
|
|
90
|
+
# @raise [NestingError] (see {.generate})
|
|
91
|
+
def self.pretty_generate(obj, opts = nil)
|
|
92
|
+
opts = opts.nil? ? PRETTY_GENERATE_OPTS : PRETTY_GENERATE_OPTS.merge(opts)
|
|
93
|
+
generate_native(obj, opts)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Validates a document without building any Ruby values: the full
|
|
97
|
+
# parser (tokenizers, string decode, number validation) runs into a
|
|
98
|
+
# null sink, 1.8-2.5x faster than {.parse}.
|
|
99
|
+
#
|
|
100
|
+
# Returns true iff <code>NOSJ.parse(source, opts)</code> would
|
|
101
|
+
# succeed: parse refusals (malformed JSON, wrong encoding, too-deep
|
|
102
|
+
# nesting) are +false+, while option and argument-type errors still
|
|
103
|
+
# raise exactly like {.parse}.
|
|
104
|
+
#
|
|
105
|
+
# @example
|
|
106
|
+
# NOSJ.valid?('{"a":1}') #=> true
|
|
107
|
+
# NOSJ.valid?('{"a":}') #=> false
|
|
108
|
+
#
|
|
109
|
+
# @param source [String] the JSON document
|
|
110
|
+
# @param opts [Hash, nil] same options as {.parse}
|
|
111
|
+
# @return [Boolean]
|
|
112
|
+
# @raise [ArgumentError] for unsupported options
|
|
113
|
+
def self.valid?(source, opts = nil)
|
|
114
|
+
valid_native(source, opts)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Partial parsing, Hash#dig-shaped: extracts one value from a JSON
|
|
118
|
+
# string without materializing the rest of the document. Skipped
|
|
119
|
+
# content is stepped over at SIMD block speed, so a lookup costs what
|
|
120
|
+
# it skips, not what the document weighs.
|
|
121
|
+
#
|
|
122
|
+
# @example
|
|
123
|
+
# NOSJ.dig(json, "users", 3, "name") #=> "grace" or nil
|
|
124
|
+
#
|
|
125
|
+
# @param source [String] the JSON document
|
|
126
|
+
# @param path [Array<String, Symbol, Integer>] object keys and array
|
|
127
|
+
# indices; unlike Array#dig, negative indices return +nil+ (JSON
|
|
128
|
+
# Pointer has no equivalent)
|
|
129
|
+
# @return [Object, nil] the matched value, or +nil+ when the path
|
|
130
|
+
# does not resolve
|
|
131
|
+
# @raise [ArgumentError] for path elements that are not Strings,
|
|
132
|
+
# Symbols, or Integers
|
|
133
|
+
def self.dig(source, *path)
|
|
134
|
+
dig_native(source, path)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Batch {.dig}: many paths resolved in ONE pass over the document.
|
|
138
|
+
# The walk descends only into subtrees some path still needs, so a
|
|
139
|
+
# batch costs about as much as its single deepest lookup.
|
|
140
|
+
#
|
|
141
|
+
# On malformed documents a batch may raise where a single dig would
|
|
142
|
+
# return +nil+: one pass scans every byte some path needs.
|
|
143
|
+
#
|
|
144
|
+
# @example
|
|
145
|
+
# NOSJ.dig_many(json, [["users", 3, "name"], ["meta", "count"]])
|
|
146
|
+
# #=> ["grace", 42]
|
|
147
|
+
#
|
|
148
|
+
# @param source [String] the JSON document
|
|
149
|
+
# @param paths [Array<Array<String, Symbol, Integer>>] one dig path
|
|
150
|
+
# per result
|
|
151
|
+
# @param opts [Hash, nil] materialization options ({.parse}'s
|
|
152
|
+
# +symbolize_names+, +freeze+, ...)
|
|
153
|
+
# @return [Array<Object, nil>] positionally aligned with +paths+
|
|
154
|
+
# @raise [ArgumentError] for malformed paths
|
|
155
|
+
def self.dig_many(source, paths, opts = nil)
|
|
156
|
+
dig_many_native(source, paths, opts)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Partial parsing by JSON Pointer (with the standard +~0+/+~1+
|
|
160
|
+
# escapes). The matched subtree materializes under the same options
|
|
161
|
+
# as {.parse}.
|
|
162
|
+
#
|
|
163
|
+
# @example
|
|
164
|
+
# NOSJ.at_pointer(json, "/users/3/name") #=> "grace" or nil
|
|
165
|
+
#
|
|
166
|
+
# @param source [String] the JSON document
|
|
167
|
+
# @param pointer [String] a JSON Pointer (empty string = whole
|
|
168
|
+
# document)
|
|
169
|
+
# @param opts [Hash, nil] materialization options
|
|
170
|
+
# @return [Object, nil] the matched value, or +nil+ when the pointer
|
|
171
|
+
# does not resolve
|
|
172
|
+
# @raise [ArgumentError] for a malformed pointer (non-empty without a
|
|
173
|
+
# leading +/+)
|
|
174
|
+
def self.at_pointer(source, pointer, opts = nil)
|
|
175
|
+
at_pointer_native(source, pointer, opts)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Batch {.at_pointer}: the pointer-string counterpart of {.dig_many},
|
|
179
|
+
# resolving the whole set in one pass.
|
|
180
|
+
#
|
|
181
|
+
# @example
|
|
182
|
+
# NOSJ.at_pointers(json, ["/users/3/name", "/meta/count"])
|
|
183
|
+
# #=> ["grace", 42]
|
|
184
|
+
#
|
|
185
|
+
# @param source [String] the JSON document
|
|
186
|
+
# @param pointers [Array<String>] JSON Pointers, one per result
|
|
187
|
+
# @param opts [Hash, nil] materialization options
|
|
188
|
+
# @return [Array<Object, nil>] positionally aligned with +pointers+
|
|
189
|
+
# @raise [ArgumentError] for malformed pointers
|
|
190
|
+
def self.at_pointers(source, pointers, opts = nil)
|
|
191
|
+
at_pointers_native(source, pointers, opts)
|
|
192
|
+
end
|
|
193
|
+
end
|
data/sig/nosj.rbs
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Public interfaces only. The native layer (NOSJ.parse_native and
|
|
2
|
+
# friends) and the JSON drop-in's patched JSON singleton methods are
|
|
3
|
+
# implementation detail and deliberately unsigned.
|
|
4
|
+
module NOSJ
|
|
5
|
+
VERSION: String
|
|
6
|
+
|
|
7
|
+
# Any value JSON can represent, as Ruby objects: what parse returns
|
|
8
|
+
# and what partial parsing materializes. Object keys are String
|
|
9
|
+
# (Symbol with symbolize_names). generate accepts more than this
|
|
10
|
+
# alias (anything with to_json, unless strict), hence untyped there.
|
|
11
|
+
type value = nil | bool | Integer | Float | String
|
|
12
|
+
| Array[value] | Hash[String | Symbol, value]
|
|
13
|
+
|
|
14
|
+
# Options arrive as a positional Hash (the JSON gem's own calling
|
|
15
|
+
# convention; an explicit **kwargs would allocate per call), nil when
|
|
16
|
+
# omitted. Parse: symbolize_names, freeze, max_nesting, allow_nan,
|
|
17
|
+
# allow_trailing_comma. Generate: indent, space, space_before,
|
|
18
|
+
# object_nl, array_nl, max_nesting, allow_nan, ascii_only,
|
|
19
|
+
# script_safe/escape_slash, strict, depth, buffer_initial_length.
|
|
20
|
+
type opts = Hash[Symbol, untyped]?
|
|
21
|
+
|
|
22
|
+
# One NOSJ.dig path element (negative Integer indices resolve to nil).
|
|
23
|
+
type path_element = String | Symbol | Integer
|
|
24
|
+
|
|
25
|
+
class Error < StandardError
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class GeneratorError < Error
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class NestingError < Error
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.parse: (String source, ?opts opts) -> value
|
|
35
|
+
|
|
36
|
+
def self.generate: (untyped obj, ?opts opts) -> String
|
|
37
|
+
|
|
38
|
+
def self.pretty_generate: (untyped obj, ?opts opts) -> String
|
|
39
|
+
|
|
40
|
+
def self.valid?: (String source, ?opts opts) -> bool
|
|
41
|
+
|
|
42
|
+
def self.dig: (String source, *path_element path) -> value
|
|
43
|
+
|
|
44
|
+
def self.dig_many: (String source, Array[Array[path_element]] paths, ?opts opts) -> Array[value]
|
|
45
|
+
|
|
46
|
+
def self.at_pointer: (String source, String pointer, ?opts opts) -> value
|
|
47
|
+
|
|
48
|
+
def self.at_pointers: (String source, Array[String] pointers, ?opts opts) -> Array[value]
|
|
49
|
+
|
|
50
|
+
# Defined by `require "nosj/multi_json"`. The runtime superclass is
|
|
51
|
+
# multi_json's Adapter (whose namespace differs across multi_json
|
|
52
|
+
# versions), so it is not declared here.
|
|
53
|
+
class MultiJsonAdapter
|
|
54
|
+
# multi_json wraps whatever the adapter's ParseError names.
|
|
55
|
+
ParseError: singleton(::JSON::ParserError)
|
|
56
|
+
|
|
57
|
+
def load: (String string, ?Hash[Symbol, untyped] options) -> value
|
|
58
|
+
|
|
59
|
+
def dump: (untyped object, ?Hash[Symbol, untyped] options) -> String
|
|
60
|
+
end
|
|
61
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: nosj
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: x86_64-linux
|
|
6
|
+
authors:
|
|
7
|
+
- Yaroslav Markin
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: 'gem nosj is an extremely fast, json-gem-compatible JSON parser and generator
|
|
13
|
+
for Ruby: Rust and SIMD via the first-party nosj crate, precompiled platform gems
|
|
14
|
+
with per-platform PGO, partial parsing (JSON Pointer, single and batch), allocation-free
|
|
15
|
+
validation, and a one-line JSON module drop-in.'
|
|
16
|
+
email:
|
|
17
|
+
- yaroslav@markin.net
|
|
18
|
+
executables: []
|
|
19
|
+
extensions: []
|
|
20
|
+
extra_rdoc_files: []
|
|
21
|
+
files:
|
|
22
|
+
- CHANGELOG.md
|
|
23
|
+
- LICENSE.txt
|
|
24
|
+
- NOTICE
|
|
25
|
+
- README.md
|
|
26
|
+
- lib/nosj.rb
|
|
27
|
+
- lib/nosj/3.3/nosj.so
|
|
28
|
+
- lib/nosj/3.4/nosj.so
|
|
29
|
+
- lib/nosj/4.0/nosj.so
|
|
30
|
+
- lib/nosj/json.rb
|
|
31
|
+
- lib/nosj/multi_json.rb
|
|
32
|
+
- lib/nosj/native.rb
|
|
33
|
+
- lib/nosj/version.rb
|
|
34
|
+
- sig/nosj.rbs
|
|
35
|
+
homepage: https://github.com/yaroslav/nosj-ruby
|
|
36
|
+
licenses:
|
|
37
|
+
- MIT
|
|
38
|
+
metadata:
|
|
39
|
+
allowed_push_host: https://rubygems.org
|
|
40
|
+
homepage_uri: https://github.com/yaroslav/nosj-ruby
|
|
41
|
+
source_code_uri: https://github.com/yaroslav/nosj-ruby
|
|
42
|
+
changelog_uri: https://github.com/yaroslav/nosj-ruby/blob/main/CHANGELOG.md
|
|
43
|
+
bug_tracker_uri: https://github.com/yaroslav/nosj-ruby/issues
|
|
44
|
+
documentation_uri: https://rubydoc.info/gems/nosj
|
|
45
|
+
rubygems_mfa_required: 'true'
|
|
46
|
+
rdoc_options: []
|
|
47
|
+
require_paths:
|
|
48
|
+
- lib
|
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '3.3'
|
|
54
|
+
- - "<"
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: 4.1.dev
|
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 3.3.11
|
|
62
|
+
requirements: []
|
|
63
|
+
rubygems_version: 4.0.16
|
|
64
|
+
specification_version: 4
|
|
65
|
+
summary: An extremely fast JSON parser and generator for Ruby, written in Rust and
|
|
66
|
+
SIMD-accelerated on every platform.
|
|
67
|
+
test_files: []
|