nosj 0.1.0-x86_64-linux → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a0fd640bbecb91b12ed17a8ee5edc5b87befe85b1fcdcd124c58624255b3d02
4
- data.tar.gz: 6cc111ee1c0a1d55640325d48e5b71fad155f18d218211a9fcaf2f3f2a3a54b7
3
+ metadata.gz: 46cefa7803d25d779048e2c450ea1c5b5daa0c42508277432ef99df7918c783c
4
+ data.tar.gz: b11bcb71b9334785acbc7c3f1c48570f212e77646cb3c613db7cc76261895250
5
5
  SHA512:
6
- metadata.gz: 6dcc90744851a53f59a088e2ea4429ece7df99e2b72cbe81d049818641beb500b6847b9a3d9f703094c6d2f9aec669c89ab3ae652d47d29a8f3cefe0ee195ba9
7
- data.tar.gz: 1f50198d497a46a8abbd281934ce3a04e5a704a1cbec221e2cf1dc0d570de817e447c4eb580c61e288960d5c797ba8f3f7b5e9215e85f90b439ae02e9dce57db
6
+ metadata.gz: 1789804de8bff93994f515aba7d8fe5ac0f527e865bb8d917c8ed7d9a2cd08e7a3cddb2b0194653697eb62aafa466820c97b01c15a9afde9530a4f8b98bdedd5
7
+ data.tar.gz: 5aab59746b4856fb2afb505d18da3c4d9b2c3f0f02e115c402a17e94c5669b911443899cbf0958771606ae95789764ced92b091a1d5917cb186c620570811978
data/CHANGELOG.md CHANGED
@@ -1,4 +1,25 @@
1
- ## [0.1.0] - 2026-07-15
1
+ ## [0.2.0] - 2026-07-16
2
+
3
+ - File APIs. `NOSJ.load_file(path, opts)` parses a file directly
4
+ (~1.3× faster than `parse(File.read(path))`—no file-sized Ruby
5
+ String is created), and `NOSJ.write_file(path, obj, opts)` generates
6
+ straight to disk, returning the byte count like `File.write`.
7
+ `NOSJ.load_lazy_file(path, opts)` wraps a file as a lazy document
8
+ over a read-only memory map, and `NOSJ.at_pointer_file` /
9
+ `NOSJ.dig_file` pull single values out of a file without reading the
10
+ rest into Ruby. Missing files raise the usual `Errno` exceptions.
11
+ - `NOSJ.lazy`: lazy documents. Wrap a document once, then read only
12
+ what you need: `doc["users"][3]["name"]` parses just that path, `#dig`
13
+ and `#at_pointer` resolve whole paths, and `#keys`, `#size`, and
14
+ `#each` inspect a node without parsing its values. Containers come
15
+ back lazy, scalars come back as plain Ruby values, and repeated
16
+ reads are cached. `#value` (also `#to_h` / `#to_a`) materializes a
17
+ subtree under the usual parse options (`symbolize_names`, `freeze`,
18
+ ...). Pass a frozen string and creating the view is practically
19
+ free, even on megabyte documents. Malformed content raises on first
20
+ read, not at wrap time.
21
+
22
+ ## [0.1.0] - 2026-07-16
2
23
 
3
24
  Initial release.
4
25
 
data/README.md CHANGED
@@ -10,10 +10,12 @@
10
10
  - It is **faster** than gem json and every
