json 2.3.1 → 2.5.1

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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +22 -0
  3. data/LICENSE +56 -0
  4. data/VERSION +1 -1
  5. data/ext/json/ext/generator/generator.c +60 -11
  6. data/ext/json/ext/generator/generator.h +5 -2
  7. data/ext/json/ext/parser/extconf.rb +25 -0
  8. data/ext/json/ext/parser/parser.c +110 -68
  9. data/ext/json/ext/parser/parser.h +1 -0
  10. data/ext/json/ext/parser/parser.rl +67 -25
  11. data/ext/json/extconf.rb +1 -0
  12. data/json.gemspec +11 -77
  13. data/lib/json.rb +171 -0
  14. data/lib/json/add/complex.rb +0 -1
  15. data/lib/json/add/rational.rb +0 -1
  16. data/lib/json/common.rb +240 -228
  17. data/lib/json/pure/generator.rb +28 -8
  18. data/lib/json/pure/parser.rb +20 -2
  19. data/lib/json/version.rb +1 -1
  20. data/tests/fixtures/fail29.json +1 -0
  21. data/tests/fixtures/fail30.json +1 -0
  22. data/tests/fixtures/fail31.json +1 -0
  23. data/tests/fixtures/fail32.json +1 -0
  24. data/tests/json_addition_test.rb +0 -4
  25. data/tests/json_common_interface_test.rb +43 -0
  26. data/tests/json_fixtures_test.rb +3 -0
  27. data/tests/json_generator_test.rb +16 -38
  28. data/tests/json_parser_test.rb +25 -0
  29. data/tests/lib/core_assertions.rb +763 -0
  30. data/tests/lib/envutil.rb +365 -0
  31. data/tests/lib/find_executable.rb +22 -0
  32. data/tests/lib/helper.rb +4 -0
  33. data/tests/ractor_test.rb +30 -0
  34. data/tests/test_helper.rb +3 -3
  35. metadata +16 -37
  36. data/.gitignore +0 -18
  37. data/.travis.yml +0 -26
  38. data/README-json-jruby.md +0 -33
  39. data/Rakefile +0 -334
  40. data/diagrams/.keep +0 -0
  41. data/install.rb +0 -23
  42. data/java/src/json/ext/ByteListTranscoder.java +0 -166
  43. data/java/src/json/ext/Generator.java +0 -466
  44. data/java/src/json/ext/GeneratorMethods.java +0 -231
  45. data/java/src/json/ext/GeneratorService.java +0 -42
  46. data/java/src/json/ext/GeneratorState.java +0 -490
  47. data/java/src/json/ext/OptionsReader.java +0 -113
  48. data/java/src/json/ext/Parser.java +0 -2362
  49. data/java/src/json/ext/Parser.rl +0 -893
  50. data/java/src/json/ext/ParserService.java +0 -34
  51. data/java/src/json/ext/RuntimeInfo.java +0 -116
  52. data/java/src/json/ext/StringDecoder.java +0 -166
  53. data/java/src/json/ext/StringEncoder.java +0 -111
  54. data/java/src/json/ext/Utils.java +0 -88
  55. data/json-java.gemspec +0 -37
  56. data/json_pure.gemspec +0 -33
  57. data/references/rfc7159.txt +0 -899
  58. data/tools/diff.sh +0 -18
  59. data/tools/fuzz.rb +0 -131
  60. data/tools/server.rb +0 -62
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 80444509bc162d6df8e9cc3e7af2fc28507c06aef49cbfc1dd9e5990af42b14f
4
- data.tar.gz: 8541be9708b44604eeeecac22f89c47933d32c90606f23c1d37e70c8b2d3e9db
3
+ metadata.gz: 4ba367cf703870f72ec5de7af43e713095df4b9c88cb0ae12a4c10455052383a
4
+ data.tar.gz: 622fc0230b9a26ddde47fb3e81c2cf2f0143c22cbfd2429019db1a0f9eef5aaa
5
5
  SHA512:
6
- metadata.gz: 1df7b5ee2bf58103f0b5776c4a581aa3b013ad4b3a85a442d37bb72dc62aaf04dc42ed1080fb307fec1d1e9128c9f21e43827c7f15494cb0f9f310f7189bdc5e
7
- data.tar.gz: 15ba56ce5d0e04c5326feb9e9faf2627628a715fa4bbeaec5c4aadeab5f27a65135f4f24f142b361f62ca37bbf36380f671d7ae35d46991737e4fc62423a6f9b
6
+ metadata.gz: 1cab7c9113f03333b720a039fd065d5dd376ab3b4dda1630ccf316ee72121ed4a8abfc06a576be524ce7a86b78e9af917b507fbe95411efef11a563da95295c4
7
+ data.tar.gz: 68b7cec95107a831286fc3ff36971cd9cc0efbc29157bc0df95a16238b5594214ffca0d417f2dd9011f9e26bf4e163e01e179cbf06f8c053df68c4d60f2416cc
data/CHANGES.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changes
2
2
 
