json 2.3.1 → 2.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 80444509bc162d6df8e9cc3e7af2fc28507c06aef49cbfc1dd9e5990af42b14f
4
- data.tar.gz: 8541be9708b44604eeeecac22f89c47933d32c90606f23c1d37e70c8b2d3e9db
3
+ metadata.gz: 4b5241427373f8f03f7faa96afdec132dcb7601f2e9cce4903ce0879c208bc3f
4
+ data.tar.gz: 7e3e820aae7a8036affec28ce44f4aadeebfd74b4bea85ad2d597eb42e82b745
5
5
  SHA512:
6
- metadata.gz: 1df7b5ee2bf58103f0b5776c4a581aa3b013ad4b3a85a442d37bb72dc62aaf04dc42ed1080fb307fec1d1e9128c9f21e43827c7f15494cb0f9f310f7189bdc5e
7
- data.tar.gz: 15ba56ce5d0e04c5326feb9e9faf2627628a715fa4bbeaec5c4aadeab5f27a65135f4f24f142b361f62ca37bbf36380f671d7ae35d46991737e4fc62423a6f9b
6
+ metadata.gz: e0f403e2c458aa86f820671726a92f4798703240099417a22e5d489d140f53d48559560d6603547f2a0f07aa0595fb383c4b1b2c53e1df1b34e16df2ca4ea480
7
+ data.tar.gz: 5e0f19fe6c8c086adbe499b85bb49c1b5f14697cb63ed8d7fd96d82e8504806eb0b016f8e2a556ec7eab5443beddc8109d2ef5921bd3ac54eedf45056218924b
@@ -4,7 +4,6 @@ language: ruby
4
4
 
5
5
  # Specify which ruby versions you wish to run your tests on, each version will be used
6
6
  rvm:
7
- - 2.0.0
8
7
  - 2.1
9
8
  - 2.2
10
9
  - 2.3
@@ -13,14 +12,12 @@ rvm:
13
12
  - 2.6
14
13
  - 2.7.0-preview3
15
14
  - ruby-head
16
- - jruby
17
- - jruby-9.2.7.0
15
+ - jruby-9.1 # Ruby 2.3
16
+ - jruby-9.2 # Ruby 2.5
18
17
  - truffleruby
19
18
  matrix:
20
19
  allow_failures:
21
20
  - rvm: ruby-head
22
- - rvm: jruby
23
- - rvm: jruby-9.2.7.0
24
21
  - rvm: truffleruby
25
22
  script: "bundle exec rake"
26
23
  sudo: false
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.4.0
@@ -22,7 +22,7 @@ static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
22
22
  i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
23
23
  i_pack, i_unpack, i_create_id, i_extend, i_key_p,
24
24
  i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
25
- i_buffer_initial_length, i_dup;
25
+ i_buffer_initial_length, i_dup, i_escape_slash;
26
26
 
27
27
  /*
28
28
  * Copyright 2001-2004 Unicode, Inc.
@@ -130,7 +130,7 @@ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
130
130
 
131
131
  /* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
132
132
  * and control characters are JSON escaped. */
