json 2.7.4 → 2.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +25 -0
- data/README.md +8 -77
- data/ext/json/ext/fbuffer/fbuffer.h +85 -47
- data/ext/json/ext/generator/generator.c +367 -216
- data/ext/json/ext/parser/extconf.rb +5 -27
- data/ext/json/ext/parser/parser.c +1536 -474
- data/ext/json/ext/parser/parser.rl +717 -243
- data/json.gemspec +4 -1
- data/lib/json/add/bigdecimal.rb +1 -1
- data/lib/json/common.rb +200 -54
- data/lib/json/ext/generator/state.rb +1 -31
- data/lib/json/ext.rb +2 -4
- data/lib/json/{pure → truffle_ruby}/generator.rb +165 -124
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +15 -20
- metadata +4 -8
- data/ext/json/ext/generator/generator.h +0 -129
- data/ext/json/ext/parser/parser.h +0 -60
- data/lib/json/pure/parser.rb +0 -331
- data/lib/json/pure.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39c161c94f7ae85545dc117ec7616aa65f69e9192f081dd1d0934fc57f7a1b9b
|
4
|
+
data.tar.gz: f980984efc78b2bf8b0aa81e67dc8115e503bcb03171ce7658bdc9ba653da0b7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 02e0733a4e893e0c486bc3ea2785c15601c5e660d990c8c83543df3df6f93acdb41d29e656f951896de8854f9672d89bae462f7761746e27614e038b48f72296
|
7
|
+
data.tar.gz: 5b22f7e7aa15e8965293fb91ac5d45631f5ef16dbaf0911f5d0763175138dfde8bb104dcea2df73c5e99fda45aecde081c971ccd2bc7c2dae9b4d700376ef8e3
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,30 @@
|
|
1
1
|
# Changes
|
2
2
|
|
3
|
+
### 2024-11-06 (2.8.1)
|
4
|
+
|
5
|
+
* Fix the java packages to include the extension.
|
6
|
+
|
7
|
+
### 2024-11-06 (2.8.0)
|
8
|
+
|
9
|
+
* Emit a deprecation warning when `JSON.load` create custom types without the `create_additions` option being explictly enabled.
|
10
|
+
* Prefer to use `JSON.unsafe_load(string)` or `JSON.load(string, create_additions: true)`.
|
11
|
+
* Emit a deprecation warning when serializing valid UTF-8 strings encoded in `ASCII_8BIT` aka `BINARY`.
|
12
|
+
* Bump required Ruby version to 2.7.
|
13
|
+
* Add support for optionally parsing trailing commas, via `allow_trailing_comma: true`, which in cunjunction with the
|
14
|
+
pre-existing support for comments, make it suitable to parse `jsonc` documents.
|
15
|
+
* Many performance improvements to `JSON.parse` and `JSON.load`, up to `1.7x` faster on real world documents.
|
16
|
+
* Some minor performance improvements to `JSON.dump` and `JSON.generate`.
|
17
|
+
|
18
|
+
### 2024-11-04 (2.7.6)
|
19
|
+
|
20
|
+
* Fix a regression in JSON.generate when dealing with Hash keys that are string subclasses, call `to_json` on them.
|
21
|
+
|
22
|
+
### 2024-10-25 (2.7.5)
|
23
|
+
|
24
|
+
* Fix a memory leak when `#to_json` methods raise an exception.
|
25
|
+
* Gracefully handle formatting configs being set to `nil` instead of `""`.
|
26
|
+
* Workaround another issue caused by conflicting versions of both `json_pure` and `json` being loaded.
|
27
|
+
|
3
28
|
### 2024-10-25 (2.7.4)
|
4
29
|
|
5
30
|
* Workaround a bug in 3.4.8 and older https://github.com/rubygems/rubygems/pull/6490.
|
data/README.md
CHANGED
@@ -5,16 +5,10 @@
|
|
5
5
|
## Description
|
6
6
|
|
7
7
|
This is an implementation of the JSON specification according to RFC 7159
|
8
|
-
http://www.ietf.org/rfc/rfc7159.txt .
|
8
|
+
http://www.ietf.org/rfc/rfc7159.txt .
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
* The quite a bit faster native extension variant, which is in parts
|
13
|
-
implemented in C or Java and comes with a parser generated by the [Ragel]
|
14
|
-
state machine compiler.
|
15
|
-
|
16
|
-
Both variants of the JSON generator generate UTF-8 character sequences by
|
17
|
-
default. If an :ascii\_only option with a true value is given, they escape all
|
10
|
+
The JSON generator generate UTF-8 character sequences by default.
|
11
|
+
If an :ascii\_only option with a true value is given, they escape all
|
18
12
|
non-ASCII and control characters with \uXXXX escape sequences, and support
|
19
13
|
UTF-16 surrogate pairs in order to be able to generate the whole range of
|
20
14
|
unicode code points.
|
@@ -27,10 +21,6 @@ endpoint.
|
|
27
21
|
|
28
22
|
## Installation
|
29
23
|
|
30
|
-
It's recommended to use the extension variant of JSON, because it's faster than
|
31
|
-
the pure ruby variant. If you cannot build it on your system, you can settle
|
32
|
-
for the latter.
|
33
|
-
|
34
24
|
Install the gem and add to the application's Gemfile by executing:
|
35
25
|
|
36
26
|
$ bundle add json
|
@@ -39,12 +29,6 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
39
29
|
|
40
30
|
$ gem install json
|
41
31
|
|
42
|
-
|
43
|
-
There is also a pure ruby json only variant of the gem, that can be installed
|
44
|
-
with:
|
45
|
-
|
46
|
-
$ gem install json_pure
|
47
|
-
|
48
32
|
## Usage
|
49
33
|
|
50
34
|
To use JSON you can
|
@@ -53,20 +37,6 @@ To use JSON you can
|
|
53
37
|
require 'json'
|
54
38
|
```
|
55
39
|
|
56
|
-
to load the installed variant (either the extension `'json'` or the pure
|
57
|
-
variant `'json_pure'`). If you have installed the extension variant, you can
|
58
|
-
pick either the extension variant or the pure variant by typing
|
59
|
-
|
60
|
-
```ruby
|
61
|
-
require 'json/ext'
|
62
|
-
```
|
63
|
-
|
64
|
-
or
|
65
|
-
|
66
|
-
```ruby
|
67
|
-
require 'json/pure'
|
68
|
-
```
|
69
|
-
|
70
40
|
Now you can parse a JSON document into a ruby data structure by calling
|
71
41
|
|
72
42
|
```ruby
|
@@ -82,50 +52,11 @@ You can also use the `pretty_generate` method (which formats the output more
|
|
82
52
|
verbosely and nicely) or `fast_generate` (which doesn't do any of the security
|
83
53
|
checks generate performs, e. g. nesting deepness checks).
|
84
54
|
|
85
|
-
|
86
|
-
generate a JSON document from an array or hash:
|
87
|
-
|
88
|
-
```ruby
|
89
|
-
document = JSON 'test' => 23 # => "{\"test\":23}"
|
90
|
-
document = JSON['test' => 23] # => "{\"test\":23}"
|
91
|
-
```
|
92
|
-
|
93
|
-
and
|
94
|
-
|
95
|
-
```ruby
|
96
|
-
data = JSON '{"test":23}' # => {"test"=>23}
|
97
|
-
data = JSON['{"test":23}'] # => {"test"=>23}
|
98
|
-
```
|
99
|
-
|
100
|
-
You can choose to load a set of common additions to ruby core's objects if
|
101
|
-
you
|
102
|
-
|
103
|
-
```ruby
|
104
|
-
require 'json/add/core'
|
105
|
-
```
|
106
|
-
|
107
|
-
After requiring this you can, e. g., serialise/deserialise Ruby ranges:
|
108
|
-
|
109
|
-
```ruby
|
110
|
-
JSON JSON(1..10) # => 1..10
|
111
|
-
```
|
112
|
-
|
113
|
-
To find out how to add JSON support to other or your own classes, read the
|
114
|
-
section "More Examples" below.
|
115
|
-
|
116
|
-
## Serializing exceptions
|
117
|
-
|
118
|
-
The JSON module doesn't extend `Exception` by default. If you convert an `Exception`
|
119
|
-
object to JSON, it will by default only include the exception message.
|
120
|
-
|
121
|
-
To include the full details, you must either load the `json/add/core` mentioned
|
122
|
-
above, or specifically load the exception addition:
|
123
|
-
|
124
|
-
```ruby
|
125
|
-
require 'json/add/exception'
|
126
|
-
```
|
55
|
+
## Handling arbitrary types
|
127
56
|
|
128
|
-
|
57
|
+
> [!CAUTION]
|
58
|
+
> You should never use `JSON.unsafe_load` nor `JSON.parse(str, create_additions: true)` to parse untrusted user input,
|
59
|
+
> as it can lead to remote code execution vulnerabilities.
|
129
60
|
|
130
61
|
To create a JSON document from a ruby data structure, you can call
|
131
62
|
`JSON.generate` like that:
|
@@ -191,7 +122,7 @@ JSON.parse json
|
|
191
122
|
# => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
|
192
123
|
json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
|
193
124
|
# => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
|
194
|
-
JSON.
|
125
|
+
JSON.unsafe_load json
|
195
126
|
# => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
|
196
127
|
```
|
197
128
|
|
@@ -4,21 +4,58 @@
|
|
4
4
|
#include "ruby.h"
|
5
5
|
#include "ruby/encoding.h"
|
6
6
|
|
7
|
+
/* shims */
|
8
|
+
/* This is the fallback definition from Ruby 3.4 */
|
9
|
+
|
10
|
+
#ifndef RBIMPL_STDBOOL_H
|
11
|
+
#if defined(__cplusplus)
|
12
|
+
# if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L)
|
13
|
+
# include <cstdbool>
|
14
|
+
# endif
|
15
|
+
#elif defined(HAVE_STDBOOL_H)
|
16
|
+
# include <stdbool.h>
|
17
|
+
#elif !defined(HAVE__BOOL)
|
18
|
+
typedef unsigned char _Bool;
|
19
|
+
# define bool _Bool
|
20
|
+
# define true ((_Bool)+1)
|
21
|
+
# define false ((_Bool)+0)
|
22
|
+
# define __bool_true_false_are_defined
|
23
|
+
#endif
|
24
|
+
#endif
|
25
|
+
|
26
|
+
#ifndef RB_UNLIKELY
|
27
|
+
#define RB_UNLIKELY(expr) expr
|
28
|
+
#endif
|
29
|
+
|
30
|
+
#ifndef RB_LIKELY
|
31
|
+
#define RB_LIKELY(expr) expr
|
32
|
+
#endif
|
33
|
+
|
34
|
+
#ifndef MAYBE_UNUSED
|
35
|
+
# define MAYBE_UNUSED(x) x
|
36
|
+
#endif
|
37
|
+
|
38
|
+
enum fbuffer_type {
|
39
|
+
FBUFFER_HEAP_ALLOCATED = 0,
|
40
|
+
FBUFFER_STACK_ALLOCATED = 1,
|
41
|
+
};
|
42
|
+
|
7
43
|
typedef struct FBufferStruct {
|
44
|
+
enum fbuffer_type type;
|
8
45
|
unsigned long initial_length;
|
9
|
-
char *ptr;
|
10
46
|
unsigned long len;
|
11
47
|
unsigned long capa;
|
48
|
+
char *ptr;
|
12
49
|
} FBuffer;
|
13
50
|
|
51
|
+
#define FBUFFER_STACK_SIZE 512
|
14
52
|
#define FBUFFER_INITIAL_LENGTH_DEFAULT 1024
|
15
53
|
|
16
|
-
#define FBUFFER_PTR(fb) (fb->ptr)
|
17
|
-
#define FBUFFER_LEN(fb) (fb->len)
|
18
|
-
#define FBUFFER_CAPA(fb) (fb->capa)
|
54
|
+
#define FBUFFER_PTR(fb) ((fb)->ptr)
|
55
|
+
#define FBUFFER_LEN(fb) ((fb)->len)
|
56
|
+
#define FBUFFER_CAPA(fb) ((fb)->capa)
|
19
57
|
#define FBUFFER_PAIR(fb) FBUFFER_PTR(fb), FBUFFER_LEN(fb)
|
20
58
|
|
21
|
-
static FBuffer *fbuffer_alloc(unsigned long initial_length);
|
22
59
|
static void fbuffer_free(FBuffer *fb);
|
23
60
|
#ifndef JSON_GENERATOR
|
24
61
|
static void fbuffer_clear(FBuffer *fb);
|
@@ -27,29 +64,26 @@ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len);
|
|
27
64
|
#ifdef JSON_GENERATOR
|
28
65
|
static void fbuffer_append_long(FBuffer *fb, long number);
|
29
66
|
#endif
|
30
|
-
static void fbuffer_append_char(FBuffer *fb, char newchr);
|
67
|
+
static inline void fbuffer_append_char(FBuffer *fb, char newchr);
|
31
68
|
#ifdef JSON_GENERATOR
|
32
69
|
static VALUE fbuffer_to_s(FBuffer *fb);
|
33
70
|
#endif
|
34
71
|
|
35
|
-
|
36
|
-
#define RB_UNLIKELY(expr) expr
|
37
|
-
#endif
|
38
|
-
|
39
|
-
static FBuffer *fbuffer_alloc(unsigned long initial_length)
|
72
|
+
static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *stack_buffer, long stack_buffer_size)
|
40
73
|
{
|
41
|
-
|
42
|
-
if (
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
74
|
+
fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT;
|
75
|
+
if (stack_buffer) {
|
76
|
+
fb->type = FBUFFER_STACK_ALLOCATED;
|
77
|
+
fb->ptr = stack_buffer;
|
78
|
+
fb->capa = stack_buffer_size;
|
79
|
+
}
|
47
80
|
}
|
48
81
|
|
49
82
|
static void fbuffer_free(FBuffer *fb)
|
50
83
|
{
|
51
|
-
if (fb->ptr
|
52
|
-
|
84
|
+
if (fb->ptr && fb->type == FBUFFER_HEAP_ALLOCATED) {
|
85
|
+
ruby_xfree(fb->ptr);
|
86
|
+
}
|
53
87
|
}
|
54
88
|
|
55
89
|
#ifndef JSON_GENERATOR
|
@@ -59,22 +93,34 @@ static void fbuffer_clear(FBuffer *fb)
|
|
59
93
|
}
|
60
94
|
#endif
|
61
95
|
|
62
|
-
static
|
96
|
+
static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
|
63
97
|
{
|
64
|
-
|
65
|
-
unsigned long required;
|
98
|
+
unsigned long required;
|
66
99
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
100
|
+
if (RB_UNLIKELY(!fb->ptr)) {
|
101
|
+
fb->ptr = ALLOC_N(char, fb->initial_length);
|
102
|
+
fb->capa = fb->initial_length;
|
103
|
+
}
|
71
104
|
|
72
|
-
|
105
|
+
for (required = fb->capa; requested > required - fb->len; required <<= 1);
|
73
106
|
|
74
|
-
|
107
|
+
if (required > fb->capa) {
|
108
|
+
if (fb->type == FBUFFER_STACK_ALLOCATED) {
|
109
|
+
const char *old_buffer = fb->ptr;
|
110
|
+
fb->ptr = ALLOC_N(char, required);
|
111
|
+
fb->type = FBUFFER_HEAP_ALLOCATED;
|
112
|
+
MEMCPY(fb->ptr, old_buffer, char, fb->len);
|
113
|
+
} else {
|
75
114
|
REALLOC_N(fb->ptr, char, required);
|
76
|
-
fb->capa = required;
|
77
115
|
}
|
116
|
+
fb->capa = required;
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
|
121
|
+
{
|
122
|
+
if (RB_UNLIKELY(requested > fb->capa - fb->len)) {
|
123
|
+
fbuffer_do_inc_capa(fb, requested);
|
78
124
|
}
|
79
125
|
}
|
80
126
|
|
@@ -99,7 +145,7 @@ static void fbuffer_append_str(FBuffer *fb, VALUE str)
|
|
99
145
|
}
|
100
146
|
#endif
|
101
147
|
|
102
|
-
static void fbuffer_append_char(FBuffer *fb, char newchr)
|
148
|
+
static inline void fbuffer_append_char(FBuffer *fb, char newchr)
|
103
149
|
{
|
104
150
|
fbuffer_inc_capa(fb, 1);
|
105
151
|
*(fb->ptr + fb->len) = newchr;
|
@@ -107,33 +153,25 @@ static void fbuffer_append_char(FBuffer *fb, char newchr)
|
|
107
153
|
}
|
108
154
|
|
109
155
|
#ifdef JSON_GENERATOR
|
110
|
-
static void freverse(char *start, char *end)
|
111
|
-
{
|
112
|
-
char c;
|
113
|
-
|
114
|
-
while (end > start) {
|
115
|
-
c = *end, *end-- = *start, *start++ = c;
|
116
|
-
}
|
117
|
-
}
|
118
|
-
|
119
156
|
static long fltoa(long number, char *buf)
|
120
157
|
{
|
121
|
-
static char digits[] = "0123456789";
|
158
|
+
static const char digits[] = "0123456789";
|
122
159
|
long sign = number;
|
123
160
|
char* tmp = buf;
|
124
161
|
|
125
162
|
if (sign < 0) number = -number;
|
126
|
-
do *tmp
|
127
|
-
if (sign < 0) *tmp
|
128
|
-
|
129
|
-
return tmp - buf;
|
163
|
+
do *tmp-- = digits[number % 10]; while (number /= 10);
|
164
|
+
if (sign < 0) *tmp-- = '-';
|
165
|
+
return buf - tmp;
|
130
166
|
}
|
131
167
|
|
168
|
+
#define LONG_BUFFER_SIZE 20
|
132
169
|
static void fbuffer_append_long(FBuffer *fb, long number)
|
133
170
|
{
|
134
|
-
char buf[
|
135
|
-
|
136
|
-
|
171
|
+
char buf[LONG_BUFFER_SIZE];
|
172
|
+
char *buffer_end = buf + LONG_BUFFER_SIZE;
|
173
|
+
long len = fltoa(number, buffer_end - 1);
|
174
|
+
fbuffer_append(fb, buffer_end - len, len);
|
137
175
|
}
|
138
176
|
|
139
177
|
static VALUE fbuffer_to_s(FBuffer *fb)
|