3
+ ## 2020-12-22 (2.5.1)
4
+
5
+ * Restore the compatibility for constants of JSON class.
6
+
7
+ ## 2020-12-22 (2.5.0)
8
+
9
+ * Ready to Ractor-safe at Ruby 3.0.
10
+
11
+ ## 2020-12-17 (2.4.1)
12
+
13
+ * Restore version.rb with 2.4.1
14
+
15
+ ## 2020-12-15 (2.4.0)
16
+
17
+ * Implement a freeze: parser option #447
18
+ * Fix an issue with generate_pretty and empty objects in the Ruby and Java implementations #449
19
+ * Fix JSON.load_file doc #448
20
+ * Fix pure parser with unclosed arrays / objects #425
21
+ * bundle the LICENSE file in the gem #444
22
+ * Add an option to escape forward slash character #405
23
+ * RDoc for JSON #439 #446 #442 #434 #433 #430
24
+
3
25
  ## 2020-06-30 (2.3.1)
4
26
 
5
27
  * Spelling and grammar fixes for comments. Pull request #191 by Josh
data/LICENSE ADDED
@@ -0,0 +1,56 @@
1
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
2
+ You can redistribute it and/or modify it under either the terms of the
3
+ 2-clause BSDL (see the file BSDL), or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a) place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b) use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c) give non-standard binaries non-standard names, with
21
+ instructions on where to get the original software distribution.
22
+
23
+ d) make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or binary form,
26
+ provided that you do at least ONE of the following:
27
+
28
+ a) distribute the binaries and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b) accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c) give non-standard binaries non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d) make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under these terms.
43
+
44
+ For the list of those files and their copying conditions, see the
45
+ file LEGAL.
46
+
47
+ 5. The scripts and library files supplied as input to or produced as
48
+ output from the software do not automatically fall under the
49
+ copyright of the software, but belong to whomever generated them,
50
+ and may be sold commercially, and may be aggregated with this
51
+ software.
52
+
53
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
54
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
55
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56
+ PURPOSE.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.3.1
1
+ 2.5.1
@@ -15,14 +15,13 @@ static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
15
15
  #endif
16
16
  mFloat, mString, mString_Extend,
17
17
  mTrueClass, mFalseClass, mNilClass, eGeneratorError,
18
- eNestingError,
19
- i_SAFE_STATE_PROTOTYPE;
18
+ eNestingError;
20
19
 
21
20
  static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
22
21
  i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
23
22
  i_pack, i_unpack, i_create_id, i_extend, i_key_p,
24
23
  i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
25
- i_buffer_initial_length, i_dup;
24
+ i_buffer_initial_length, i_dup, i_escape_slash;
26
25
 
27
26
  /*
28
27
  * Copyright 2001-2004 Unicode, Inc.
@@ -130,7 +129,7 @@ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
130
129
 
131
130
  /* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
132
131
  * and control characters are JSON escaped. */
133
- static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
132
+ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash)
134
133
  {
135
134
  const UTF8 *source = (UTF8 *) RSTRING_PTR(string);
136
135
  const UTF8 *sourceEnd = source + RSTRING_LEN(string);
@@ -180,6 +179,11 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
180
179
  case '"':
181
180
  fbuffer_append(buffer, "\\\"", 2);
182
181
  break;
182
+ case '/':
183
+ if(escape_slash) {
184
+ fbuffer_append(buffer, "\\/", 2);
185
+ break;
186
+ }
183
187
  default:
184
188
  fbuffer_append_char(buffer, (char)ch);
185
189
  break;
@@ -229,7 +233,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
229
233
  * characters required by the JSON standard are JSON escaped. The remaining
230
234
  * characters (should be UTF8) are just passed through and appended to the
231
235
  * result. */
232
- static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
236
+ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash)
233
237
  {
234
238
  const char *ptr = RSTRING_PTR(string), *p;
235
239
  unsigned long len = RSTRING_LEN(string), start = 0, end = 0;
@@ -280,6 +284,12 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
280
284
  escape = "\\\"";
281
285
  escape_len = 2;
282
286
  break;
287
+ case '/':
288
+ if(escape_slash) {
289
+ escape = "\\/";
290
+ escape_len = 2;
291
+ break;
292
+ }
283
293
  default:
284
294
  {
285
295
  unsigned short clen = 1;
@@ -609,13 +619,18 @@ static size_t State_memsize(const void *ptr)
609
619
  return size;
610
620
  }
611
621
 
622
+ #ifndef HAVE_RB_EXT_RACTOR_SAFE
623
+ # undef RUBY_TYPED_FROZEN_SHAREABLE
624
+ # define RUBY_TYPED_FROZEN_SHAREABLE 0
625
+ #endif
626
+
612
627
  #ifdef NEW_TYPEDDATA_WRAPPER
613
628
  static const rb_data_type_t JSON_Generator_State_type = {
614
629
  "JSON/Generator/State",
615
630
  {NULL, State_free, State_memsize,},
616
631
  #ifdef RUBY_TYPED_FREE_IMMEDIATELY
617
632
  0, 0,
618
- RUBY_TYPED_FREE_IMMEDIATELY,
633
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
619
634
  #endif
620
635
  };
621
636
  #endif
@@ -716,6 +731,8 @@ static VALUE cState_configure(VALUE self, VALUE opts)
716
731
  state->allow_nan = RTEST(tmp);
717
732
  tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
718
733
  state->ascii_only = RTEST(tmp);
734
+ tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
735
+ state->escape_slash = RTEST(tmp);
719
736
  return self;
720
737
  }