133
- static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
133
+ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash)
134
134
  {
135
135
  const UTF8 *source = (UTF8 *) RSTRING_PTR(string);
136
136
  const UTF8 *sourceEnd = source + RSTRING_LEN(string);
@@ -180,6 +180,11 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
180
180
  case '"':
181
181
  fbuffer_append(buffer, "\\\"", 2);
182
182
  break;
183
+ case '/':
184
+ if(escape_slash) {
185
+ fbuffer_append(buffer, "\\/", 2);
186
+ break;
187
+ }
183
188
  default:
184
189
  fbuffer_append_char(buffer, (char)ch);
185
190
  break;
@@ -229,7 +234,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
229
234
  * characters required by the JSON standard are JSON escaped. The remaining
230
235
  * characters (should be UTF8) are just passed through and appended to the
231
236
  * result. */
232
- static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
237
+ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash)
233
238
  {
234
239
  const char *ptr = RSTRING_PTR(string), *p;
235
240
  unsigned long len = RSTRING_LEN(string), start = 0, end = 0;
@@ -280,6 +285,12 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
280
285
  escape = "\\\"";
281
286
  escape_len = 2;
282
287
  break;
288
+ case '/':
289
+ if(escape_slash) {
290
+ escape = "\\/";
291
+ escape_len = 2;
292
+ break;
293
+ }
283
294
  default:
284
295
  {
285
296
  unsigned short clen = 1;
@@ -716,6 +727,8 @@ static VALUE cState_configure(VALUE self, VALUE opts)
716
727
  state->allow_nan = RTEST(tmp);
717
728
  tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
718
729
  state->ascii_only = RTEST(tmp);
730
+ tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
731
+ state->escape_slash = RTEST(tmp);
719
732
  return self;
720
733
  }
721
734
 
@@ -750,6 +763,7 @@ static VALUE cState_to_h(VALUE self)
750
763
  rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
751
764
  rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
752
765
  rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
766
+ rb_hash_aset(result, ID2SYM(i_escape_slash), state->escape_slash ? Qtrue : Qfalse);
753
767
  rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
754
768
  rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
755
769
  return result;
@@ -934,9 +948,9 @@ static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
934
948
  }
935
949
  #endif
936
950
  if (state->ascii_only) {
937
- convert_UTF8_to_JSON_ASCII(buffer, obj);
951
+ convert_UTF8_to_JSON_ASCII(buffer, obj, state->escape_slash);
938
952
  } else {
939
- convert_UTF8_to_JSON(buffer, obj);
953
+ convert_UTF8_to_JSON(buffer, obj, state->escape_slash);
940
954
  }
941
955
  fbuffer_append_char(buffer, '"');
942
956
  }
@@ -1377,6 +1391,31 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
1377
1391
  return state->max_nesting = FIX2LONG(depth);
1378
1392
  }
1379
1393
 
