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.
@@ -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
- enum duplicate_key_action on_duplicate_key;
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, sym_escape_slash, sym_strict, sym_as_json, sym_sort_keys;
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, binary_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
- if (RB_ENCODING_GET_INLINED(str) == binary_encindex) {
874
- VALUE utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
875
- switch (rb_enc_str_coderange(utf8_string)) {
876
- case ENC_CODERANGE_7BIT:
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
- long len;
901
+ rb_len_t len;
905
902
  search_state search;
906
903
  search.buffer = buffer;
907
- RSTRING_GETMEM(obj, search.ptr, len);
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(obj)) {
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->on_duplicate_key != JSON_IGNORE) {
960
- VALUE do_raise = state->on_duplicate_key == JSON_RAISE ? Qtrue : Qfalse;
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
- long depth = ++data->depth;
1049
- if (RB_UNLIKELY(depth > state->max_nesting && state->max_nesting)) {
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->sort_keys)) {
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 (int i = 0; i < RARRAY_LEN(obj); i++) {
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
- tmp = rb_funcall(obj, i_to_s, 0);
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
- VALUE tmp = rb_funcall(obj, i_to_s, 0);
1167
- fbuffer_append_str(buffer, StringValue(tmp));
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", rb_funcall(obj, i_to_s, 0));
1189
+ raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", json_to_s(obj));
1187
1190
  }
1188
1191
 
1189
- VALUE tmp = rb_funcall(obj, i_to_s, 0);
1190
- fbuffer_append_str(buffer, tmp);
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
- generate_json_symbol(buffer, data, obj);
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
- generate_json_symbol(buffer, data, obj);
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
- * This string is put at the end of a line that holds a JSON array.
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
- * This string is put at the end of a line that holds a JSON array.
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, rb_convert_type(as_json, T_DATA, "Proc", "to_proc"));
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 cState_sort_keys_p(VALUE self)
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 Qnil;
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
- switch (state->on_duplicate_key) {
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
- * This sets the maximum level of data structure nesting in the generated JSON
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->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
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) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse;
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", cState_sort_keys_p, 0);
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_