json 2.7.6 → 2.8.0.alpha1
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/CHANGES.md +8 -0
- data/README.md +8 -77
- data/ext/json/ext/fbuffer/fbuffer.h +85 -51
- data/ext/json/ext/generator/generator.c +327 -204
- 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 +3 -1
- data/lib/json/add/bigdecimal.rb +1 -1
- data/lib/json/common.rb +200 -59
- data/lib/json/ext/generator/state.rb +1 -31
- data/lib/json/ext.rb +2 -4
- data/lib/json/{pure → truffle_ruby}/generator.rb +150 -128
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +15 -20
- metadata +4 -8
- data/ext/json/ext/generator/generator.h +0 -118
- 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: e37f288be36138ec53fe36090c7886445f097184538b33b04ce12524082f6f8f
|
4
|
+
data.tar.gz: a7a4d1069d594d876cad44766c22ff3688f171b5cfa5ed636bec07daaae11b82
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1025ceda0144fb3ead6b25813e994565c9fcd99573f04db11cee7fd7a8db1b7b362590d85db99176a6e0884f231e128b411f1f24f19aee77bd9413973cbcaf90
|
7
|
+
data.tar.gz: 8f8c78a0ef4fc3c1334318813d1ffa944f770f5a2fca17c4b23c7ad89a29fa6a17b47d1caf1b3615ecad23ee9a0af6f80d19a72b2228af80887a4f0f51c1eed3
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Changes
|
2
2
|
|
3
|
+
### UNRELEASED
|
4
|
+
|
5
|
+
* Emit a deprecation warning when `JSON.load` create custom types without the `create_additions` option being explictly enabled.
|
6
|
+
* Prefer to use `JSON.unsafe_load(string)` or `JSON.load(string, create_additions: true)`.
|
7
|
+
* Emit a deprecation warning when serializing valid UTF-8 strings encoded in `ASCII_8BIT` aka `BINARY`.
|
8
|
+
* Bump required_ruby_version to 2.7.
|
9
|
+
* More performance improvments to `JSON.dump` and `JSON.generate`.
|
10
|
+
|
3
11
|
### 2024-11-04 (2.7.6)
|
4
12
|
|
5
13
|
* Fix a regression in JSON.generate when dealing with Hash keys that are string subclasses, call `to_json` on them.
|
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,33 +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
|
-
#ifndef RB_LIKELY
|
40
|
-
#define RB_LIKELY(expr) expr
|
41
|
-
#endif
|
42
|
-
|
43
|
-
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)
|
44
73
|
{
|
45
|
-
|
46
|
-
if (
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
+
}
|
51
80
|
}
|
52
81
|
|
53
82
|
static void fbuffer_free(FBuffer *fb)
|
54
83
|
{
|
55
|
-
if (fb->ptr
|
56
|
-
|
84
|
+
if (fb->ptr && fb->type == FBUFFER_HEAP_ALLOCATED) {
|
85
|
+
ruby_xfree(fb->ptr);
|
86
|
+
}
|
57
87
|
}
|
58
88
|
|
59
89
|
#ifndef JSON_GENERATOR
|
@@ -63,22 +93,34 @@ static void fbuffer_clear(FBuffer *fb)
|
|
63
93
|
}
|
64
94
|
#endif
|
65
95
|
|
66
|
-
static
|
96
|
+
static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
|
67
97
|
{
|
68
|
-
|
69
|
-
unsigned long required;
|
98
|
+
unsigned long required;
|
70
99
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
100
|
+
if (RB_UNLIKELY(!fb->ptr)) {
|
101
|
+
fb->ptr = ALLOC_N(char, fb->initial_length);
|
102
|
+
fb->capa = fb->initial_length;
|
103
|
+
}
|
75
104
|
|
76
|
-
|
105
|
+
for (required = fb->capa; requested > required - fb->len; required <<= 1);
|
77
106
|
|
78
|
-
|
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 {
|
79
114
|
REALLOC_N(fb->ptr, char, required);
|
80
|
-
fb->capa = required;
|
81
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);
|
82
124
|
}
|
83
125
|
}
|
84
126
|
|
@@ -103,7 +145,7 @@ static void fbuffer_append_str(FBuffer *fb, VALUE str)
|
|
103
145
|
}
|
104
146
|
#endif
|
105
147
|
|
106
|
-
static void fbuffer_append_char(FBuffer *fb, char newchr)
|
148
|
+
static inline void fbuffer_append_char(FBuffer *fb, char newchr)
|
107
149
|
{
|
108
150
|
fbuffer_inc_capa(fb, 1);
|
109
151
|
*(fb->ptr + fb->len) = newchr;
|
@@ -111,33 +153,25 @@ static void fbuffer_append_char(FBuffer *fb, char newchr)
|
|
111
153
|
}
|
112
154
|
|
113
155
|
#ifdef JSON_GENERATOR
|
114
|
-
static void freverse(char *start, char *end)
|
115
|
-
{
|
116
|
-
char c;
|
117
|
-
|
118
|
-
while (end > start) {
|
119
|
-
c = *end, *end-- = *start, *start++ = c;
|
120
|
-
}
|
121
|
-
}
|
122
|
-
|
123
156
|
static long fltoa(long number, char *buf)
|
124
157
|
{
|
125
|
-
static char digits[] = "0123456789";
|
158
|
+
static const char digits[] = "0123456789";
|
126
159
|
long sign = number;
|
127
160
|
char* tmp = buf;
|
128
161
|
|
129
162
|
if (sign < 0) number = -number;
|
130
|
-
do *tmp
|
131
|
-
if (sign < 0) *tmp
|
132
|
-
|
133
|
-
return tmp - buf;
|
163
|
+
do *tmp-- = digits[number % 10]; while (number /= 10);
|
164
|
+
if (sign < 0) *tmp-- = '-';
|
165
|
+
return buf - tmp;
|
134
166
|
}
|
135
167
|
|
168
|
+
#define LONG_BUFFER_SIZE 20
|
136
169
|
static void fbuffer_append_long(FBuffer *fb, long number)
|
137
170
|
{
|
138
|
-
char buf[
|
139
|
-
|
140
|
-
|
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);
|
141
175
|
}
|
142
176
|
|
143
177
|
static VALUE fbuffer_to_s(FBuffer *fb)
|