1394
+ /*
1395
+ * call-seq: escape_slash
1396
+ *
1397
+ * If this boolean is true, the forward slashes will be escaped in
1398
+ * the json output.
1399
+ */
1400
+ static VALUE cState_escape_slash(VALUE self)
1401
+ {
1402
+ GET_STATE(self);
1403
+ return state->escape_slash ? Qtrue : Qfalse;
1404
+ }
1405
+
1406
+ /*
1407
+ * call-seq: escape_slash=(depth)
1408
+ *
1409
+ * This sets whether or not the forward slashes will be escaped in
1410
+ * the json output.
1411
+ */
1412
+ static VALUE cState_escape_slash_set(VALUE self, VALUE enable)
1413
+ {
1414
+ GET_STATE(self);
1415
+ state->escape_slash = RTEST(enable);
1416
+ return Qnil;
1417
+ }
1418
+
1380
1419
  /*
1381
1420
  * call-seq: allow_nan?
1382
1421
  *
@@ -1489,6 +1528,9 @@ void Init_generator(void)
1489
1528
  rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
1490
1529
  rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
1491
1530
  rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
1531
+ rb_define_method(cState, "escape_slash", cState_escape_slash, 0);
1532
+ rb_define_method(cState, "escape_slash?", cState_escape_slash, 0);
1533
+ rb_define_method(cState, "escape_slash=", cState_escape_slash_set, 1);
1492
1534
  rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
1493
1535
  rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
1494
1536
  rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
@@ -1545,6 +1587,7 @@ void Init_generator(void)
1545
1587
  i_object_nl = rb_intern("object_nl");
1546
1588
  i_array_nl = rb_intern("array_nl");
1547
1589
  i_max_nesting = rb_intern("max_nesting");
1590
+ i_escape_slash = rb_intern("escape_slash");
1548
1591
  i_allow_nan = rb_intern("allow_nan");
1549
1592
  i_ascii_only = rb_intern("ascii_only");
1550
1593
  i_depth = rb_intern("depth");
@@ -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'
@@ -97,7 +97,7 @@ static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
97
97
  i_chr, i_max_nesting, i_allow_nan, i_symbolize_names,
98
98
  i_object_class, i_array_class, i_decimal_class, i_key_p,
99
99
  i_deep_const_get, i_match, i_match_string, i_aset, i_aref,
100
- i_leftshift, i_new, i_BigDecimal;
100
+ i_leftshift, i_new, i_BigDecimal, i_freeze, i_uminus;
101
101
 
102
102
 
103
103
  #line 126 "parser.rl"
@@ -869,6 +869,10 @@ case 28:
869
869
 
870
870
  #line 292 "parser.rl"
871
871
 
872
+ if (json->freeze) {
873
+ OBJ_FREEZE(*result);
874
+ }
875
+
872
876
  if (cs >= JSON_value_first_final) {
873
877
  return p;
874
878
  } else {
@@ -877,7 +881,7 @@ case 28:
877
881
  }
878
882
 
879
883
 
880
- #line 881 "parser.c"
884
+ #line 885 "parser.c"
881
885
  enum {JSON_integer_start = 1};
882
886
  enum {JSON_integer_first_final = 3};
883
887
  enum {JSON_integer_error = 0};
@@ -885,7 +889,7 @@ enum {JSON_integer_error = 0};
885
889
  enum {JSON_integer_en_main = 1};
886
890
 
887
891
 
888
- #line 308 "parser.rl"
892
+ #line 312 "parser.rl"
889
893
 
890
894
 
891
895
  static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result)
@@ -893,15 +897,15 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res
893
897
  int cs = EVIL;
894
898
 
895
899
 
896
- #line 897 "parser.c"
900
+ #line 901 "parser.c"
897
901
  {
898
902
  cs = JSON_integer_start;
899
903
  }
900
904
 
901
- #line 315 "parser.rl"
905
+ #line 319 "parser.rl"
902
906
  json->memo = p;
903
907
 
904
- #line 905 "parser.c"
908
+ #line 909 "parser.c"
905
909
  {
906
910
  if ( p == pe )
907
911
  goto _test_eof;
@@ -935,14 +939,14 @@ case 3:
935
939
  goto st0;
936
940
  goto tr4;
937
941
  tr4:
938
- #line 305 "parser.rl"
942
+ #line 309 "parser.rl"
939
943
  { p--; {p++; cs = 4; goto _out;} }
940
944
  goto st4;
941
945
  st4:
942
946
  if ( ++p == pe )
943
947
  goto _test_eof4;
944
948
  case 4:
945
- #line 946 "parser.c"
949
+ #line 950 "parser.c"
946
950
  goto st0;
947
951
  st5:
948
952
  if ( ++p == pe )
@@ -961,7 +965,7 @@ case 5:
961
965
  _out: {}
962
966
  }
963
967
 
964
- #line 317 "parser.rl"
968
+ #line 321 "parser.rl"
965
969
 
966
970
  if (cs >= JSON_integer_first_final) {
967
971
  long len = p - json->memo;
@@ -976,7 +980,7 @@ case 5:
976
980
  }
977
981
 
978
982
 
979
- #line 980 "parser.c"
983
+ #line 984 "parser.c"
980
984
  enum {JSON_float_start = 1};
981
985
  enum {JSON_float_first_final = 8};
982
986
  enum {JSON_float_error = 0};
@@ -984,7 +988,7 @@ enum {JSON_float_error = 0};
984
988
  enum {JSON_float_en_main = 1};
985
989
 
986
990
 
987
- #line 342 "parser.rl"
991
+ #line 346 "parser.rl"
988
992
 
989
993
 
990
994
  static int is_bigdecimal_class(VALUE obj)
@@ -1005,15 +1009,15 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
1005
1009
  int cs = EVIL;
1006
1010
 
1007
1011
 
1008
- #line 1009 "parser.c"
1012
+ #line 1013 "parser.c"
1009
1013
  {
1010
1014
  cs = JSON_float_start;
1011
1015
  }
1012
1016
 
1013
- #line 362 "parser.rl"
1017
+ #line 366 "parser.rl"
1014
1018
  json->memo = p;
1015
1019
 
1016
- #line 1017 "parser.c"
1020
+ #line 1021 "parser.c"
1017
1021
  {
1018
1022
  if ( p == pe )
1019
1023
  goto _test_eof;
@@ -1071,14 +1075,14 @@ case 8:
1071
1075
  goto st0;
1072
1076
  goto tr9;
1073
1077
  tr9:
1074
- #line 336 "parser.rl"
1078
+ #line 340 "parser.rl"
1075
1079
  { p--; {p++; cs = 9; goto _out;} }
1076
1080
  goto st9;
1077
1081
  st9:
1078
1082
  if ( ++p == pe )
1079
1083
  goto _test_eof9;
1080
1084
  case 9:
1081
- #line 1082 "parser.c"
1085
+ #line 1086 "parser.c"
1082
1086
  goto st0;
1083
1087
  st5:
1084
1088
  if ( ++p == pe )
@@ -1139,7 +1143,7 @@ case 7:
1139
1143
  _out: {}
1140
1144
  }
1141
1145
 
1142
- #line 364 "parser.rl"
1146
+ #line 368 "parser.rl"
1143
1147
 
1144
1148
  if (cs >= JSON_float_first_final) {
1145
1149
  long len = p - json->memo;
@@ -1165,7 +1169,7 @@ case 7:
1165
1169
 
1166
1170
 
1167
1171
 
1168
- #line 1169 "parser.c"
1172
+ #line 1173 "parser.c"
1169
1173
  enum {JSON_array_start = 1};
1170
1174
  enum {JSON_array_first_final = 17};
1171
1175
  enum {JSON_array_error = 0};
@@ -1173,7 +1177,7 @@ enum {JSON_array_error = 0};
1173
1177
  enum {JSON_array_en_main = 1};
1174
1178
 
1175
1179
 
1176
- #line 417 "parser.rl"
1180
+ #line 421 "parser.rl"
1177
1181
 
1178
1182
 
1179
1183
  static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
@@ -1187,14 +1191,14 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul
1187
1191
  *result = NIL_P(array_class) ? rb_ary_new() : rb_class_new_instance(0, 0, array_class);
1188
1192
 
1189
1193
 
1190
- #line 1191 "parser.c"
1194
+ #line 1195 "parser.c"
1191
1195
  {
1192
1196
  cs = JSON_array_start;
1193
1197
  }
1194
1198
 
1195
- #line 430 "parser.rl"
1199
+ #line 434 "parser.rl"
1196
1200
 
1197
- #line 1198 "parser.c"
1201
+ #line 1202 "parser.c"
1198
1202
  {
1199
1203
  if ( p == pe )
1200
1204
  goto _test_eof;
@@ -1233,7 +1237,7 @@ case 2:
1233
1237
  goto st2;
1234
1238
  goto st0;
1235
1239
  tr2:
1236
- #line 394 "parser.rl"
1240
+ #line 398 "parser.rl"
1237
1241
  {
1238
1242
  VALUE v = Qnil;
1239
1243
  char *np = JSON_parse_value(json, p, pe, &v, current_nesting);
@@ -1253,7 +1257,7 @@ st3:
1253
1257
  if ( ++p == pe )
1254
1258
  goto _test_eof3;
1255
1259
  case 3:
1256
- #line 1257 "parser.c"
1260
+ #line 1261 "parser.c"
1257
1261
  switch( (*p) ) {
1258
1262
  case 13: goto st3;
1259
1263
  case 32: goto st3;
@@ -1353,14 +1357,14 @@ case 12:
1353
1357
  goto st3;
1354
1358
  goto st12;
1355
1359
  tr4:
1356
- #line 409 "parser.rl"
1360
+ #line 413 "parser.rl"
1357
1361
  { p--; {p++; cs = 17; goto _out;} }
1358
1362
  goto st17;
1359
1363
  st17:
1360
1364
  if ( ++p == pe )
1361
1365
  goto _test_eof17;
1362
1366
  case 17:
1363
- #line 1364 "parser.c"
1367
+ #line 1368 "parser.c"
1364
1368
  goto st0;
1365
1369
  st13:
1366
1370
  if ( ++p == pe )
@@ -1416,7 +1420,7 @@ case 16:
1416
1420
  _out: {}
1417
1421
  }
1418
1422
 
1419
- #line 431 "parser.rl"
1423
+ #line 435 "parser.rl"
1420
1424
 
1421
1425
  if(cs >= JSON_array_first_final) {
1422
1426
  return p + 1;
@@ -1505,7 +1509,7 @@ static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)
1505
1509
  }
1506
1510
 
1507
1511
 
1508
- #line 1509 "parser.c"
1512
+ #line 1513 "parser.c"
1509
1513
  enum {JSON_string_start = 1};
1510
1514
  enum {JSON_string_first_final = 8};
1511
1515
  enum {JSON_string_error = 0};
@@ -1513,7 +1517,7 @@ enum {JSON_string_error = 0};
1513
1517
  enum {JSON_string_en_main = 1};
1514
1518
 
1515
1519
 
1516
- #line 538 "parser.rl"
1520
+ #line 542 "parser.rl"
1517
1521
 
1518
1522
 
1519
1523
  static int
@@ -1535,15 +1539,15 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
1535
1539
 
1536
1540
  *result = rb_str_buf_new(0);
1537
1541
 
1538
- #line 1539 "parser.c"
1542
+ #line 1543 "parser.c"
1539
1543
  {
1540
1544
  cs = JSON_string_start;
1541
1545
  }
1542
1546
 
1543
- #line 559 "parser.rl"
1547
+ #line 563 "parser.rl"
1544
1548
  json->memo = p;
1545
1549
 
1546
- #line 1547 "parser.c"
1550
+ #line 1551 "parser.c"
1547
1551
  {
1548
1552
  if ( p == pe )
1549
1553
  goto _test_eof;
@@ -1568,7 +1572,7 @@ case 2:
1568
1572
  goto st0;
1569
1573
  goto st2;
1570
1574
  tr2:
1571
- #line 524 "parser.rl"
1575
+ #line 528 "parser.rl"
1572
1576
  {
1573
1577
  *result = json_string_unescape(*result, json->memo + 1, p);
1574
1578
  if (NIL_P(*result)) {
@@ -1579,14 +1583,14 @@ tr2:
1579
1583
  {p = (( p + 1))-1;}
1580
1584
  }
1581
1585
  }
1582
- #line 535 "parser.rl"
1586
+ #line 539 "parser.rl"
1583
1587
  { p--; {p++; cs = 8; goto _out;} }
1584
1588
  goto st8;
1585
1589
  st8:
1586
1590
  if ( ++p == pe )
1587
1591
  goto _test_eof8;
1588
1592
  case 8:
1589
- #line 1590 "parser.c"
1593
+ #line 1594 "parser.c"
1590
1594
  goto st0;
1591
1595
  st3:
1592
1596
  if ( ++p == pe )
@@ -1662,7 +1666,7 @@ case 7:
1662
1666
  _out: {}
1663
1667
  }
1664
1668
 
1665
- #line 561 "parser.rl"
1669
+ #line 565 "parser.rl"
1666
1670
 
1667
1671
  if (json->create_additions && RTEST(match_string = json->match_string)) {
1668
1672
  VALUE klass;
@@ -1678,7 +1682,22 @@ case 7:
1678
1682
  if (json->symbolize_names && json->parsing_name) {
1679
1683
  *result = rb_str_intern(*result);
1680
1684
  } else if (RB_TYPE_P(*result, T_STRING)) {
1685
+ # if STR_UMINUS_DEDUPE_FROZEN
1686
+ if (json->freeze) {
1687
+ // Starting from MRI 2.8 it is preferable to freeze the string
1688
+ // before deduplication so that it can be interned directly
1689
+ // otherwise it would be duplicated first which is wasteful.
1690
+ *result = rb_funcall(rb_str_freeze(*result), i_uminus, 0);
1691
+ }
1692
+ # elif STR_UMINUS_DEDUPE
1693
+ if (json->freeze) {
1694
+ // MRI 2.5 and older do not deduplicate strings that are already
1695
+ // frozen.
1696
+ *result = rb_funcall(*result, i_uminus, 0);
1697
+ }
1698
+ # else
1681
1699
  rb_str_resize(*result, RSTRING_LEN(*result));
1700
+ # endif
1682
1701
  }
1683
1702
  if (cs >= JSON_string_first_final) {
1684
1703
  return p + 1;
@@ -1786,6 +1805,12 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
1786
1805
  } else {
1787
1806
  json->symbolize_names = 0;
1788
1807
  }
1808
+ tmp = ID2SYM(i_freeze);
1809
+ if (option_given_p(opts, tmp)) {
1810
+ json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
1811
+ } else {
1812
+ json->freeze = 0;
1813
+ }
1789
1814
  tmp = ID2SYM(i_create_additions);
1790
1815
  if (option_given_p(opts, tmp)) {
1791
1816
  json->create_additions = RTEST(rb_hash_aref(opts, tmp));
@@ -1849,7 +1874,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
1849
1874
  }
1850
1875
 
1851
1876
 
1852
- #line 1853 "parser.c"
1877
+ #line 1878 "parser.c"
1853
1878
  enum {JSON_start = 1};
1854
1879
  enum {JSON_first_final = 10};
1855
1880
  enum {JSON_error = 0};
@@ -1857,7 +1882,7 @@ enum {JSON_error = 0};
1857
1882
  enum {JSON_en_main = 1};
1858
1883
 
1859
1884
 
1860
- #line 761 "parser.rl"
1885
+ #line 786 "parser.rl"
1861
1886
 
1862
1887
 
1863
1888
  /*
@@ -1874,16 +1899,16 @@ static VALUE cParser_parse(VALUE self)
1874
1899
  GET_PARSER;
1875
1900
 
1876
1901
 
1877
- #line 1878 "parser.c"
1902
+ #line 1903 "parser.c"
1878
1903
  {
1879
1904
  cs = JSON_start;
1880
1905
  }
1881
1906
 
1882
- #line 777 "parser.rl"
1907
+ #line 802 "parser.rl"
1883
1908
  p = json->source;
1884
1909
  pe = p + json->len;
1885
1910
 
1886
- #line 1887 "parser.c"
1911
+ #line 1912 "parser.c"
1887
1912
  {
1888
1913
  if ( p == pe )
1889
1914
  goto _test_eof;
@@ -1917,7 +1942,7 @@ st0:
1917
1942
  cs = 0;
1918
1943
  goto _out;
1919
1944
  tr2:
1920
- #line 753 "parser.rl"
1945
+ #line 778 "parser.rl"
1921
1946
  {
1922
1947
  char *np = JSON_parse_value(json, p, pe, &result, 0);
1923
1948
  if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;}
@@ -1927,7 +1952,7 @@ st10:
1927
1952
  if ( ++p == pe )
1928
1953
  goto _test_eof10;
1929
1954
  case 10:
1930
- #line 1931 "parser.c"
1955
+ #line 1956 "parser.c"
1931
1956
  switch( (*p) ) {
1932
1957
  case 13: goto st10;
1933
1958
  case 32: goto st10;
@@ -2016,7 +2041,7 @@ case 9:
2016
2041
  _out: {}
2017
2042
  }
2018
2043
 
2019
- #line 780 "parser.rl"
2044
+ #line 805 "parser.rl"
2020
2045
 
2021
2046
  if (cs >= JSON_first_final && p == pe) {
2022
2047
  return result;
@@ -2126,6 +2151,8 @@ void Init_parser(void)
2126
2151
  i_leftshift = rb_intern("<<");
2127
2152
  i_new = rb_intern("new");
2128
2153
  i_BigDecimal = rb_intern("BigDecimal");
2154
+ i_freeze = rb_intern("freeze");
2155
+ i_uminus = rb_intern("-@");
2129
2156
  }
2130
2157
 
2131
2158
  /*