json_pure 2.3.1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c9596fed3a23816c350541834dec8366a59b55f45dd24148bf9f9582c811cec
4
- data.tar.gz: 6ab35bc50d5ee2849938e9e8b60815283f697e66d20fa35bca2b124a7d95f5fa
3
+ metadata.gz: 19ad55284912f57f06f2aa2d0a6336486ee6d20112a3cec8e3f4e918a0fbd338
4
+ data.tar.gz: 159c717b0b0cc8e4e6d8609b542b113fb8c483e1a306b6582f8a98ddadc20090
5
5
  SHA512:
6
- metadata.gz: 99981f3f931536d63001b061545fce1adc3afe92065741b25986083bf99c6432c94488453e4df244d79e760f8a3c6553a1ef2c56c6a65d15b81270dedbc7d718
7
- data.tar.gz: c9e6267ba4d21ad4e072888ef20d024efa4298a7e914334e51cfb75c1c4a7f5b8a552948a754ae1ca08cd8db191aba07163b6cdc3acac6948873a55cf3f686fa
6
+ metadata.gz: fba550423cbfb98dfe9abc4fe534e7fbeff135cde38a0e17b98123dbf8a664b70e7d26e130b536292123268266917251c06800b1224eca3007e1f6f54a148b16
7
+ data.tar.gz: fbe734f8b76e9f4c4c90304d11fa8026d349e2684f01358140cb36113720a57016fbbe8b12857f5e2c7b82baef2ac09a528b7839e17a22f87132940af98da2a0
@@ -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/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
  /*