721
738
 
@@ -750,6 +767,7 @@ static VALUE cState_to_h(VALUE self)
750
767
  rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
751
768
  rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
752
769
  rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
770
+ rb_hash_aset(result, ID2SYM(i_escape_slash), state->escape_slash ? Qtrue : Qfalse);
753
771
  rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
754
772
  rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
755
773
  return result;
@@ -934,9 +952,9 @@ static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
934
952
  }
935
953
  #endif
936
954
  if (state->ascii_only) {
937
- convert_UTF8_to_JSON_ASCII(buffer, obj);
955
+ convert_UTF8_to_JSON_ASCII(buffer, obj, state->escape_slash);
938
956
  } else {
939
- convert_UTF8_to_JSON(buffer, obj);
957
+ convert_UTF8_to_JSON(buffer, obj, state->escape_slash);
940
958
  }
941
959
  fbuffer_append_char(buffer, '"');
942
960
  }
@@ -1152,8 +1170,7 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
1152
1170
  } else if (rb_obj_is_kind_of(opts, rb_cHash)) {
1153
1171
  return rb_funcall(self, i_new, 1, opts);
1154
1172
  } else {
1155
- VALUE prototype = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
1156
- return rb_funcall(prototype, i_dup, 0);
1173
+ return rb_class_new_instance(0, NULL, cState);
1157
1174
  }
1158
1175
  }
1159
1176
 
@@ -1377,6 +1394,31 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
1377
1394
  return state->max_nesting = FIX2LONG(depth);
1378
1395
  }
1379
1396
 
1397
+ /*
1398
+ * call-seq: escape_slash
1399
+ *
1400
+ * If this boolean is true, the forward slashes will be escaped in
1401
+ * the json output.
1402
+ */
1403
+ static VALUE cState_escape_slash(VALUE self)
1404
+ {
1405
+ GET_STATE(self);
1406
+ return state->escape_slash ? Qtrue : Qfalse;
1407
+ }
1408
+
1409
+ /*
1410
+ * call-seq: escape_slash=(depth)
1411
+ *
1412
+ * This sets whether or not the forward slashes will be escaped in
1413
+ * the json output.
1414
+ */
1415
+ static VALUE cState_escape_slash_set(VALUE self, VALUE enable)
1416
+ {
1417
+ GET_STATE(self);
1418
+ state->escape_slash = RTEST(enable);
1419
+ return Qnil;
1420
+ }
1421
+
1380
1422
  /*
1381
1423
  * call-seq: allow_nan?
1382
1424
  *
@@ -1460,6 +1502,10 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
1460
1502
  */
1461
1503
  void Init_generator(void)