11
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
12
  faster than Yajl—[see Benchmarks](#benchmarks).
13
+ - It has **lazy documents**: `NOSJ.lazy` wraps a document and parses a value only when you touch it—repeated access costs nanoseconds, and everything you never read is never parsed.
14
+ - It has a **partial parsing mode**: JSON Pointer lookups that pull single values out of big documents in microseconds, skipping everything else.
15
+ - It has **file APIs**: parse, generate, dig, and lazy-wrap files directly—no throwaway file-sized Ruby String, and the partial modes memory-map the file so unread pages never even leave the disk.
13
16
  - It comes **precompiled** (platform gems built with per-platform optimizations,
14
17
  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.
18
+ - Otherwise, same API and option names as gem json.
17
19
 
18
20
  **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
21
 
@@ -83,17 +85,23 @@ NOSJ.generate(obj) # indent, space, object_nl, ...,
83
85
  NOSJ.pretty_generate(obj) # ascii_only, script_safe, strict
84
86
  ```
85
87
 
86
- **Validation without parsing.** `NOSJ.valid?` runs the full
87
- parser—tokenizers, string decode, number validationinto 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:
88
+ **Lazy documents.** `NOSJ.lazy` wraps a document in a lazy view: read
89
+ a field and only that path is parsedcontainers stay lazy, scalars
90
+ arrive as plain Ruby values, and repeated reads are cached:
90
91
 
91
92
  ```ruby
92
- NOSJ.valid?('{"a":1}') #=> true
93
- NOSJ.valid?('{"a":}') #=> false
94
- NOSJ.valid?(src, max_nesting: false) # same options as parse
93
+ doc = NOSJ.lazy(json)
94
+ doc["users"][3]["name"] # parses only this path
95
+ doc.dig("meta", "count") # a whole path in one fused resolution
96
+ doc["users"].size # counted without materializing anything
97
+ doc["users"][3].value # materialize one subtree (parse options apply)
95
98
  ```
96
99
 
100
+ Pass a frozen string and creating the view is practically free—
101
+ nanoseconds, even on a megabyte document. Malformed content raises
102
+ when it is first read, not at wrap time.
103
+
104
+
97
105
  **Partial parsing.** Pull values out of a document without
98
106
  materializing the rest—skipped content is stepped over at SIMD block
99
107
  speed, so a lookup costs what it skips, not what the document weighs:
@@ -114,11 +122,38 @@ at the far end of a 570 KB document costs ~71µs, still 13× faster
114
122
  than parse-then-dig. Misses return nil; matched subtrees materialize
115
123
  with the same options as `parse` (`symbolize_names:`, `freeze:`).
116
124
 
125
+ **Files.** Every mode has a file-native form, so a document never
126
+ round-trips through a throwaway Ruby String:
127
+
128
+ ```ruby
129
+ NOSJ.load_file("config.json") # 1.3× File.read + parse
130
+ NOSJ.write_file("out.json", obj) # generate straight to disk
131
+ NOSJ.dig_file("huge.json", "users", 3, "name") # never reads the rest
132
+ NOSJ.at_pointer_file("huge.json", "/meta/count")
133
+ doc = NOSJ.load_lazy_file("huge.json") # lazy view over a memory map
134
+ ```
135
+
136
+ The partial and lazy forms memory-map the file, so pages you never
137
+ read are never loaded from disk. Missing files raise the usual
138
+ `Errno` exceptions. Measured numbers live in
139
+ [Benchmarks → File APIs](#file-apis).
140
+
141
+ **Validation without parsing.** `NOSJ.valid?` runs the full
142
+ parser—tokenizers, string decode, number validation—into a null sink
143
+ and allocates no Ruby objects at all. It is 2-4× faster than
144
+ `NOSJ.parse`, which already leads every parser above:
145
+
146
+ ```ruby
147
+ NOSJ.valid?('{"a":1}') #=> true
148
+ NOSJ.valid?('{"a":}') #=> false
149
+ NOSJ.valid?(src, max_nesting: false) # same options as parse
150
+ ```
151
+
117
152
  ## Benchmarks
118
153
 
119
154
  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
155
 
121
- Parse:
156
+ ### Parse
122
157
 
123
158
  | file | nosj (i/s) | json | Oj | FastJsonparser | RapidJSON | Yajl |
124
159
  |---|---:|---:|---:|---:|---:|---:|
@@ -136,7 +171,7 @@ Parse:
136
171
  | tolstoy | **8.9k** | ×1.79 | ×1.96 | ×2.29 | ×2.10 | ×17.31 |
137
172
  | twitter | **1.1k** | ×1.09 | ×1.83 | ×2.25 | ×2.61 | ×5.40 |
138
173
 
139
- Generate:
174
+ ### Generate
140
175
 
141
176
  | file | nosj (i/s) | json | Oj | RapidJSON | Yajl |
142
177
  |---|---:|---:|---:|---:|---:|
@@ -157,6 +192,23 @@ Generate:
157
192
  \* canada-generate is a statistical tie with the json gem (within
158
193
  measurement error).
159
194
 
195
+ ### File APIs
196
+
197
+ twitter.json (570 KB) from a warm page cache, medians of 7 alternating
198
+ rounds against the plain-Ruby composition on the same parser (Apple
199
+ Silicon dev box, Ruby 4.0.6 + YJIT, PGO build, 2026-07-16):
200
+
201
+ | operation | µs/op | vs the Ruby way |
202
+ |---|---:|---|
203
+ | `NOSJ.load_file` (parse the whole file) | 948 | ×1.33 vs `NOSJ.parse(File.read(path))` |
204
+ | `NOSJ.dig_file` (one deep field) | 246 | ×5.2 vs read + parse + dig |
205
+ | `NOSJ.load_lazy_file` + one field | 257 | ×5.0 vs read + parse + dig |
206
+
207
+ `NOSJ.write_file` measures at parity with
208
+ `File.write(NOSJ.generate(obj))` on this box—file-write timings swing
209
+ too much for an honest multiplier; what it saves is the intermediate
210
+ file-sized Ruby String.
211
+
160
212
  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
213
 
162
214
  ## Switching from the json gem
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/lazy.rb ADDED
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NOSJ
4
+ # A lazy view of one JSON container inside a document created with
5
+ # {NOSJ.lazy}. Nothing is parsed until it is touched: indexing walks
6
+ # the raw bytes to the requested child (skipping siblings at SIMD
7
+ # block speed), returns another Lazy node for containers, and
8
+ # materializes plain Ruby values for scalars. Resolved children are
9
+ # cached, so repeated access is free and object identity is stable.
10
+ #
11
+ # Validation is as-you-go: skipped content is bracket-balance
12
+ # checked and resolved targets fully validated, so a malformed region
13
+ # raises when an access first walks it, not at {NOSJ.lazy} time.
14
+ #
15
+ # Nodes hold their own stable copy of the document (shared across the
16
+ # whole node tree), so mutating the source string later is harmless.
17
+ #
18
+ # @example Pull two fields out of a big document
19
+ # doc = NOSJ.lazy(huge_json)
20
+ # doc["users"][3]["name"] # only this path is parsed
21
+ # doc.dig("meta", "count")
22
+ #
23
+ # @example Materialize a subtree
24
+ # doc["users"][3].value #=> {"name" => ..., ...}
25
+ class Lazy
26
+ include Enumerable
27
+
28
+ # Resolves one child. String and Symbol keys index objects; Integer
29
+ # indices index arrays (negative indices resolve to +nil+, as in
30
+ # {NOSJ.dig}). Containers come back as further Lazy nodes, scalars
31
+ # as plain Ruby values, misses as +nil+. Results are cached on the
32
+ # node.
33
+ #
34
+ # @param token [String, Symbol, Integer]
35
+ # @return [NOSJ::Lazy, Object, nil]
36
+ def [](token)
37
+ cache = (@children ||= {})
38
+ cache.fetch(token) { cache[token] = __get(token) }
39
+ end
40
+
41
+ # Hash#dig-shaped access, fused into a single resolution: the whole
42
+ # path resolves in one walk of this node's bytes, no intermediate
43
+ # nodes. Semantics match {NOSJ.dig}: misses, negative indices, and
44
+ # steps into scalars resolve to +nil+. Not cached.
45
+ #
46
+ # @param path [Array<String, Symbol, Integer>]
47
+ # @return [NOSJ::Lazy, Object, nil]
48
+ def dig(first, *rest)
49
+ __dig([first, *rest])
50
+ end
51
+
52
+ # Resolves an RFC 6901 JSON Pointer within this node's subtree,
53
+ # with the same lazy/materialize behavior as {#[]}. Not cached.
54
+ #
55
+ # @param pointer [String] e.g. <tt>"/users/3/name"</tt>
56
+ # @return [NOSJ::Lazy, Object, nil]
57
+ def at_pointer(pointer)
58
+ __at_pointer(pointer)
59
+ end
60
+
61
+ # Materializes this node's whole subtree as plain Ruby values,
62
+ # under the options given to {NOSJ.lazy} (+symbolize_names+,
63
+ # +freeze+, ...).
64
+ #
65
+ # @return [Hash, Array]
66
+ def value
67
+ __materialize
68
+ end
69
+ alias_method :materialize, :value
70
+
71
+ # @return [Hash] the materialized subtree
72
+ # @raise [TypeError] on an array node
73
+ def to_h
74
+ raise TypeError, "to_h on a JSON array" unless object?
75
+
76
+ __materialize
77
+ end
78
+
79
+ # @return [Array] the materialized subtree
80
+ # @raise [TypeError] on an object node
81
+ def to_a
82
+ raise TypeError, "to_a on a JSON object" unless array?
83
+
84
+ __materialize
85
+ end
86
+
87
+ # @return [Boolean] whether this node is a JSON object
88
+ def object?
89
+ __kind == :object
90
+ end
91
+
92
+ # @return [Boolean] whether this node is a JSON array
93
+ def array?
94
+ __kind == :array
95
+ end
96
+
97
+ # The object's keys (always Strings), read in one walk without
98
+ # materializing any values.
99
+ #
100
+ # @return [Array<String>]
101
+ # @raise [TypeError] on an array node
102
+ def keys
103
+ __keys
104
+ end
105
+
106
+ # Entry count (object pairs or array elements), read in one walk
107
+ # without materializing anything.
108
+ #
109
+ # @return [Integer]
110
+ def size
111
+ __size
112
+ end
113
+ alias_method :length, :size
114
+ alias_method :count, :size
115
+
116
+ # @return [Boolean]
117
+ def empty?
118
+ size.zero?
119
+ end
120
+
121
+ # Iterates direct children, resolved in one walk: object nodes
122
+ # yield +[key, child]+ pairs (like Hash), array nodes yield
123
+ # children. Containers arrive as Lazy nodes, scalars as values.
124
+ #
125
+ # @return [Enumerator] when no block is given
126
+ def each(&block)
127
+ return enum_for(:each) unless block
128
+
129
+ if object?
130
+ __children.each { |pair| yield pair }
131
+ else
132
+ __children.each { |child| yield child }
133
+ end
134
+ self
135
+ end
136
+
137
+ # @return [String] kind and span size, without touching content
138
+ def inspect
139
+ "#<NOSJ::Lazy #{__kind} (#{__byte_size} bytes)>"
140
+ end
141
+ alias_method :to_s, :inspect
142
+
143
+ private :__get, :__dig, :__at_pointer, :__materialize, :__kind,
144
+ :__byte_size, :__keys, :__size, :__children
145
+ end
146
+
147
+ # Wraps a JSON document for lazy, on-demand access: returns a
148
+ # {NOSJ::Lazy} node for a container root, or the materialized value
149
+ # for a scalar root. The document bytes are copied once; no parsing
150
+ # happens beyond locating the root value.
151
+ #
152
+ # @example
153
+ # doc = NOSJ.lazy('{"users":[{"name":"ada"},{"name":"grace"}]}')
154
+ # doc["users"][1]["name"] #=> "grace" — the rest is never parsed
155
+ #
156
+ # @param source [String] the JSON document (UTF-8 or US-ASCII)
157
+ # @param opts [Hash, nil] {NOSJ.parse} options applied whenever a
158
+ # value materializes: +symbolize_names+, +freeze+, +max_nesting+,
159
+ # +allow_nan+, +allow_trailing_comma+
160
+ # @return [NOSJ::Lazy, Object]
161
+ # @raise [RuntimeError] when the document root is malformed
162
+ def self.lazy(source, opts = nil)
163
+ lazy_native(source, opts)
164
+ end
165
+ end
data/lib/nosj/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module NOSJ
4
4
  # The gem version.
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.0"
6
6
  end
data/lib/nosj.rb CHANGED
@@ -2,13 +2,15 @@
2
2
 
3
3
  require_relative "nosj/version"
4
4
  require_relative "nosj/native"
5
+ require_relative "nosj/lazy"
5
6
 
6
7
  # nosj is the evil twin of the +json+ gem: the same API, output bytes,
7
8
  # option names, and error messages, backed by the Rust
8
9
  # {https://github.com/yaroslav/nosj nosj} crate with SIMD-accelerated
9
10
  # 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).
11
+ # zero-allocation validation ({.valid?}), partial parsing
12
+ # ({.dig}, {.at_pointer}, and their batch forms), and lazy documents
13
+ # ({.lazy}).
12
14
  #
13
15
  # Options arrive as a positional Hash (the +json+ gem's own calling
14
16
  # convention); an explicit +**kwargs+ would allocate per call.
@@ -190,4 +192,85 @@ module NOSJ
190
192
  def self.at_pointers(source, pointers, opts = nil)
191
193
  at_pointers_native(source, pointers, opts)
192
194
  end
195
+
196
+ # Parses a JSON file, like +JSON.load_file+—except the file is read
197
+ # natively into a reused buffer, so no file-sized Ruby String is ever
198
+ # created (or garbage-collected).
199
+ #
200
+ # @example
201
+ # NOSJ.load_file("config.json", symbolize_names: true)
202
+ #
203
+ # @param path [String] the file to parse (UTF-8)
204
+ # @param opts [Hash, nil] the same options as {.parse}
205
+ # @return [Object] the parsed value tree
206
+ # @raise [SystemCallError] +Errno::ENOENT+ and friends, like File.read
207
+ # @raise [RuntimeError] when the document is malformed or not UTF-8
208
+ def self.load_file(path, opts = nil)
209
+ load_file_native(path, opts)
210
+ end
211
+
212
+ # Generates +obj+ as JSON and writes it to +path+, streaming the
213
+ # generator's buffer straight to disk—no intermediate Ruby String.
214
+ #
215
+ # @example
216
+ # NOSJ.write_file("out.json", {"a" => [1, true]}) #=> 14
217
+ # NOSJ.write_file("pretty.json", obj, indent: " ", object_nl: "\n")
218
+ #
219
+ # @param path [String] the file to (over)write
220
+ # @param obj [Object] the value tree to generate
221
+ # @param opts [Hash, nil] the same options as {.generate}
222
+ # @return [Integer] the number of bytes written, like File.write
223
+ # @raise [SystemCallError] +Errno::ENOENT+ and friends, like File.write
224
+ # @raise [GeneratorError] like {.generate}
225
+ def self.write_file(path, obj, opts = nil)
226
+ write_file_native(path, obj, opts)
227
+ end
228
+
229
+ # Wraps a JSON file as a lazy document ({.lazy} for files): the file
230
+ # is memory-mapped read-only, so beyond one sequential UTF-8 check,
231
+ # pages you never read are never loaded from disk. The mapping lives
232
+ # as long as any node on it; the file must not be modified while it
233
+ # is in use.
234
+ #
235
+ # @example
236
+ # doc = NOSJ.load_lazy_file("huge.json")
237
+ # doc["users"][3]["name"] # touches only these pages
238
+ #
239
+ # @param path [String] the file to wrap (UTF-8)
240
+ # @param opts [Hash, nil] {.parse} options applied on materialization
241
+ # @return [NOSJ::Lazy, Object]
242
+ # @raise [SystemCallError] +Errno::ENOENT+ and friends
243
+ # @raise [RuntimeError] when the file is not UTF-8 or the root is malformed
244
+ def self.load_lazy_file(path, opts = nil)
245
+ load_lazy_file_native(path, opts)
246
+ end
247
+
248
+ # {.at_pointer} against a file: memory-maps it, resolves the pointer,
249
+ # materializes only the matched subtree, and never reads the rest
250
+ # into Ruby.
251
+ #
252
+ # @example
253
+ # NOSJ.at_pointer_file("huge.json", "/users/3/name")
254
+ #
255
+ # @param path [String] the file to query (UTF-8)
256
+ # @param pointer [String] an RFC 6901 JSON Pointer
257
+ # @param opts [Hash, nil] materialization options
258
+ # @return [Object, nil] nil when the pointer misses
259
+ # @raise [ArgumentError] for malformed pointers
260
+ def self.at_pointer_file(path, pointer, opts = nil)
261
+ at_pointer_file_native(path, pointer, opts)
262
+ end
263
+
264
+ # {.dig} against a file: the Hash#dig-shaped counterpart of
265
+ # {.at_pointer_file}. Negative indices resolve to nil.
266
+ #
267
+ # @example
268
+ # NOSJ.dig_file("huge.json", "users", 3, "name")
269
+ #
270
+ # @param path [String] the file to query (UTF-8)
271
+ # @param path_elements [Array<String, Symbol, Integer>]
272
+ # @return [Object, nil]
273
+ def self.dig_file(path, *path_elements)
274
+ dig_file_native(path, path_elements)
275
+ end
193
276
  end
data/sig/nosj.rbs CHANGED
@@ -47,6 +47,60 @@ module NOSJ
47
47
 
48
48
  def self.at_pointers: (String source, Array[String] pointers, ?opts opts) -> Array[value]
49
49
 
50
+ def self.lazy: (String source, ?opts opts) -> (Lazy | value)
51
+
52
+ def self.load_file: (String path, ?opts opts) -> value
53
+
54
+ def self.write_file: (String path, untyped obj, ?opts opts) -> Integer
55
+
56
+ def self.load_lazy_file: (String path, ?opts opts) -> (Lazy | value)
57
+
58
+ def self.at_pointer_file: (String path, String pointer, ?opts opts) -> value
59
+
60
+ def self.dig_file: (String path, *path_element path_elements) -> value
61
+
62
+ # A lazy view of one JSON container: children resolve on first
63
+ # access (containers as further Lazy nodes, scalars as values,
64
+ # misses as nil) and are cached on the node.
65
+ class Lazy
66
+ include Enumerable[untyped]
67
+
68
+ def []: (path_element token) -> (Lazy | value)
69
+
70
+ def dig: (path_element first, *path_element rest) -> (Lazy | value)
71
+
72
+ def at_pointer: (String pointer) -> (Lazy | value)
73
+
74
+ def value: () -> value
75
+
76
+ alias materialize value
77
+
78
+ def to_h: () -> Hash[String | Symbol, value]
79
+
80
+ def to_a: () -> Array[value]
81
+
82
+ def object?: () -> bool
83
+
84
+ def array?: () -> bool
85
+
86
+ def keys: () -> Array[String]
87
+
88
+ def size: () -> Integer
89
+
90
+ alias length size
91
+
92
+ alias count size
93
+
94
+ def empty?: () -> bool
95
+
96
+ def each: () { (untyped) -> void } -> self
97
+ | () -> Enumerator[untyped, self]
98
+
99
+ def inspect: () -> String
100
+
101
+ alias to_s inspect
102
+ end
103
+
50
104
  # Defined by `require "nosj/multi_json"`. The runtime superclass is
51
105
  # multi_json's Adapter (whose namespace differs across multi_json
52
106
  # versions), so it is not declared here.
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.1.0
4
+ version: 0.2.0
5
5
  platform: x86_64-linux
6
6
  authors:
7
7
  - Yaroslav Markin
@@ -11,7 +11,9 @@ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: 'gem nosj is an extremely fast, json-gem-compatible JSON parser and generator
13
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
14
+ with per-platform PGO, partial parsing (JSON Pointer, single and batch), lazy documents
15
+ that parse a value only when you touch it, file APIs that parse, generate, and query
16
+ files natively (memory-mapped, so unread pages never leave the disk), allocation-free
15
17
  validation, and a one-line JSON module drop-in.'
16
18
  email:
17
19
  - yaroslav@markin.net
@@ -28,6 +30,7 @@ files:
28
30
  - lib/nosj/3.4/nosj.so
29
31
  - lib/nosj/4.0/nosj.so
30
32
  - lib/nosj/json.rb
33
+ - lib/nosj/lazy.rb
31
34
  - lib/nosj/multi_json.rb
32
35
  - lib/nosj/native.rb
33
36
  - lib/nosj/version.rb