json 2.7.6 → 2.8.0.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|