1462
1504
  {
1505
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
1506
+ rb_ext_ractor_safe(true);
1507
+ #endif
1508
+
1463
1509
  #undef rb_intern
1464
1510
  rb_require("json/common");
1465
1511
 
@@ -1489,6 +1535,9 @@ void Init_generator(void)
1489
1535
  rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
1490
1536
  rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
1491
1537
  rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
1538
+ rb_define_method(cState, "escape_slash", cState_escape_slash, 0);
1539
+ rb_define_method(cState, "escape_slash?", cState_escape_slash, 0);
1540
+ rb_define_method(cState, "escape_slash=", cState_escape_slash_set, 1);
1492
1541
  rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
1493
1542
  rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
1494
1543
  rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
@@ -1545,6 +1594,7 @@ void Init_generator(void)
1545
1594
  i_object_nl = rb_intern("object_nl");
1546
1595
  i_array_nl = rb_intern("array_nl");
1547
1596
  i_max_nesting = rb_intern("max_nesting");
1597
+ i_escape_slash = rb_intern("escape_slash");
1548
1598
  i_allow_nan = rb_intern("allow_nan");
1549
1599
  i_ascii_only = rb_intern("ascii_only");
1550
1600
  i_depth = rb_intern("depth");
@@ -1565,5 +1615,4 @@ void Init_generator(void)
1565
1615
  i_encoding = rb_intern("encoding");
1566
1616
  i_encode = rb_intern("encode");
1567
1617
  #endif
1568
- i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
1569
1618
  }
@@ -49,8 +49,8 @@ static const UTF32 halfMask = 0x3FFUL;
49
49
  static unsigned char isLegalUTF8(const UTF8 *source, unsigned long length);
50
50
  static void unicode_escape(char *buf, UTF16 character);
51
51
  static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16 character);
52
- static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string);
53
- static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string);
52
+ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash);
53
+ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash);
54
54
  static char *fstrndup(const char *ptr, unsigned long len);
55
55
 
56
56
  /* ruby api and some helpers */
@@ -72,6 +72,7 @@ typedef struct JSON_Generator_StateStruct {
72
72
  long max_nesting;
73
73
  char allow_nan;
74
74
  char ascii_only;
75
+ char escape_slash;
75
76
  long depth;
76
77
  long buffer_initial_length;
77
78
  } JSON_Generator_State;
@@ -150,6 +151,8 @@ static VALUE cState_allow_nan_p(VALUE self);
150
151
  static VALUE cState_ascii_only_p(VALUE self);
151
152
  static VALUE cState_depth(VALUE self);
152
153
  static VALUE cState_depth_set(VALUE self, VALUE depth);
154
+ static VALUE cState_escape_slash(VALUE self);
155
+ static VALUE cState_escape_slash_set(VALUE self, VALUE depth);
153
156
  static FBuffer *cState_prepare_buffer(VALUE self);
154
157
  #ifndef ZALLOC
155
158
  #define ZALLOC(type) ((type *)ruby_zalloc(sizeof(type)))
@@ -3,4 +3,29 @@ require 'mkmf'
3
3
 
4
4
  have_func("rb_enc_raise", "ruby.h")
5
5
 
6
+ # checking if String#-@ (str_uminus) dedupes... '
7
+ begin
8
+ a = -(%w(t e s t).join)
9
+ b = -(%w(t e s t).join)
10
+ if a.equal?(b)
11
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=1 '
12
+ else
13
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=0 '
14
+ end
15
+ rescue NoMethodError
16
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=0 '
17
+ end
18
+
19
+ # checking if String#-@ (str_uminus) directly interns frozen strings... '
20
+ begin
21
+ s = rand.to_s.freeze
22
+ if (-s).equal?(s) && (-s.dup).equal?(s)
23
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=1 '
24
+ else
25
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
26
+ end
27
+ rescue NoMethodError
28
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
29
+ end
30
+
6
31
  create_makefile 'json/ext/parser'
@@ -91,13 +91,12 @@ static int convert_UTF32_to_UTF8(char *buf, UTF32 ch)
91
91
 
92
92
  static VALUE mJSON, mExt, cParser, eParserError, eNestingError;
93
93
  static VALUE CNaN, CInfinity, CMinusInfinity;
94
- static VALUE cBigDecimal = Qundef;
95
94
 
96
95
  static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
97
96
  i_chr, i_max_nesting, i_allow_nan, i_symbolize_names,
98
97
  i_object_class, i_array_class, i_decimal_class, i_key_p,
99
98
  i_deep_const_get, i_match, i_match_string, i_aset, i_aref,
100
- i_leftshift, i_new, i_BigDecimal;
99
+ i_leftshift, i_new, i_try_convert, i_freeze, i_uminus;
101
100
 
102
101
 
103
102
  #line 126 "parser.rl"
@@ -869,6 +868,10 @@ case 28:
869
868
 
870
869
  #line 292 "parser.rl"
871
870
 
871
+ if (json->freeze) {
872
+ OBJ_FREEZE(*result);
873
+ }
874
+
872
875
  if (cs >= JSON_value_first_final) {
873
876
  return p;
874
877
  } else {
@@ -877,7 +880,7 @@ case 28:
877
880
  }
878
881
 
879
882
 
