json 2.14.1 → 2.15.0
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 +6 -0
- data/README.md +3 -1
- data/ext/json/ext/generator/generator.c +14 -6
- data/ext/json/ext/vendor/fpconv.c +12 -11
- data/lib/json/truffle_ruby/generator.rb +21 -13
- data/lib/json/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff78e67c786dd7f165bdd12e945ad6cb9de9c15c491b7423a6a7b9cc176c4c56
|
4
|
+
data.tar.gz: '068efe1a1652768b10fb4da5c0fe8e0d4296147efcf0a75a02ca667e66bb60f7'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f326bc37bf1a00e3c379bbdf66591b3cd37a1b768f7432fcafe771eeede97b50a45151012d1e946c0c72038c7dc34cd0a935a685a9211a64699de235334d0a1a
|
7
|
+
data.tar.gz: ea2a1bfb35384feb19f9c16764490bbd57a772bbf2bfe44c206a3bc6f45e86d452cecb30830900e0f0e12e9ece5b9fa18aba25b2bee221b4982f805ec0df32a0
|
data/CHANGES.md
CHANGED
@@ -2,6 +2,11 @@
|
|
2
2
|
|
3
3
|
### Unreleased
|
4
4
|
|
5
|
+
### 2025-09-22 (2.15.0)
|
6
|
+
|
7
|
+
* `JSON::Coder` callback now receive a second argument to convey whether the object is a hash key.
|
8
|
+
* Tuned the floating point number generator to not use scientific notation as agressively.
|
9
|
+
|
5
10
|
### 2025-09-18 (2.14.1)
|
6
11
|
|
7
12
|
* Fix `IndexOutOfBoundsException` in the JRuby extension when encoding shared strings.
|
@@ -23,6 +28,7 @@
|
|
23
28
|
* Fix `JSON::Coder` to also invoke block for hash keys that aren't strings nor symbols.
|
24
29
|
* Fix `JSON.unsafe_load` usage with proc
|
25
30
|
* Fix the parser to more consistently reject invalid UTF-16 surogate pairs.
|
31
|
+
* Stop defining `String.json_create`, `String#to_json_raw`, `String#to_json_raw_object` when `json/add` isn't loaded.
|
26
32
|
|
27
33
|
### 2025-07-28 (2.13.2)
|
28
34
|
|
data/README.md
CHANGED
@@ -97,7 +97,7 @@ Instead it is recommended to use the newer `JSON::Coder` API:
|
|
97
97
|
|
98
98
|
```ruby
|
99
99
|
module MyApp
|
100
|
-
API_JSON_CODER = JSON::Coder.new do |object|
|
100
|
+
API_JSON_CODER = JSON::Coder.new do |object, is_object_key|
|
101
101
|
case object
|
102
102
|
when Time
|
103
103
|
object.iso8601(3)
|
@@ -113,6 +113,8 @@ puts MyApp::API_JSON_CODER.dump(Time.now.utc) # => "2025-01-21T08:41:44.286Z"
|
|
113
113
|
The provided block is called for all objects that don't have a native JSON equivalent, and
|
114
114
|
must return a Ruby object that has a native JSON equivalent.
|
115
115
|
|
116
|
+
It is also called for objects that do have a JSON equivalent, but are used as Hash keys, for instance `{ 1 => 2}`.
|
117
|
+
|
116
118
|
## Combining JSON fragments
|
117
119
|
|
118
120
|
To combine JSON fragments into a bigger JSON document, you can use `JSON::Fragment`:
|
@@ -29,6 +29,7 @@ typedef struct JSON_Generator_StateStruct {
|
|
29
29
|
|
30
30
|
enum duplicate_key_action on_duplicate_key;
|
31
31
|
|
32
|
+
bool as_json_single_arg;
|
32
33
|
bool allow_nan;
|
33
34
|
bool ascii_only;
|
34
35
|
bool script_safe;
|
@@ -1033,6 +1034,13 @@ json_inspect_hash_with_mixed_keys(struct hash_foreach_arg *arg)
|
|
1033
1034
|
}
|
1034
1035
|
}
|
1035
1036
|
|
1037
|
+
static VALUE
|
1038
|
+
json_call_as_json(JSON_Generator_State *state, VALUE object, VALUE is_key)
|
1039
|
+
{
|
1040
|
+
VALUE proc_args[2] = {object, is_key};
|
1041
|
+
return rb_proc_call_with_block(state->as_json, 2, proc_args, Qnil);
|
1042
|
+
}
|
1043
|
+
|
1036
1044
|
static int
|
1037
1045
|
json_object_i(VALUE key, VALUE val, VALUE _arg)
|
1038
1046
|
{
|
@@ -1086,7 +1094,7 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
|
|
1086
1094
|
default:
|
1087
1095
|
if (data->state->strict) {
|
1088
1096
|
if (RTEST(data->state->as_json) && !as_json_called) {
|
1089
|
-
key =
|
1097
|
+
key = json_call_as_json(data->state, key, Qtrue);
|
1090
1098
|
key_type = rb_type(key);
|
1091
1099
|
as_json_called = true;
|
1092
1100
|
goto start;
|
@@ -1328,7 +1336,7 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
|
|
1328
1336
|
/* for NaN and Infinity values we either raise an error or rely on Float#to_s. */
|
1329
1337
|
if (!allow_nan) {
|
1330
1338
|
if (data->state->strict && data->state->as_json) {
|
1331
|
-
VALUE casted_obj =
|
1339
|
+
VALUE casted_obj = json_call_as_json(data->state, obj, Qfalse);
|
1332
1340
|
if (casted_obj != obj) {
|
1333
1341
|
increase_depth(data);
|
1334
1342
|
generate_json(buffer, data, casted_obj);
|
@@ -1345,12 +1353,11 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
|
|
1345
1353
|
}
|
1346
1354
|
|
1347
1355
|
/* This implementation writes directly into the buffer. We reserve
|
1348
|
-
* the
|
1356
|
+
* the 32 characters that fpconv_dtoa states as its maximum.
|
1349
1357
|
*/
|
1350
|
-
fbuffer_inc_capa(buffer,
|
1358
|
+
fbuffer_inc_capa(buffer, 32);
|
1351
1359
|
char* d = buffer->ptr + buffer->len;
|
1352
1360
|
int len = fpconv_dtoa(value, d);
|
1353
|
-
|
1354
1361
|
/* fpconv_dtoa converts a float to its shortest string representation,
|
1355
1362
|
* but it adds a ".0" if this is a plain integer.
|
1356
1363
|
*/
|
@@ -1417,7 +1424,7 @@ start:
|
|
1417
1424
|
general:
|
1418
1425
|
if (data->state->strict) {
|
1419
1426
|
if (RTEST(data->state->as_json) && !as_json_called) {
|
1420
|
-
obj =
|
1427
|
+
obj = json_call_as_json(data->state, obj, Qfalse);
|
1421
1428
|
as_json_called = true;
|
1422
1429
|
goto start;
|
1423
1430
|
} else {
|
@@ -1943,6 +1950,7 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
|
|
1943
1950
|
else if (key == sym_allow_duplicate_key) { state->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
|
1944
1951
|
else if (key == sym_as_json) {
|
1945
1952
|
VALUE proc = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse;
|
1953
|
+
state->as_json_single_arg = proc && rb_proc_arity(proc) == 1;
|
1946
1954
|
state_write_value(data, &state->as_json, proc);
|
1947
1955
|
}
|
1948
1956
|
return ST_CONTINUE;
|
@@ -29,6 +29,10 @@
|
|
29
29
|
#include <string.h>
|
30
30
|
#include <stdint.h>
|
31
31
|
|
32
|
+
#ifdef JSON_DEBUG
|
33
|
+
#include <assert.h>
|
34
|
+
#endif
|
35
|
+
|
32
36
|
#define npowers 87
|
33
37
|
#define steppowers 8
|
34
38
|
#define firstpower -348 /* 10 ^ -348 */
|
@@ -320,15 +324,7 @@ static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg)
|
|
320
324
|
{
|
321
325
|
int exp = absv(K + ndigits - 1);
|
322
326
|
|
323
|
-
|
324
|
-
|
325
|
-
if(neg) {
|
326
|
-
max_trailing_zeros -= 1;
|
327
|
-
}
|
328
|
-
|
329
|
-
/* write plain integer */
|
330
|
-
if(K >= 0 && (exp < (ndigits + max_trailing_zeros))) {
|
331
|
-
|
327
|
+
if(K >= 0 && exp < 15) {
|
332
328
|
memcpy(dest, digits, ndigits);
|
333
329
|
memset(dest + ndigits, '0', K);
|
334
330
|
|
@@ -432,10 +428,12 @@ static int filter_special(double fp, char* dest)
|
|
432
428
|
*
|
433
429
|
* Input:
|
434
430
|
* fp -> the double to convert, dest -> destination buffer.
|
435
|
-
* The generated string will never be longer than
|
436
|
-
* Make sure to pass a pointer to at least
|
431
|
+
* The generated string will never be longer than 32 characters.
|
432
|
+
* Make sure to pass a pointer to at least 32 bytes of memory.
|
437
433
|
* The emitted string will not be null terminated.
|
438
434
|
*
|
435
|
+
*
|
436
|
+
*
|
439
437
|
* Output:
|
440
438
|
* The number of written characters.
|
441
439
|
*
|
@@ -474,6 +472,9 @@ static int fpconv_dtoa(double d, char dest[28])
|
|
474
472
|
int ndigits = grisu2(d, digits, &K);
|
475
473
|
|
476
474
|
str_len += emit_digits(digits, ndigits, dest + str_len, K, neg);
|
475
|
+
#ifdef JSON_DEBUG
|
476
|
+
assert(str_len <= 32);
|
477
|
+
#endif
|
477
478
|
|
478
479
|
return str_len;
|
479
480
|
}
|
@@ -47,6 +47,14 @@ module JSON
|
|
47
47
|
|
48
48
|
SCRIPT_SAFE_ESCAPE_PATTERN = /[\/"\\\x0-\x1f\u2028-\u2029]/
|
49
49
|
|
50
|
+
def self.native_type?(value) # :nodoc:
|
51
|
+
(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.native_key?(key) # :nodoc:
|
55
|
+
(Symbol === key || String === key)
|
56
|
+
end
|
57
|
+
|
50
58
|
# Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
|
51
59
|
# UTF16 big endian characters as \u????, and return it.
|
52
60
|
def self.utf8_to_json(string, script_safe = false) # :nodoc:
|
@@ -448,10 +456,10 @@ module JSON
|
|
448
456
|
state = State.from_state(state) if state
|
449
457
|
if state&.strict?
|
450
458
|
value = self
|
451
|
-
if state.strict? && !(
|
459
|
+
if state.strict? && !Generator.native_type?(value)
|
452
460
|
if state.as_json
|
453
|
-
value = state.as_json.call(value)
|
454
|
-
unless
|
461
|
+
value = state.as_json.call(value, false)
|
462
|
+
unless Generator.native_type?(value)
|
455
463
|
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
456
464
|
end
|
457
465
|
value.to_json(state)
|
@@ -509,12 +517,12 @@ module JSON
|
|
509
517
|
end
|
510
518
|
result << state.indent * depth if indent
|
511
519
|
|
512
|
-
if state.strict? && !(
|
520
|
+
if state.strict? && !Generator.native_key?(key)
|
513
521
|
if state.as_json
|
514
|
-
key = state.as_json.call(key)
|
522
|
+
key = state.as_json.call(key, true)
|
515
523
|
end
|
516
524
|
|
517
|
-
unless
|
525
|
+
unless Generator.native_key?(key)
|
518
526
|
raise GeneratorError.new("#{key.class} not allowed as object key in JSON", value)
|
519
527
|
end
|
520
528
|
end
|
@@ -527,10 +535,10 @@ module JSON
|
|
527
535
|
end
|
528
536
|
|
529
537
|
result = +"#{result}#{key_json}#{state.space_before}:#{state.space}"
|
530
|
-
if state.strict? && !(
|
538
|
+
if state.strict? && !Generator.native_type?(value)
|
531
539
|
if state.as_json
|
532
|
-
value = state.as_json.call(value)
|
533
|
-
unless
|
540
|
+
value = state.as_json.call(value, false)
|
541
|
+
unless Generator.native_type?(value)
|
534
542
|
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
535
543
|
end
|
536
544
|
result << value.to_json(state)
|
@@ -588,10 +596,10 @@ module JSON
|
|
588
596
|
each { |value|
|
589
597
|
result << delim unless first
|
590
598
|
result << state.indent * depth if indent
|
591
|
-
if state.strict? && !(
|
599
|
+
if state.strict? && !Generator.native_type?(value)
|
592
600
|
if state.as_json
|
593
|
-
value = state.as_json.call(value)
|
594
|
-
unless
|
601
|
+
value = state.as_json.call(value, false)
|
602
|
+
unless Generator.native_type?(value)
|
595
603
|
raise GeneratorError.new("#{value.class} returned by #{state.as_json} not allowed in JSON", value)
|
596
604
|
end
|
597
605
|
result << value.to_json(state)
|
@@ -625,7 +633,7 @@ module JSON
|
|
625
633
|
if state.allow_nan?
|
626
634
|
to_s
|
627
635
|
elsif state.strict? && state.as_json
|
628
|
-
casted_value = state.as_json.call(self)
|
636
|
+
casted_value = state.as_json.call(self, false)
|
629
637
|
|
630
638
|
if casted_value.equal?(self)
|
631
639
|
raise GeneratorError.new("#{self} not allowed in JSON", self)
|
data/lib/json/version.rb
CHANGED