json 2.3.1 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
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
  /*