880
- #line 881 "parser.c"
883
+ #line 885 "parser.c"
881
884
  enum {JSON_integer_start = 1};
882
885
  enum {JSON_integer_first_final = 3};
883
886
  enum {JSON_integer_error = 0};
@@ -885,7 +888,7 @@ enum {JSON_integer_error = 0};
885
888
  enum {JSON_integer_en_main = 1};
886
889
 
887
890
 
888
- #line 308 "parser.rl"
891
+ #line 312 "parser.rl"
889
892
 
890
893
 
891
894
  static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result)
@@ -893,15 +896,15 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res
893
896
  int cs = EVIL;
894
897
 
895
898
 
896
- #line 897 "parser.c"
899
+ #line 901 "parser.c"
897
900
  {
898
901
  cs = JSON_integer_start;
899
902
  }
900
903
 
901
- #line 315 "parser.rl"
904
+ #line 319 "parser.rl"
902
905
  json->memo = p;
903
906
 
904
- #line 905 "parser.c"
907
+ #line 909 "parser.c"
905
908
  {
906
909
  if ( p == pe )
907
910
  goto _test_eof;
@@ -935,14 +938,14 @@ case 3:
935
938
  goto st0;
936
939
  goto tr4;
937
940
  tr4:
938
- #line 305 "parser.rl"
941
+ #line 309 "parser.rl"
939
942
  { p--; {p++; cs = 4; goto _out;} }
940
943
  goto st4;
941
944
  st4:
942
945
  if ( ++p == pe )
943
946
  goto _test_eof4;
944
947
  case 4:
945
- #line 946 "parser.c"
948
+ #line 950 "parser.c"
946
949
  goto st0;
947
950
  st5:
948
951
  if ( ++p == pe )
@@ -961,7 +964,7 @@ case 5:
961
964
  _out: {}
962
965
  }
963
966
 
964
- #line 317 "parser.rl"
967
+ #line 321 "parser.rl"
965
968
 
966
969
  if (cs >= JSON_integer_first_final) {
967
970
  long len = p - json->memo;
@@ -976,7 +979,7 @@ case 5:
976
979
  }
977
980
 
978
981
 
979
- #line 980 "parser.c"
982
+ #line 984 "parser.c"
980
983
  enum {JSON_float_start = 1};
981
984
  enum {JSON_float_first_final = 8};
982
985
  enum {JSON_float_error = 0};
@@ -984,36 +987,23 @@ enum {JSON_float_error = 0};
984
987
  enum {JSON_float_en_main = 1};
985
988
 
986
989
 
987
- #line 342 "parser.rl"
988
-
990
+ #line 346 "parser.rl"
989
991
 
990
- static int is_bigdecimal_class(VALUE obj)
991
- {
992
- if (cBigDecimal == Qundef) {
993
- if (rb_const_defined(rb_cObject, i_BigDecimal)) {
994
- cBigDecimal = rb_const_get_at(rb_cObject, i_BigDecimal);
995
- }
996
- else {
997
- return 0;
998
- }
999
- }
1000
- return obj == cBigDecimal;
1001
- }
1002
992
 
1003
993
  static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result)
