json 2.21.2 → 3.1.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 +64 -1
- data/README.md +4 -84
- data/ext/json/ext/fbuffer/fbuffer.h +4 -0
- data/ext/json/ext/generator/generator.c +187 -81
- data/ext/json/ext/json.h +19 -0
- data/ext/json/ext/parser/parser.c +139 -138
- data/lib/json/common.rb +153 -412
- data/lib/json/ext/generator/state.rb +2 -33
- data/lib/json/ext.rb +129 -5
- data/lib/json/truffle_ruby/generator.rb +140 -102
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +51 -295
- metadata +2 -18
- data/lib/json/add/bigdecimal.rb +0 -58
- data/lib/json/add/complex.rb +0 -51
- data/lib/json/add/core.rb +0 -13
- data/lib/json/add/date.rb +0 -54
- data/lib/json/add/date_time.rb +0 -67
- data/lib/json/add/exception.rb +0 -49
- data/lib/json/add/ostruct.rb +0 -54
- data/lib/json/add/range.rb +0 -54
- data/lib/json/add/rational.rb +0 -49
- data/lib/json/add/regexp.rb +0 -48
- data/lib/json/add/set.rb +0 -48
- data/lib/json/add/string.rb +0 -35
- data/lib/json/add/struct.rb +0 -52
- data/lib/json/add/symbol.rb +0 -52
- data/lib/json/add/time.rb +0 -52
- data/lib/json/generic_object.rb +0 -67
|
@@ -9,12 +9,6 @@
|
|
|
9
9
|
|
|
10
10
|
/* ruby api and some helpers */
|
|
11
11
|
|
|
12
|
-
enum duplicate_key_action {
|
|
13
|
-
JSON_DEPRECATED = 0,
|
|
14
|
-
JSON_IGNORE,
|
|
15
|
-
JSON_RAISE,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
12
|
typedef struct JSON_Generator_StateStruct {
|
|
19
13
|
VALUE indent;
|
|
20
14
|
VALUE space;
|
|
@@ -27,21 +21,22 @@ typedef struct JSON_Generator_StateStruct {
|
|
|
27
21
|
long depth;
|
|
28
22
|
long buffer_initial_length;
|
|
29
23
|
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
bool allow_duplicate_key;
|
|
32
25
|
bool as_json_single_arg;
|
|
33
26
|
bool allow_nan;
|
|
34
27
|
bool ascii_only;
|
|
35
28
|
bool script_safe;
|
|
36
29
|
bool strict;
|
|
30
|
+
bool rfc8785;
|
|
37
31
|
VALUE sort_keys;
|
|
38
32
|
} JSON_Generator_State;
|
|
39
33
|
|
|
40
|
-
static VALUE mJSON, cState, cFragment, eGeneratorError, eNestingError, Encoding_UTF_8, default_sort_keys_proc
|
|
34
|
+
static VALUE mJSON, cState, cFragment, eGeneratorError, eNestingError, Encoding_UTF_8, default_sort_keys_proc,
|
|
35
|
+
rfc8785_number_formatter_proc, rfc8785_sort_keys_proc;
|
|
41
36
|
|
|
42
37
|
static ID i_to_s, i_to_json, i_new, i_encode;
|
|
43
38
|
static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan, sym_allow_duplicate_key,
|
|
44
|
-
sym_ascii_only, sym_depth, sym_buffer_initial_length, sym_script_safe,
|
|
39
|
+
sym_ascii_only, sym_depth, sym_buffer_initial_length, sym_script_safe, sym_strict, sym_as_json, sym_sort_keys, sym_rfc8785;
|
|
45
40
|
|
|
46
41
|
|
|
47
42
|
#define GET_STATE_TO(self, state) \
|
|
@@ -80,7 +75,7 @@ static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *dat
|
|
|
80
75
|
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
81
76
|
static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
82
77
|
|
|
83
|
-
static int usascii_encindex, utf8_encindex
|
|
78
|
+
static int usascii_encindex, utf8_encindex;
|
|
84
79
|
|
|
85
80
|
NORETURN(static void) raise_generator_error_str(VALUE invalid_object, VALUE str)
|
|
86
81
|
{
|
|
@@ -775,6 +770,12 @@ static void vstate_spill(struct generate_json_data *data)
|
|
|
775
770
|
RB_OBJ_WRITTEN(vstate, Qundef, state->sort_keys);
|
|
776
771
|
}
|
|
777
772
|
|
|
773
|
+
static inline VALUE json_to_s(VALUE obj)
|
|
774
|
+
{
|
|
775
|
+
VALUE tmp = rb_funcall(obj, i_to_s, 0);
|
|
776
|
+
return StringValue(tmp);
|
|
777
|
+
}
|
|
778
|
+
|
|
778
779
|
static inline VALUE json_call_to_json(struct generate_json_data *data, VALUE obj)
|
|
779
780
|
{
|
|
780
781
|
if (RB_UNLIKELY(!data->vstate)) {
|
|
@@ -870,21 +871,12 @@ NOINLINE(static) VALUE convert_invalid_encoding(struct generate_json_data *data,
|
|
|
870
871
|
}
|
|
871
872
|
}
|
|
872
873
|
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
return utf8_string;
|
|
878
|
-
case ENC_CODERANGE_VALID:
|
|
879
|
-
// For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
|
|
880
|
-
// TODO: Raise in 3.0.0
|
|
881
|
-
rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
|
|
882
|
-
return utf8_string;
|
|
883
|
-
break;
|
|
884
|
-
}
|
|
874
|
+
str = rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
|
|
875
|
+
Check_Type(str, T_STRING);
|
|
876
|
+
if (!valid_json_string_p(str)) {
|
|
877
|
+
raise_generator_error(str, "source sequence is illegal/malformed utf-8");
|
|
885
878
|
}
|
|
886
|
-
|
|
887
|
-
return rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
|
|
879
|
+
return str;
|
|
888
880
|
}
|
|
889
881
|
|
|
890
882
|
ALWAYS_INLINE(static) VALUE ensure_valid_encoding(struct generate_json_data *data, VALUE str, bool as_json_called, bool is_key)
|
|
@@ -899,12 +891,17 @@ ALWAYS_INLINE(static) VALUE ensure_valid_encoding(struct generate_json_data *dat
|
|
|
899
891
|
|
|
900
892
|
static void raw_generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
901
893
|
{
|
|
894
|
+
VALUE str = obj;
|
|
895
|
+
if (RB_UNLIKELY(buffer->io)) {
|
|
896
|
+
// IO writes can mutate the original string while we are reading it.
|
|
897
|
+
str = rb_str_new_frozen(str);
|
|
898
|
+
}
|
|
902
899
|
fbuffer_append_char(buffer, '"');
|
|
903
900
|
|
|
904
|
-
|
|
901
|
+
rb_len_t len;
|
|
905
902
|
search_state search;
|
|
906
903
|
search.buffer = buffer;
|
|
907
|
-
RSTRING_GETMEM(
|
|
904
|
+
RSTRING_GETMEM(str, search.ptr, len);
|
|
908
905
|
search.cursor = search.ptr;
|
|
909
906
|
search.end = search.ptr + len;
|
|
910
907
|
|
|
@@ -915,7 +912,7 @@ static void raw_generate_json_string(FBuffer *buffer, struct generate_json_data
|
|
|
915
912
|
search.chunk_end = NULL;
|
|
916
913
|
#endif /* HAVE_SIMD */
|
|
917
914
|
|
|
918
|
-
switch (json_str_coderange(
|
|
915
|
+
switch (json_str_coderange(str)) {
|
|
919
916
|
case ENC_CODERANGE_7BIT:
|
|
920
917
|
case ENC_CODERANGE_VALID:
|
|
921
918
|
if (RB_UNLIKELY(data->state->ascii_only)) {
|
|
@@ -931,6 +928,7 @@ static void raw_generate_json_string(FBuffer *buffer, struct generate_json_data
|
|
|
931
928
|
break;
|
|
932
929
|
}
|
|
933
930
|
fbuffer_append_char(buffer, '"');
|
|
931
|
+
RB_GC_GUARD(str);
|
|
934
932
|
}
|
|
935
933
|
|
|
936
934
|
static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
@@ -956,9 +954,8 @@ json_inspect_hash_with_mixed_keys(struct hash_foreach_arg *arg)
|
|
|
956
954
|
arg->mixed_keys_encountered = true;
|
|
957
955
|
|
|
958
956
|
JSON_Generator_State *state = arg->data->state;
|
|
959
|
-
if (state->
|
|
960
|
-
|
|
961
|
-
rb_funcall(mJSON, rb_intern("on_mixed_keys_hash"), 2, arg->hash, do_raise);
|
|
957
|
+
if (!state->allow_duplicate_key) {
|
|
958
|
+
rb_funcall(mJSON, rb_intern("on_mixed_keys_hash"), 1, arg->hash);
|
|
962
959
|
}
|
|
963
960
|
}
|
|
964
961
|
|
|
@@ -1045,16 +1042,19 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
|
|
|
1045
1042
|
static inline long increase_depth(struct generate_json_data *data)
|
|
1046
1043
|
{
|
|
1047
1044
|
JSON_Generator_State *state = data->state;
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
rb_raise(eNestingError, "nesting of %ld is too deep. Did you try to serialize objects with circular references?", --data->depth);
|
|
1045
|
+
if (RB_UNLIKELY(data->depth >= state->max_nesting && state->max_nesting)) {
|
|
1046
|
+
rb_raise(eNestingError, "nesting of %ld is too deep. Did you try to serialize objects with circular references?", data->depth + 1);
|
|
1051
1047
|
}
|
|
1052
|
-
return depth;
|
|
1048
|
+
return ++data->depth;
|
|
1053
1049
|
}
|
|
1054
1050
|
|
|
1055
1051
|
static void generate_json_object(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1056
1052
|
{
|
|
1057
|
-
if (RB_UNLIKELY(data->state->
|
|
1053
|
+
if (RB_UNLIKELY(data->state->rfc8785)) {
|
|
1054
|
+
VALUE args[2] = {obj, data->state->strict ? data->state->as_json : Qnil};
|
|
1055
|
+
obj = rb_proc_call_with_block(rfc8785_sort_keys_proc, 2, args, Qnil);
|
|
1056
|
+
Check_Type(obj, T_HASH);
|
|
1057
|
+
} else if (RB_UNLIKELY(data->state->sort_keys)) {
|
|
1058
1058
|
obj = rb_proc_call_with_block(data->state->sort_keys, 1, &obj, Qnil);
|
|
1059
1059
|
Check_Type(obj, T_HASH);
|
|
1060
1060
|
}
|
|
@@ -1098,7 +1098,7 @@ static void generate_json_array(FBuffer *buffer, struct generate_json_data *data
|
|
|
1098
1098
|
|
|
1099
1099
|
fbuffer_append_char(buffer, '[');
|
|
1100
1100
|
if (RB_UNLIKELY(data->state->array_nl)) fbuffer_append_str(buffer, data->state->array_nl);
|
|
1101
|
-
for (
|
|
1101
|
+
for (rb_len_t i = 0; i < RARRAY_LEN(obj); i++) {
|
|
1102
1102
|
if (i > 0) {
|
|
1103
1103
|
fbuffer_append_char(buffer, ',');
|
|
1104
1104
|
if (RB_UNLIKELY(data->state->array_nl)) fbuffer_append_str(buffer, data->state->array_nl);
|
|
@@ -1126,18 +1126,7 @@ static void generate_json_fallback(FBuffer *buffer, struct generate_json_data *d
|
|
|
1126
1126
|
Check_Type(tmp, T_STRING);
|
|
1127
1127
|
fbuffer_append_str(buffer, tmp);
|
|
1128
1128
|
} else {
|
|
1129
|
-
|
|
1130
|
-
Check_Type(tmp, T_STRING);
|
|
1131
|
-
generate_json_string(buffer, data, tmp);
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
static inline void generate_json_symbol(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1136
|
-
{
|
|
1137
|
-
if (data->state->strict) {
|
|
1138
|
-
generate_json_string(buffer, data, rb_sym2str(obj));
|
|
1139
|
-
} else {
|
|
1140
|
-
generate_json_fallback(buffer, data, obj);
|
|
1129
|
+
generate_json_string(buffer, data, json_to_s(obj));
|
|
1141
1130
|
}
|
|
1142
1131
|
}
|
|
1143
1132
|
|
|
@@ -1156,15 +1145,29 @@ static void generate_json_true(FBuffer *buffer, struct generate_json_data *data,
|
|
|
1156
1145
|
fbuffer_append(buffer, "true", 4);
|
|
1157
1146
|
}
|
|
1158
1147
|
|
|
1148
|
+
static void generate_json_rfc8785_number(FBuffer *buffer, VALUE obj)
|
|
1149
|
+
{
|
|
1150
|
+
VALUE str = rb_proc_call_with_block(rfc8785_number_formatter_proc, 1, &obj, Qnil);
|
|
1151
|
+
Check_Type(str, T_STRING);
|
|
1152
|
+
fbuffer_append_str(buffer, str);
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1159
1155
|
static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1160
1156
|
{
|
|
1157
|
+
if (RB_UNLIKELY(data->state->rfc8785)) {
|
|
1158
|
+
generate_json_rfc8785_number(buffer, obj);
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
1161
|
fbuffer_append_long(buffer, FIX2LONG(obj));
|
|
1162
1162
|
}
|
|
1163
1163
|
|
|
1164
1164
|
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1165
1165
|
{
|
|
1166
|
-
|
|
1167
|
-
|
|
1166
|
+
if (RB_UNLIKELY(data->state->rfc8785)) {
|
|
1167
|
+
generate_json_rfc8785_number(buffer, obj);
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
fbuffer_append_str(buffer, json_to_s(obj));
|
|
1168
1171
|
}
|
|
1169
1172
|
|
|
1170
1173
|
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
@@ -1183,11 +1186,15 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
|
|
|
1183
1186
|
return;
|
|
1184
1187
|
}
|
|
1185
1188
|
}
|
|
1186
|
-
raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON",
|
|
1189
|
+
raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", json_to_s(obj));
|
|
1187
1190
|
}
|
|
1188
1191
|
|
|
1189
|
-
|
|
1190
|
-
|
|
1192
|
+
fbuffer_append_str(buffer, json_to_s(obj));
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
if (RB_UNLIKELY(data->state->rfc8785)) {
|
|
1197
|
+
generate_json_rfc8785_number(buffer, obj);
|
|
1191
1198
|
return;
|
|
1192
1199
|
}
|
|
1193
1200
|
|
|
@@ -1226,7 +1233,13 @@ start:
|
|
|
1226
1233
|
} else if (RB_FLONUM_P(obj)) {
|
|
1227
1234
|
generate_json_float(buffer, data, obj);
|
|
1228
1235
|
} else if (RB_STATIC_SYM_P(obj)) {
|
|
1229
|
-
|
|
1236
|
+
if (data->state->strict) {
|
|
1237
|
+
obj = rb_sym2str(obj);
|
|
1238
|
+
JSON_ASSERT(RBASIC_CLASS(obj) == rb_cString);
|
|
1239
|
+
goto generate_string;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
generate_json_fallback(buffer, data, obj);
|
|
1230
1243
|
} else {
|
|
1231
1244
|
goto general;
|
|
1232
1245
|
}
|
|
@@ -1247,6 +1260,7 @@ start:
|
|
|
1247
1260
|
case T_STRING:
|
|
1248
1261
|
if (fallback && klass != rb_cString) goto general;
|
|
1249
1262
|
|
|
1263
|
+
generate_string:
|
|
1250
1264
|
if (RB_LIKELY(valid_json_string_p(obj))) {
|
|
1251
1265
|
raw_generate_json_string(buffer, data, obj);
|
|
1252
1266
|
} else if (as_json_called) {
|
|
@@ -1258,7 +1272,13 @@ start:
|
|
|
1258
1272
|
}
|
|
1259
1273
|
break;
|
|
1260
1274
|
case T_SYMBOL:
|
|
1261
|
-
|
|
1275
|
+
if (data->state->strict) {
|
|
1276
|
+
obj = rb_sym2str(obj);
|
|
1277
|
+
JSON_ASSERT(RBASIC_CLASS(obj) == rb_cString);
|
|
1278
|
+
goto generate_string;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
generate_json_fallback(buffer, data, obj);
|
|
1262
1282
|
break;
|
|
1263
1283
|
case T_FLOAT:
|
|
1264
1284
|
if (fallback && klass != rb_cFloat) goto general;
|
|
@@ -1295,10 +1315,28 @@ static void generate_json_no_fallback(FBuffer *buffer, struct generate_json_data
|
|
|
1295
1315
|
generate_json_general(buffer, data, obj, false);
|
|
1296
1316
|
}
|
|
1297
1317
|
|
|
1318
|
+
static void validate_rfc8785(JSON_Generator_State *state)
|
|
1319
|
+
{
|
|
1320
|
+
if (!state->rfc8785) return;
|
|
1321
|
+
|
|
1322
|
+
const char *option = state->indent ? "indent" :
|
|
1323
|
+
state->space ? "space" :
|
|
1324
|
+
state->space_before ? "space_before" :
|
|
1325
|
+
state->object_nl ? "object_nl" :
|
|
1326
|
+
state->array_nl ? "array_nl" :
|
|
1327
|
+
state->ascii_only ? "ascii_only" :
|
|
1328
|
+
state->script_safe ? "script_safe" :
|
|
1329
|
+
state->allow_nan ? "allow_nan" : NULL;
|
|
1330
|
+
if (option) {
|
|
1331
|
+
rb_raise(rb_eArgError, "%s cannot be used with rfc8785", option);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1298
1335
|
static VALUE generate_json_try(VALUE d)
|
|
1299
1336
|
{
|
|
1300
1337
|
struct generate_json_data *data = (struct generate_json_data *)d;
|
|
1301
1338
|
|
|
1339
|
+
validate_rfc8785(data->state);
|
|
1302
1340
|
data->func(data->buffer, data, data->obj);
|
|
1303
1341
|
|
|
1304
1342
|
return fbuffer_finalize(data->buffer);
|
|
@@ -1546,7 +1584,7 @@ static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
|
|
1546
1584
|
/*
|
|
1547
1585
|
* call-seq: as_json()
|
|
1548
1586
|
*
|
|
1549
|
-
*
|
|
1587
|
+
* Returns the callback used to convert unsupported objects in strict mode.
|
|
1550
1588
|
*/
|
|
1551
1589
|
static VALUE cState_as_json(VALUE self)
|
|
1552
1590
|
{
|
|
@@ -1554,16 +1592,28 @@ static VALUE cState_as_json(VALUE self)
|
|
|
1554
1592
|
return state->as_json;
|
|
1555
1593
|
}
|
|
1556
1594
|
|
|
1595
|
+
static VALUE as_json_config(VALUE value)
|
|
1596
|
+
{
|
|
1597
|
+
if (rb_obj_is_proc(value)) {
|
|
1598
|
+
return value;
|
|
1599
|
+
}
|
|
1600
|
+
VALUE proc = rb_check_funcall(value, rb_intern("to_proc"), 0, NULL);
|
|
1601
|
+
if (proc == Qundef || !rb_obj_is_proc(proc)) {
|
|
1602
|
+
rb_raise(rb_eTypeError, "as_json must be a Proc");
|
|
1603
|
+
}
|
|
1604
|
+
return proc;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1557
1607
|
/*
|
|
1558
1608
|
* call-seq: as_json=(as_json)
|
|
1559
1609
|
*
|
|
1560
|
-
*
|
|
1610
|
+
* Sets the Proc used to convert unsupported objects in strict mode.
|
|
1561
1611
|
*/
|
|
1562
1612
|
static VALUE cState_as_json_set(VALUE self, VALUE as_json)
|
|
1563
1613
|
{
|
|
1564
1614
|
rb_check_frozen(self);
|
|
1565
1615
|
GET_STATE(self);
|
|
1566
|
-
RB_OBJ_WRITE(self, &state->as_json,
|
|
1616
|
+
RB_OBJ_WRITE(self, &state->as_json, as_json_config(as_json));
|
|
1567
1617
|
return Qnil;
|
|
1568
1618
|
}
|
|
1569
1619
|
|
|
@@ -1737,9 +1787,34 @@ static VALUE cState_set_default_sort_keys_proc(VALUE self, VALUE proc)
|
|
|
1737
1787
|
if (!rb_obj_is_proc(proc)) {
|
|
1738
1788
|
rb_raise(rb_eTypeError, "sort_key_proc must be a Proc");
|
|
1739
1789
|
}
|
|
1790
|
+
if (default_sort_keys_proc) {
|
|
1791
|
+
rb_raise(rb_eArgError, "sort_key_proc can only be set once");
|
|
1792
|
+
}
|
|
1740
1793
|
return default_sort_keys_proc = proc;
|
|
1741
1794
|
}
|
|
1742
1795
|
|
|
1796
|
+
static VALUE cState_set_rfc8785_number_formatter_proc(VALUE self, VALUE proc)
|
|
1797
|
+
{
|
|
1798
|
+
if (!rb_obj_is_proc(proc)) {
|
|
1799
|
+
rb_raise(rb_eTypeError, "rfc8785_number_formatter_proc must be a Proc");
|
|
1800
|
+
}
|
|
1801
|
+
if (rfc8785_number_formatter_proc) {
|
|
1802
|
+
rb_raise(rb_eArgError, "rfc8785_number_formatter_proc can only be set once");
|
|
1803
|
+
}
|
|
1804
|
+
return rfc8785_number_formatter_proc = proc;
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
static VALUE cState_set_rfc8785_sort_keys_proc(VALUE self, VALUE proc)
|
|
1808
|
+
{
|
|
1809
|
+
if (!rb_obj_is_proc(proc)) {
|
|
1810
|
+
rb_raise(rb_eTypeError, "rfc8785_sort_keys_proc must be a Proc");
|
|
1811
|
+
}
|
|
1812
|
+
if (rfc8785_sort_keys_proc) {
|
|
1813
|
+
rb_raise(rb_eArgError, "rfc8785_sort_keys_proc can only be set once");
|
|
1814
|
+
}
|
|
1815
|
+
return rfc8785_sort_keys_proc = proc;
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1743
1818
|
static VALUE normalize_sort_keys(VALUE value)
|
|
1744
1819
|
{
|
|
1745
1820
|
if (rb_obj_is_proc(value)) {
|
|
@@ -1758,7 +1833,7 @@ static VALUE normalize_sort_keys(VALUE value)
|
|
|
1758
1833
|
*
|
|
1759
1834
|
* Get the value of sort_keys.
|
|
1760
1835
|
*/
|
|
1761
|
-
static VALUE
|
|
1836
|
+
static VALUE cState_sort_keys(VALUE self)
|
|
1762
1837
|
{
|
|
1763
1838
|
GET_STATE(self);
|
|
1764
1839
|
return state->sort_keys;
|
|
@@ -1778,20 +1853,39 @@ static VALUE cState_sort_keys_set(VALUE self, VALUE value)
|
|
|
1778
1853
|
rb_check_frozen(self);
|
|
1779
1854
|
GET_STATE(self);
|
|
1780
1855
|
RB_OBJ_WRITE(self, &state->sort_keys, normalize_sort_keys(value));
|
|
1781
|
-
return
|
|
1856
|
+
return state->sort_keys;
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
|
|
1860
|
+
/*
|
|
1861
|
+
* call-seq: rfc8785?
|
|
1862
|
+
*
|
|
1863
|
+
* Get whether RFC8785 (canonicalization) is enabled.
|
|
1864
|
+
*/
|
|
1865
|
+
static VALUE cState_rfc8785_p(VALUE self)
|
|
1866
|
+
{
|
|
1867
|
+
GET_STATE(self);
|
|
1868
|
+
return state->rfc8785 ? Qtrue : Qfalse;
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
/*
|
|
1872
|
+
* call-seq: rfc8785=
|
|
1873
|
+
*
|
|
1874
|
+
* Sets whether RFC8785 (canonicalization) is enabled.
|
|
1875
|
+
*/
|
|
1876
|
+
|
|
1877
|
+
static VALUE cState_rfc8785_set(VALUE self, VALUE value)
|
|
1878
|
+
{
|
|
1879
|
+
rb_check_frozen(self);
|
|
1880
|
+
GET_STATE(self);
|
|
1881
|
+
state->rfc8785 = RTEST(value);
|
|
1882
|
+
return state->rfc8785 ? Qtrue : Qfalse;
|
|
1782
1883
|
}
|
|
1783
1884
|
|
|
1784
1885
|
static VALUE cState_allow_duplicate_key_p(VALUE self)
|
|
1785
1886
|
{
|
|
1786
1887
|
GET_STATE(self);
|
|
1787
|
-
|
|
1788
|
-
case JSON_IGNORE:
|
|
1789
|
-
return Qtrue;
|
|
1790
|
-
case JSON_DEPRECATED:
|
|
1791
|
-
return Qnil;
|
|
1792
|
-
default:
|
|
1793
|
-
return Qfalse;
|
|
1794
|
-
}
|
|
1888
|
+
return state->allow_duplicate_key ? Qtrue : Qfalse;
|
|
1795
1889
|
}
|
|
1796
1890
|
|
|
1797
1891
|
/*
|
|
@@ -1808,8 +1902,7 @@ static VALUE cState_depth(VALUE self)
|
|
|
1808
1902
|
/*
|
|
1809
1903
|
* call-seq: depth=(depth)
|
|
1810
1904
|
*
|
|
1811
|
-
*
|
|
1812
|
-
* to the integer depth, max_nesting = 0 if no maximum should be checked.
|
|
1905
|
+
* Sets the current depth of data structure nesting to the integer +depth+.
|
|
1813
1906
|
*/
|
|
1814
1907
|
static VALUE cState_depth_set(VALUE self, VALUE depth)
|
|
1815
1908
|
{
|
|
@@ -1856,6 +1949,7 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
|
|
|
1856
1949
|
struct configure_state_data {
|
|
1857
1950
|
JSON_Generator_State *state;
|
|
1858
1951
|
VALUE vstate; // Ruby object that owns the state, or Qfalse if stack-allocated
|
|
1952
|
+
VALUE unknown_keywords;
|
|
1859
1953
|
};
|
|
1860
1954
|
|
|
1861
1955
|
static inline void state_write_value(struct configure_state_data *data, VALUE *field, VALUE value)
|
|
@@ -1883,17 +1977,23 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
|
|
|
1883
1977
|
else if (key == sym_depth) { state->depth = depth_config(val); }
|
|
1884
1978
|
else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); }
|
|
1885
1979
|
else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
|
|
1886
|
-
else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
|
|
1887
1980
|
else if (key == sym_strict) { state->strict = RTEST(val); }
|
|
1888
|
-
else if (key == sym_allow_duplicate_key) { state->
|
|
1981
|
+
else if (key == sym_allow_duplicate_key) { state->allow_duplicate_key = RTEST(val); }
|
|
1982
|
+
else if (key == sym_rfc8785) { state->rfc8785 = RTEST(val); }
|
|
1889
1983
|
else if (key == sym_as_json) {
|
|
1890
|
-
VALUE proc = RTEST(val) ?
|
|
1984
|
+
VALUE proc = RTEST(val) ? as_json_config(val) : Qfalse;
|
|
1891
1985
|
state->as_json_single_arg = proc && rb_proc_arity(proc) == 1;
|
|
1892
1986
|
state_write_value(data, &state->as_json, proc);
|
|
1893
1987
|
}
|
|
1894
1988
|
else if (key == sym_sort_keys) {
|
|
1895
1989
|
state_write_value(data, &state->sort_keys, normalize_sort_keys(val));
|
|
1896
1990
|
}
|
|
1991
|
+
else {
|
|
1992
|
+
if (!data->unknown_keywords) {
|
|
1993
|
+
data->unknown_keywords = rb_obj_hide(rb_ary_new());
|
|
1994
|
+
}
|
|
1995
|
+
rb_ary_push(data->unknown_keywords, key);
|
|
1996
|
+
}
|
|
1897
1997
|
return ST_CONTINUE;
|
|
1898
1998
|
}
|
|
1899
1999
|
|
|
@@ -1907,12 +2007,16 @@ static void configure_state(JSON_Generator_State *state, VALUE vstate, VALUE con
|
|
|
1907
2007
|
|
|
1908
2008
|
struct configure_state_data data = {
|
|
1909
2009
|
.state = state,
|
|
1910
|
-
.vstate = vstate
|
|
2010
|
+
.vstate = vstate,
|
|
2011
|
+
.unknown_keywords = Qfalse,
|
|
1911
2012
|
};
|
|
1912
2013
|
|
|
1913
2014
|
// We assume in most cases few keys are set so it's faster to go over
|
|
1914
2015
|
// the provided keys than to check all possible keys.
|
|
1915
2016
|
rb_hash_foreach(config, configure_state_i, (VALUE)&data);
|
|
2017
|
+
|
|
2018
|
+
raise_argument_error_on_unknown_keywords(data.unknown_keywords);
|
|
2019
|
+
validate_rfc8785(state);
|
|
1916
2020
|
}
|
|
1917
2021
|
|
|
1918
2022
|
static VALUE cState_configure(VALUE self, VALUE opts)
|
|
@@ -1972,6 +2076,8 @@ void Init_generator(void)
|
|
|
1972
2076
|
VALUE mGenerator = rb_define_module_under(mExt, "Generator");
|
|
1973
2077
|
|
|
1974
2078
|
rb_global_variable(&default_sort_keys_proc);
|
|
2079
|
+
rb_global_variable(&rfc8785_number_formatter_proc);
|
|
2080
|
+
rb_global_variable(&rfc8785_sort_keys_proc);
|
|
1975
2081
|
|
|
1976
2082
|
rb_global_variable(&eGeneratorError);
|
|
1977
2083
|
eGeneratorError = rb_path2class("JSON::GeneratorError");
|
|
@@ -1983,6 +2089,8 @@ void Init_generator(void)
|
|
|
1983
2089
|
rb_define_alloc_func(cState, cState_s_allocate);
|
|
1984
2090
|
rb_define_singleton_method(cState, "from_state", cState_from_state_s, 1);
|
|
1985
2091
|
rb_define_singleton_method(cState, "default_sort_keys_proc=", cState_set_default_sort_keys_proc, 1);
|
|
2092
|
+
rb_define_singleton_method(cState, "rfc8785_number_formatter_proc=", cState_set_rfc8785_number_formatter_proc, 1);
|
|
2093
|
+
rb_define_singleton_method(cState, "rfc8785_sort_keys_proc=", cState_set_rfc8785_sort_keys_proc, 1);
|
|
1986
2094
|
|
|
1987
2095
|
rb_define_method(cState, "initialize", cState_initialize, -1);
|
|
1988
2096
|
rb_define_alias(cState, "initialize", "initialize"); // avoid method redefinition warnings
|
|
@@ -2006,9 +2114,6 @@ void Init_generator(void)
|
|
|
2006
2114
|
rb_define_method(cState, "script_safe", cState_script_safe, 0);
|
|
2007
2115
|
rb_define_method(cState, "script_safe?", cState_script_safe, 0);
|
|
2008
2116
|
rb_define_method(cState, "script_safe=", cState_script_safe_set, 1);
|
|
2009
|
-
rb_define_alias(cState, "escape_slash", "script_safe");
|
|
2010
|
-
rb_define_alias(cState, "escape_slash?", "script_safe?");
|
|
2011
|
-
rb_define_alias(cState, "escape_slash=", "script_safe=");
|
|
2012
2117
|
rb_define_method(cState, "strict", cState_strict, 0);
|
|
2013
2118
|
rb_define_method(cState, "strict?", cState_strict, 0);
|
|
2014
2119
|
rb_define_method(cState, "strict=", cState_strict_set, 1);
|
|
@@ -2023,8 +2128,10 @@ void Init_generator(void)
|
|
|
2023
2128
|
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
|
|
2024
2129
|
rb_define_method(cState, "generate", cState_generate, -1);
|
|
2025
2130
|
rb_define_method(cState, "_generate_no_fallback", cState_generate_no_fallback, -1);
|
|
2026
|
-
rb_define_method(cState, "sort_keys",
|
|
2131
|
+
rb_define_method(cState, "sort_keys", cState_sort_keys, 0);
|
|
2027
2132
|
rb_define_method(cState, "sort_keys=", cState_sort_keys_set, 1);
|
|
2133
|
+
rb_define_method(cState, "rfc8785?", cState_rfc8785_p, 0);
|
|
2134
|
+
rb_define_method(cState, "rfc8785=", cState_rfc8785_set, 1);
|
|
2028
2135
|
|
|
2029
2136
|
rb_define_private_method(cState, "allow_duplicate_key?", cState_allow_duplicate_key_p, 0);
|
|
2030
2137
|
|
|
@@ -2050,15 +2157,14 @@ void Init_generator(void)
|
|
|
2050
2157
|
sym_depth = ID2SYM(rb_intern("depth"));
|
|
2051
2158
|
sym_buffer_initial_length = ID2SYM(rb_intern("buffer_initial_length"));
|
|
2052
2159
|
sym_script_safe = ID2SYM(rb_intern("script_safe"));
|
|
2053
|
-
sym_escape_slash = ID2SYM(rb_intern("escape_slash"));
|
|
2054
2160
|
sym_strict = ID2SYM(rb_intern("strict"));
|
|
2055
2161
|
sym_as_json = ID2SYM(rb_intern("as_json"));
|
|
2056
2162
|
sym_allow_duplicate_key = ID2SYM(rb_intern("allow_duplicate_key"));
|
|
2057
2163
|
sym_sort_keys = ID2SYM(rb_intern("sort_keys"));
|
|
2164
|
+
sym_rfc8785 = ID2SYM(rb_intern("rfc8785"));
|
|
2058
2165
|
|
|
2059
2166
|
usascii_encindex = rb_usascii_encindex();
|
|
2060
2167
|
utf8_encindex = rb_utf8_encindex();
|
|
2061
|
-
binary_encindex = rb_ascii8bit_encindex();
|
|
2062
2168
|
|
|
2063
2169
|
rb_require("json/ext/generator/state");
|
|
2064
2170
|
|
data/ext/json/ext/json.h
CHANGED
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
#include "ruby/encoding.h"
|
|
6
6
|
#include <stdint.h>
|
|
7
7
|
|
|
8
|
+
#ifndef HAVE_RB_LEN_T
|
|
9
|
+
typedef long rb_len_t;
|
|
10
|
+
# define LEN2NUM LONG2NUM
|
|
11
|
+
# define PRIdLEN "ld"
|
|
12
|
+
#endif
|
|
13
|
+
|
|
8
14
|
#ifndef RBIMPL_ASSERT_OR_ASSUME
|
|
9
15
|
# define RBIMPL_ASSERT_OR_ASSUME(x)
|
|
10
16
|
#endif
|
|
@@ -180,4 +186,17 @@ static inline VALUE json_rb_catch_obj(VALUE tag, VALUE (*func)(VALUE args), VALU
|
|
|
180
186
|
|
|
181
187
|
#endif // JSON_TRUFFLERUBY_RB_CATCH_BUG
|
|
182
188
|
|
|
189
|
+
static inline void raise_argument_error_on_unknown_keywords(VALUE unknown_keywords)
|
|
190
|
+
{
|
|
191
|
+
if (RB_UNLIKELY(unknown_keywords)) {
|
|
192
|
+
if (RARRAY_LEN(unknown_keywords) == 1) {
|
|
193
|
+
rb_raise(rb_eArgError, "unknown keyword: %" PRIsVALUE, RARRAY_AREF(unknown_keywords, 0));
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
VALUE keywords = rb_ary_join(unknown_keywords, rb_utf8_str_new_cstr(", "));
|
|
197
|
+
rb_raise(rb_eArgError, "unknown keywords: %" PRIsVALUE, keywords);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
183
202
|
#endif // _JSON_H_
|