1004
994
  {
1005
995
  int cs = EVIL;
1006
996
 
1007
997
 
1008
- #line 1009 "parser.c"
998
+ #line 1013 "parser.c"
1009
999
  {
1010
1000
  cs = JSON_float_start;
1011
1001
  }
1012
1002
 
1013
- #line 362 "parser.rl"
1003
+ #line 366 "parser.rl"
1014
1004
  json->memo = p;
1015
1005
 
1016
- #line 1017 "parser.c"
1006
+ #line 1021 "parser.c"
1017
1007
  {
1018
1008
  if ( p == pe )
1019
1009
  goto _test_eof;
@@ -1071,14 +1061,14 @@ case 8:
1071
1061
  goto st0;
1072
1062
  goto tr9;
1073
1063
  tr9:
1074
- #line 336 "parser.rl"
1064
+ #line 340 "parser.rl"
1075
1065
  { p--; {p++; cs = 9; goto _out;} }
1076
1066
  goto st9;
1077
1067
  st9:
1078
1068
  if ( ++p == pe )
1079
1069
  goto _test_eof9;
1080
1070
  case 9:
1081
- #line 1082 "parser.c"
1071
+ #line 1086 "parser.c"
1082
1072
  goto st0;
1083
1073
  st5:
1084
1074
  if ( ++p == pe )
@@ -1139,24 +1129,49 @@ case 7:
1139
1129
  _out: {}
1140
1130
  }
1141
1131
 
1142
- #line 364 "parser.rl"
1132
+ #line 368 "parser.rl"
1143
1133
 
1144
1134
  if (cs >= JSON_float_first_final) {
1135
+ VALUE mod = Qnil;
1136
+ ID method_id = 0;
1137
+ if (rb_respond_to(json->decimal_class, i_try_convert)) {
1138
+ mod = json->decimal_class;
1139
+ method_id = i_try_convert;
1140
+ } else if (rb_respond_to(json->decimal_class, i_new)) {
1141
+ mod = json->decimal_class;
1142
+ method_id = i_new;
1143
+ } else if (RB_TYPE_P(json->decimal_class, T_CLASS)) {
1144
+ VALUE name = rb_class_name(json->decimal_class);
1145
+ const char *name_cstr = RSTRING_PTR(name);
1146
+ const char *last_colon = strrchr(name_cstr, ':');
1147
+ if (last_colon) {
1148
+ const char *mod_path_end = last_colon - 1;
1149
+ VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
1150
+ mod = rb_path_to_class(mod_path);
1151
+
1152
+ const char *method_name_beg = last_colon + 1;
1153
+ long before_len = method_name_beg - name_cstr;
1154
+ long len = RSTRING_LEN(name) - before_len;
1155
+ VALUE method_name = rb_str_substr(name, before_len, len);
1156
+ method_id = SYM2ID(rb_str_intern(method_name));
1157
+ } else {
1158
+ mod = rb_mKernel;
1159
+ method_id = SYM2ID(rb_str_intern(name));
1160
+ }
1161
+ }
1162
+
1145
1163
  long len = p - json->memo;
1146
1164
  fbuffer_clear(json->fbuffer);
1147
1165
  fbuffer_append(json->fbuffer, json->memo, len);
1148
1166
  fbuffer_append_char(json->fbuffer, '\0');
1149
- if (NIL_P(json->decimal_class)) {
1150
- *result = rb_float_new(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
1167
+
1168
+ if (method_id) {
1169
+ VALUE text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
1170
+ *result = rb_funcallv(mod, method_id, 1, &text);
1151
1171
  } else {
1152
- VALUE text;
1153
- text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
1154
- if (is_bigdecimal_class(json->decimal_class)) {
1155
- *result = rb_funcall(Qnil, i_BigDecimal, 1, text);
1156
- } else {
1157
- *result = rb_funcall(json->decimal_class, i_new, 1, text);
1158
- }
1172
+ *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
1159
1173
  }
1174
+
1160
1175
  return p + 1;
1161
1176
  } else {
1162
1177
  return NULL;
@@ -1165,7 +1180,7 @@ case 7:
1165
1180
 
1166
1181
 
1167
1182
 
1168
- #line 1169 "parser.c"
1183
+ #line 1173 "parser.c"
1169
1184
  enum {JSON_array_start = 1};
1170
1185
  enum {JSON_array_first_final = 17};
1171
1186
  enum {JSON_array_error = 0};
@@ -1173,7 +1188,7 @@ enum {JSON_array_error = 0};
1173
1188
  enum {JSON_array_en_main = 1};
1174
1189
 
1175
1190
 
1176
- #line 417 "parser.rl"
1191
+ #line 421 "parser.rl"
1177
1192
 
1178
1193
 
1179
1194
  static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
@@ -1187,14 +1202,14 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul
1187
1202
  *result = NIL_P(array_class) ? rb_ary_new() : rb_class_new_instance(0, 0, array_class);
1188
1203
 
1189
1204
 
1190
- #line 1191 "parser.c"
1205
+ #line 1195 "parser.c"
1191
1206
  {
1192
1207
  cs = JSON_array_start;
1193
1208
  }
1194
1209
 
1195
- #line 430 "parser.rl"
1210
+ #line 434 "parser.rl"
1196
1211
 
1197
- #line 1198 "parser.c"
1212
+ #line 1202 "parser.c"
1198
1213
  {
1199
1214
  if ( p == pe )
1200
1215
  goto _test_eof;
@@ -1233,7 +1248,7 @@ case 2:
1233
1248
  goto st2;
1234
1249
  goto st0;
1235
1250
  tr2:
1236
- #line 394 "parser.rl"
1251
+ #line 398 "parser.rl"
1237
1252
  {
1238
1253
  VALUE v = Qnil;
1239
1254
  char *np = JSON_parse_value(json, p, pe, &v, current_nesting);
@@ -1253,7 +1268,7 @@ st3:
1253
1268
  if ( ++p == pe )
1254
1269
  goto _test_eof3;
1255
1270
  case 3:
1256
- #line 1257 "parser.c"
1271
+ #line 1261 "parser.c"
1257
1272
  switch( (*p) ) {
1258
1273
  case 13: goto st3;
1259
1274
  case 32: goto st3;
@@ -1353,14 +1368,14 @@ case 12:
1353
1368
  goto st3;
1354
1369
  goto st12;
1355
1370
  tr4:
1356
- #line 409 "parser.rl"
1371
+ #line 413 "parser.rl"
1357
1372
  { p--; {p++; cs = 17; goto _out;} }
1358
1373
  goto st17;
1359
1374
  st17:
1360
1375
  if ( ++p == pe )
1361
1376
  goto _test_eof17;
1362
1377
  case 17:
1363
- #line 1364 "parser.c"
1378
+ #line 1368 "parser.c"
1364
1379
  goto st0;
1365
1380
  st13:
1366
1381
  if ( ++p == pe )
@@ -1416,7 +1431,7 @@ case 16:
1416
1431
  _out: {}
1417
1432
  }
1418
1433
 
1419
- #line 431 "parser.rl"
1434
+ #line 435 "parser.rl"
1420
1435
 
1421
1436
  if(cs >= JSON_array_first_final) {
1422
1437
  return p + 1;
@@ -1505,7 +1520,7 @@ static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)
1505
1520
  }
1506
1521
 
1507
1522
 
1508
- #line 1509 "parser.c"
1523
+ #line 1513 "parser.c"
1509
1524
  enum {JSON_string_start = 1};
1510
1525
  enum {JSON_string_first_final = 8};
1511
1526
  enum {JSON_string_error = 0};
@@ -1513,7 +1528,7 @@ enum {JSON_string_error = 0};
1513
1528
  enum {JSON_string_en_main = 1};
1514
1529
 
1515
1530
 
1516
- #line 538 "parser.rl"
1531
+ #line 542 "parser.rl"
1517
1532
 
1518
1533
 
1519
1534
  static int
@@ -1535,15 +1550,15 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
1535
1550
 
1536
1551
  *result = rb_str_buf_new(0);
1537
1552
 
1538
- #line 1539 "parser.c"
1553
+ #line 1543 "parser.c"
1539
1554
  {
1540
1555
  cs = JSON_string_start;
1541
1556
  }
1542
1557
 
1543
- #line 559 "parser.rl"
1558
+ #line 563 "parser.rl"
1544
1559
  json->memo = p;
1545
1560
 
1546
- #line 1547 "parser.c"
1561
+ #line 1551 "parser.c"
1547
1562
  {
1548
1563
  if ( p == pe )
1549
1564
  goto _test_eof;
@@ -1568,7 +1583,7 @@ case 2:
1568
1583
  goto st0;
1569
1584
  goto st2;
1570
1585
  tr2:
1571
- #line 524 "parser.rl"
1586
+ #line 528 "parser.rl"
1572
1587
  {
1573
1588
  *result = json_string_unescape(*result, json->memo + 1, p);
1574
1589
  if (NIL_P(*result)) {
@@ -1579,14 +1594,14 @@ tr2:
1579
1594
  {p = (( p + 1))-1;}
1580
1595
  }
1581
1596
  }
1582
- #line 535 "parser.rl"
1597
+ #line 539 "parser.rl"
1583
1598
  { p--; {p++; cs = 8; goto _out;} }
1584
1599
  goto st8;
1585
1600
  st8:
1586
1601
  if ( ++p == pe )
1587
1602
  goto _test_eof8;
1588
1603
  case 8:
1589
- #line 1590 "parser.c"
1604
+ #line 1594 "parser.c"
1590
1605
  goto st0;
1591
1606
  st3:
1592
1607
  if ( ++p == pe )
@@ -1662,7 +1677,7 @@ case 7:
1662
1677
  _out: {}
1663
1678
  }
1664
1679
 
1665
- #line 561 "parser.rl"
1680
+ #line 565 "parser.rl"
1666
1681
 
1667
1682
  if (json->create_additions && RTEST(match_string = json->match_string)) {
1668
1683
  VALUE klass;
@@ -1678,7 +1693,22 @@ case 7:
1678
1693
  if (json->symbolize_names && json->parsing_name) {
1679
1694
  *result = rb_str_intern(*result);
1680
1695
  } else if (RB_TYPE_P(*result, T_STRING)) {
1696
+ # if STR_UMINUS_DEDUPE_FROZEN
1697
+ if (json->freeze) {
1698
+ // Starting from MRI 2.8 it is preferable to freeze the string
1699
+ // before deduplication so that it can be interned directly
1700
+ // otherwise it would be duplicated first which is wasteful.
1701
+ *result = rb_funcall(rb_str_freeze(*result), i_uminus, 0);
1702
+ }
1703
+ # elif STR_UMINUS_DEDUPE
1704
+ if (json->freeze) {
1705
+ // MRI 2.5 and older do not deduplicate strings that are already
1706
+ // frozen.
1707
+ *result = rb_funcall(*result, i_uminus, 0);
1708
+ }
1709
+ # else
1681
1710
  rb_str_resize(*result, RSTRING_LEN(*result));
1711
+ # endif
1682
1712
  }
1683
1713
  if (cs >= JSON_string_first_final) {
1684
1714
  return p + 1;
@@ -1786,6 +1816,12 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
1786
1816
  } else {
1787
1817
  json->symbolize_names = 0;
1788
1818
  }
1819
+ tmp = ID2SYM(i_freeze);
1820
+ if (option_given_p(opts, tmp)) {
1821
+ json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
1822
+ } else {
1823
+ json->freeze = 0;
1824
+ }
1789
1825
  tmp = ID2SYM(i_create_additions);
1790
1826
  if (option_given_p(opts, tmp)) {
1791
1827
  json->create_additions = RTEST(rb_hash_aref(opts, tmp));
@@ -1849,7 +1885,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
1849
1885
  }
1850
1886
 
1851
1887
 
1852
- #line 1853 "parser.c"
1888
+ #line 1878 "parser.c"
1853
1889
  enum {JSON_start = 1};
1854
1890
  enum {JSON_first_final = 10};
1855
1891
  enum {JSON_error = 0};
@@ -1857,7 +1893,7 @@ enum {JSON_error = 0};
1857
1893
  enum {JSON_en_main = 1};
1858
1894
 
1859
1895
 
1860
- #line 761 "parser.rl"
1896
+ #line 786 "parser.rl"
1861
1897
 
1862
1898
 
1863
1899
  /*
@@ -1874,16 +1910,16 @@ static VALUE cParser_parse(VALUE self)
1874
1910
  GET_PARSER;
1875
1911
 
1876
1912
 
1877
- #line 1878 "parser.c"
1913
+ #line 1903 "parser.c"
1878
1914
  {
1879
1915
  cs = JSON_start;
1880
1916
  }
1881
1917
 
1882
- #line 777 "parser.rl"
1918
+ #line 802 "parser.rl"
1883
1919
  p = json->source;
1884
1920
  pe = p + json->len;
1885
1921
 
1886
- #line 1887 "parser.c"
1922
+ #line 1912 "parser.c"
1887
1923
  {
1888
1924
  if ( p == pe )
1889
1925
  goto _test_eof;
@@ -1917,7 +1953,7 @@ st0:
1917
1953
  cs = 0;
1918
1954
  goto _out;
1919
1955
  tr2:
1920
- #line 753 "parser.rl"
1956
+ #line 778 "parser.rl"
1921
1957
  {
1922
1958
  char *np = JSON_parse_value(json, p, pe, &result, 0);
1923
1959
  if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;}
@@ -1927,7 +1963,7 @@ st10:
1927
1963
  if ( ++p == pe )
1928
1964
  goto _test_eof10;
1929
1965
  case 10:
1930
- #line 1931 "parser.c"
1966
+ #line 1956 "parser.c"
1931
1967
  switch( (*p) ) {
1932
1968
  case 13: goto st10;
1933
1969
  case 32: goto st10;
@@ -2016,7 +2052,7 @@ case 9:
2016
2052
  _out: {}
2017
2053
  }
2018
2054
 
2019
- #line 780 "parser.rl"
2055
+ #line 805 "parser.rl"
2020
2056
 
2021
2057
  if (cs >= JSON_first_final && p == pe) {
2022
2058
  return result;
@@ -2083,6 +2119,10 @@ static VALUE cParser_source(VALUE self)
2083
2119
 
2084
2120
  void Init_parser(void)
2085
2121
  {
2122
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
2123
+ rb_ext_ractor_safe(true);
2124
+ #endif
2125
+
2086
2126
  #undef rb_intern
2087
2127
  rb_require("json/common");
2088
2128
  mJSON = rb_define_module("JSON");
@@ -2125,7 +2165,9 @@ void Init_parser(void)
2125
2165
  i_aref = rb_intern("[]");
2126
2166
  i_leftshift = rb_intern("<<");
2127
2167
  i_new = rb_intern("new");
2128
- i_BigDecimal = rb_intern("BigDecimal");
2168
+ i_try_convert = rb_intern("try_convert");
2169
+ i_freeze = rb_intern("freeze");
2170
+ i_uminus = rb_intern("-@");
2129
2171
  }
2130
2172
 
2131
2173
  /*