json 2.1.0 → 2.6.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.
Files changed (96) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES.md +63 -5
  3. data/LICENSE +56 -0
  4. data/README.md +56 -23
  5. data/VERSION +1 -1
  6. data/ext/json/ext/generator/generator.c +223 -58
  7. data/ext/json/ext/generator/generator.h +5 -2
  8. data/ext/json/ext/parser/extconf.rb +26 -0
  9. data/ext/json/ext/parser/parser.c +2973 -1744
  10. data/ext/json/ext/parser/parser.h +6 -1
  11. data/ext/json/ext/parser/parser.rl +130 -22
  12. data/ext/json/extconf.rb +1 -0
  13. data/json.gemspec +0 -0
  14. data/lib/json/add/bigdecimal.rb +2 -2
  15. data/lib/json/add/complex.rb +2 -3
  16. data/lib/json/add/ostruct.rb +1 -1
  17. data/lib/json/add/rational.rb +2 -3
  18. data/lib/json/add/regexp.rb +2 -2
  19. data/lib/json/add/set.rb +29 -0
  20. data/lib/json/common.rb +372 -125
  21. data/lib/json/pure/generator.rb +31 -10
  22. data/lib/json/pure/parser.rb +32 -6
  23. data/lib/json/version.rb +1 -1
  24. data/lib/json.rb +549 -29
  25. metadata +19 -113
  26. data/.gitignore +0 -17
  27. data/.travis.yml +0 -19
  28. data/Gemfile +0 -16
  29. data/README-json-jruby.md +0 -33
  30. data/Rakefile +0 -408
  31. data/data/example.json +0 -1
  32. data/data/index.html +0 -38
  33. data/data/prototype.js +0 -4184
  34. data/diagrams/.keep +0 -0
  35. data/install.rb +0 -23
  36. data/java/src/json/ext/ByteListTranscoder.java +0 -166
  37. data/java/src/json/ext/Generator.java +0 -443
  38. data/java/src/json/ext/GeneratorMethods.java +0 -231
  39. data/java/src/json/ext/GeneratorService.java +0 -42
  40. data/java/src/json/ext/GeneratorState.java +0 -490
  41. data/java/src/json/ext/OptionsReader.java +0 -113
  42. data/java/src/json/ext/Parser.java +0 -2362
  43. data/java/src/json/ext/Parser.rl +0 -893
  44. data/java/src/json/ext/ParserService.java +0 -34
  45. data/java/src/json/ext/RuntimeInfo.java +0 -116
  46. data/java/src/json/ext/StringDecoder.java +0 -166
  47. data/java/src/json/ext/StringEncoder.java +0 -111
  48. data/java/src/json/ext/Utils.java +0 -88
  49. data/json-java.gemspec +0 -38
  50. data/json_pure.gemspec +0 -38
  51. data/lib/json/ext/.keep +0 -0
  52. data/references/rfc7159.txt +0 -899
  53. data/tests/fixtures/fail10.json +0 -1
  54. data/tests/fixtures/fail11.json +0 -1
  55. data/tests/fixtures/fail12.json +0 -1
  56. data/tests/fixtures/fail13.json +0 -1
  57. data/tests/fixtures/fail14.json +0 -1
  58. data/tests/fixtures/fail18.json +0 -1
  59. data/tests/fixtures/fail19.json +0 -1
  60. data/tests/fixtures/fail2.json +0 -1
  61. data/tests/fixtures/fail20.json +0 -1
  62. data/tests/fixtures/fail21.json +0 -1
  63. data/tests/fixtures/fail22.json +0 -1
  64. data/tests/fixtures/fail23.json +0 -1
  65. data/tests/fixtures/fail24.json +0 -1
  66. data/tests/fixtures/fail25.json +0 -1
  67. data/tests/fixtures/fail27.json +0 -2
  68. data/tests/fixtures/fail28.json +0 -2
  69. data/tests/fixtures/fail3.json +0 -1
  70. data/tests/fixtures/fail4.json +0 -1
  71. data/tests/fixtures/fail5.json +0 -1
  72. data/tests/fixtures/fail6.json +0 -1
  73. data/tests/fixtures/fail7.json +0 -1
  74. data/tests/fixtures/fail8.json +0 -1
  75. data/tests/fixtures/fail9.json +0 -1
  76. data/tests/fixtures/obsolete_fail1.json +0 -1
  77. data/tests/fixtures/pass1.json +0 -56
  78. data/tests/fixtures/pass15.json +0 -1
  79. data/tests/fixtures/pass16.json +0 -1
  80. data/tests/fixtures/pass17.json +0 -1
  81. data/tests/fixtures/pass2.json +0 -1
  82. data/tests/fixtures/pass26.json +0 -1
  83. data/tests/fixtures/pass3.json +0 -6
  84. data/tests/json_addition_test.rb +0 -193
  85. data/tests/json_common_interface_test.rb +0 -126
  86. data/tests/json_encoding_test.rb +0 -107
  87. data/tests/json_ext_parser_test.rb +0 -15
  88. data/tests/json_fixtures_test.rb +0 -32
  89. data/tests/json_generator_test.rb +0 -377
  90. data/tests/json_generic_object_test.rb +0 -82
  91. data/tests/json_parser_test.rb +0 -471
  92. data/tests/json_string_matching_test.rb +0 -38
  93. data/tests/test_helper.rb +0 -21
  94. data/tools/diff.sh +0 -18
  95. data/tools/fuzz.rb +0 -131
  96. data/tools/server.rb +0 -62
@@ -1,11 +1,6 @@
1
1
  #include "../fbuffer/fbuffer.h"
2
2
  #include "generator.h"
3
3
 
4
- #ifdef HAVE_RUBY_ENCODING_H
5
- static VALUE CEncoding_UTF_8;
6
- static ID i_encoding, i_encode;
7
- #endif
8
-
9
4
  static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
10
5
  mHash, mArray,
11
6
  #ifdef RUBY_INTEGER_UNIFICATION
@@ -15,14 +10,13 @@ static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
15
10
  #endif
16
11
  mFloat, mString, mString_Extend,
17
12
  mTrueClass, mFalseClass, mNilClass, eGeneratorError,
18
- eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,
19
- i_SAFE_STATE_PROTOTYPE;
13
+ eNestingError;
20
14
 
21
15
  static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
22
16
  i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
23
17
  i_pack, i_unpack, i_create_id, i_extend, i_key_p,
24
18
  i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
25
- i_buffer_initial_length, i_dup;
19
+ i_buffer_initial_length, i_dup, i_escape_slash;
26
20
 
27
21
  /*
28
22
  * Copyright 2001-2004 Unicode, Inc.
@@ -130,7 +124,7 @@ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
130
124
 
131
125
  /* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
132
126
  * and control characters are JSON escaped. */
133
- static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
127
+ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash)
134
128
  {
135
129
  const UTF8 *source = (UTF8 *) RSTRING_PTR(string);
136
130
  const UTF8 *sourceEnd = source + RSTRING_LEN(string);
@@ -180,6 +174,11 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
180
174
  case '"':
181
175
  fbuffer_append(buffer, "\\\"", 2);
182
176
  break;
177
+ case '/':
178
+ if(escape_slash) {
179
+ fbuffer_append(buffer, "\\/", 2);
180
+ break;
181
+ }
183
182
  default:
184
183
  fbuffer_append_char(buffer, (char)ch);
185
184
  break;
@@ -229,7 +228,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
229
228
  * characters required by the JSON standard are JSON escaped. The remaining
230
229
  * characters (should be UTF8) are just passed through and appended to the
231
230
  * result. */
232
- static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
231
+ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash)
233
232
  {
234
233
  const char *ptr = RSTRING_PTR(string), *p;
235
234
  unsigned long len = RSTRING_LEN(string), start = 0, end = 0;
@@ -237,6 +236,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
237
236
  int escape_len;
238
237
  unsigned char c;
239
238
  char buf[6] = { '\\', 'u' };
239
+ int ascii_only = rb_enc_str_asciionly_p(string);
240
240
 
241
241
  for (start = 0, end = 0; end < len;) {
242
242
  p = ptr + end;
@@ -279,16 +279,25 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
279
279
  escape = "\\\"";
280
280
  escape_len = 2;
281
281
  break;
282
+ case '/':
283
+ if(escape_slash) {
284
+ escape = "\\/";
285
+ escape_len = 2;
286
+ break;
287
+ }
282
288
  default:
283
289
  {
284
- unsigned short clen = trailingBytesForUTF8[c] + 1;
285
- if (end + clen > len) {
286
- rb_raise(rb_path2class("JSON::GeneratorError"),
287
- "partial character in source, but hit end");
288
- }
289
- if (!isLegalUTF8((UTF8 *) p, clen)) {
290
- rb_raise(rb_path2class("JSON::GeneratorError"),
291
- "source sequence is illegal/malformed utf-8");
290
+ unsigned short clen = 1;
291
+ if (!ascii_only) {
292
+ clen += trailingBytesForUTF8[c];
293
+ if (end + clen > len) {
294
+ rb_raise(rb_path2class("JSON::GeneratorError"),
295
+ "partial character in source, but hit end");
296
+ }
297
+ if (!isLegalUTF8((UTF8 *) p, clen)) {
298
+ rb_raise(rb_path2class("JSON::GeneratorError"),
299
+ "source sequence is illegal/malformed utf-8");
300
+ }
292
301
  }
293
302
  end += clen;
294
303
  }
@@ -324,6 +333,76 @@ static char *fstrndup(const char *ptr, unsigned long len) {
324
333
  *
325
334
  */
326
335
 
336
+ /* Explanation of the following: that's the only way to not pollute
337
+ * standard library's docs with GeneratorMethods::<ClassName> which
338
+ * are uninformative and take a large place in a list of classes
339
+ */
340
+
341
+ /*
342
+ * Document-module: JSON::Ext::Generator::GeneratorMethods
343
+ * :nodoc:
344
+ */
345
+
346
+ /*
347
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Array
348
+ * :nodoc:
349
+ */
350
+
351
+ /*
352
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
353
+ * :nodoc:
354
+ */
355
+
356
+ /*
357
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
358
+ * :nodoc:
359
+ */
360
+
361
+ /*
362
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
363
+ * :nodoc:
364
+ */
365
+
366
+ /*
367
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Float
368
+ * :nodoc:
369
+ */
370
+
371
+ /*
372
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
373
+ * :nodoc:
374
+ */
375
+
376
+ /*
377
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
378
+ * :nodoc:
379
+ */
380
+
381
+ /*
382
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
383
+ * :nodoc:
384
+ */
385
+
386
+ /*
387
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Object
388
+ * :nodoc:
389
+ */
390
+
391
+ /*
392
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::String
393
+ * :nodoc:
394
+ */
395
+
396
+ /*
397
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
398
+ * :nodoc:
399
+ */
400
+
401
+ /*
402
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
403
+ * :nodoc:
404
+ */
405
+
327
406
  /*
328
407
  * call-seq: to_json(state = nil)
329
408
  *
@@ -535,13 +614,18 @@ static size_t State_memsize(const void *ptr)
535
614
  return size;
536
615
  }
537
616
 
617
+ #ifndef HAVE_RB_EXT_RACTOR_SAFE
618
+ # undef RUBY_TYPED_FROZEN_SHAREABLE
619
+ # define RUBY_TYPED_FROZEN_SHAREABLE 0
620
+ #endif
621
+
538
622
  #ifdef NEW_TYPEDDATA_WRAPPER
539
623
  static const rb_data_type_t JSON_Generator_State_type = {
540
624
  "JSON/Generator/State",
541
625
  {NULL, State_free, State_memsize,},
542
626
  #ifdef RUBY_TYPED_FREE_IMMEDIATELY
543
627
  0, 0,
544
- RUBY_TYPED_FREE_IMMEDIATELY,
628
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
545
629
  #endif
546
630
  };
547
631
  #endif
@@ -642,6 +726,8 @@ static VALUE cState_configure(VALUE self, VALUE opts)
642
726
  state->allow_nan = RTEST(tmp);
643
727
  tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
644
728
  state->ascii_only = RTEST(tmp);
729
+ tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
730
+ state->escape_slash = RTEST(tmp);
645
731
  return self;
646
732
  }
647
733
 
@@ -676,6 +762,7 @@ static VALUE cState_to_h(VALUE self)
676
762
  rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
677
763
  rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
678
764
  rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
765
+ rb_hash_aset(result, ID2SYM(i_escape_slash), state->escape_slash ? Qtrue : Qfalse);
679
766
  rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
680
767
  rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
681
768
  return result;
@@ -692,7 +779,7 @@ static VALUE cState_aref(VALUE self, VALUE name)
692
779
  if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
693
780
  return rb_funcall(self, i_send, 1, name);
694
781
  } else {
695
- return rb_ivar_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
782
+ return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
696
783
  }
697
784
  }
698
785
 
@@ -715,43 +802,83 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
715
802
  return Qnil;
716
803
  }
717
804
 
718
- static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
805
+ struct hash_foreach_arg {
806
+ FBuffer *buffer;
807
+ JSON_Generator_State *state;
808
+ VALUE Vstate;
809
+ int iter;
810
+ };
811
+
812
+ static int
813
+ json_object_i(VALUE key, VALUE val, VALUE _arg)
719
814
  {
815
+ struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
816
+ FBuffer *buffer = arg->buffer;
817
+ JSON_Generator_State *state = arg->state;
818
+ VALUE Vstate = arg->Vstate;
819
+
720
820
  char *object_nl = state->object_nl;
721
821
  long object_nl_len = state->object_nl_len;
722
822
  char *indent = state->indent;
723
823
  long indent_len = state->indent_len;
724
- long max_nesting = state->max_nesting;
725
824
  char *delim = FBUFFER_PTR(state->object_delim);
726
825
  long delim_len = FBUFFER_LEN(state->object_delim);
727
826
  char *delim2 = FBUFFER_PTR(state->object_delim2);
728
827
  long delim2_len = FBUFFER_LEN(state->object_delim2);
828
+ long depth = state->depth;
829
+ int j;
830
+ VALUE klass, key_to_s;
831
+
832
+ if (arg->iter > 0) fbuffer_append(buffer, delim, delim_len);
833
+ if (object_nl) {
834
+ fbuffer_append(buffer, object_nl, object_nl_len);
835
+ }
836
+ if (indent) {
837
+ for (j = 0; j < depth; j++) {
838
+ fbuffer_append(buffer, indent, indent_len);
839
+ }
840
+ }
841
+
842
+ klass = CLASS_OF(key);
843
+ if (klass == rb_cString) {
844
+ key_to_s = key;
845
+ } else if (klass == rb_cSymbol) {
846
+ key_to_s = rb_id2str(SYM2ID(key));
847
+ } else {
848
+ key_to_s = rb_funcall(key, i_to_s, 0);
849
+ }
850
+ Check_Type(key_to_s, T_STRING);
851
+ generate_json(buffer, Vstate, state, key_to_s);
852
+ fbuffer_append(buffer, delim2, delim2_len);
853
+ generate_json(buffer, Vstate, state, val);
854
+
855
+ arg->iter++;
856
+ return ST_CONTINUE;
857
+ }
858
+
859
+ static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
860
+ {
861
+ char *object_nl = state->object_nl;
862
+ long object_nl_len = state->object_nl_len;
863
+ char *indent = state->indent;
864
+ long indent_len = state->indent_len;
865
+ long max_nesting = state->max_nesting;
729
866
  long depth = ++state->depth;
730
- int i, j;
731
- VALUE key, key_to_s, keys;
867
+ int j;
868
+ struct hash_foreach_arg arg;
869
+
732
870
  if (max_nesting != 0 && depth > max_nesting) {
733
871
  fbuffer_free(buffer);
734
872
  rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
735
873
  }
736
874
  fbuffer_append_char(buffer, '{');
737
- keys = rb_funcall(obj, i_keys, 0);
738
- for(i = 0; i < RARRAY_LEN(keys); i++) {
739
- if (i > 0) fbuffer_append(buffer, delim, delim_len);
740
- if (object_nl) {
741
- fbuffer_append(buffer, object_nl, object_nl_len);
742
- }
743
- if (indent) {
744
- for (j = 0; j < depth; j++) {
745
- fbuffer_append(buffer, indent, indent_len);
746
- }
747
- }
748
- key = rb_ary_entry(keys, i);
749
- key_to_s = rb_funcall(key, i_to_s, 0);
750
- Check_Type(key_to_s, T_STRING);
751
- generate_json(buffer, Vstate, state, key_to_s);
752
- fbuffer_append(buffer, delim2, delim2_len);
753
- generate_json(buffer, Vstate, state, rb_hash_aref(obj, key));
754
- }
875
+
876
+ arg.buffer = buffer;
877
+ arg.state = state;
878
+ arg.Vstate = Vstate;
879
+ arg.iter = 0;
880
+ rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
881
+
755
882
  depth = --state->depth;
756
883
  if (object_nl) {
757
884
  fbuffer_append(buffer, object_nl, object_nl_len);
@@ -802,16 +929,27 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
802
929
  fbuffer_append_char(buffer, ']');
803
930
  }
804
931
 
932
+ #ifdef HAVE_RUBY_ENCODING_H
933
+ static int enc_utf8_compatible_p(rb_encoding *enc)
934
+ {
935
+ if (enc == rb_usascii_encoding()) return 1;
936
+ if (enc == rb_utf8_encoding()) return 1;
937
+ return 0;
938
+ }
939
+ #endif
940
+
805
941
  static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
806
942
  {
807
943
  fbuffer_append_char(buffer, '"');
808
944
  #ifdef HAVE_RUBY_ENCODING_H
809
- obj = rb_funcall(obj, i_encode, 1, CEncoding_UTF_8);
945
+ if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
946
+ obj = rb_str_export_to_enc(obj, rb_utf8_encoding());
947
+ }
810
948
  #endif
811
949
  if (state->ascii_only) {
812
- convert_UTF8_to_JSON_ASCII(buffer, obj);
950
+ convert_UTF8_to_JSON_ASCII(buffer, obj, state->escape_slash);
813
951
  } else {
814
- convert_UTF8_to_JSON(buffer, obj);
952
+ convert_UTF8_to_JSON(buffer, obj, state->escape_slash);
815
953
  }
816
954
  fbuffer_append_char(buffer, '"');
817
955
  }
@@ -970,6 +1108,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
970
1108
  * * *allow_nan*: true if NaN, Infinity, and -Infinity should be
971
1109
  * generated, otherwise an exception is thrown, if these values are
972
1110
  * encountered. This options defaults to false.
1111
+ * * *ascii_only*: true if only ASCII characters should be generated. This
1112
+ * option defaults to false.
973
1113
  * * *buffer_initial_length*: sets the initial length of the generator's
974
1114
  * internal buffer.
975
1115
  */
@@ -1025,10 +1165,7 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
1025
1165
  } else if (rb_obj_is_kind_of(opts, rb_cHash)) {
1026
1166
  return rb_funcall(self, i_new, 1, opts);
1027
1167
  } else {
1028
- if (NIL_P(CJSON_SAFE_STATE_PROTOTYPE)) {
1029
- CJSON_SAFE_STATE_PROTOTYPE = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
1030
- }
1031
- return rb_funcall(CJSON_SAFE_STATE_PROTOTYPE, i_dup, 0);
1168
+ return rb_class_new_instance(0, NULL, cState);
1032
1169
  }
1033
1170
  }
1034
1171
 
@@ -1252,6 +1389,31 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
1252
1389
  return state->max_nesting = FIX2LONG(depth);
1253
1390
  }
1254
1391
 
1392
+ /*
1393
+ * call-seq: escape_slash
1394
+ *
1395
+ * If this boolean is true, the forward slashes will be escaped in
1396
+ * the json output.
1397
+ */
1398
+ static VALUE cState_escape_slash(VALUE self)
1399
+ {
1400
+ GET_STATE(self);
1401
+ return state->escape_slash ? Qtrue : Qfalse;
1402
+ }
1403
+
1404
+ /*
1405
+ * call-seq: escape_slash=(depth)
1406
+ *
1407
+ * This sets whether or not the forward slashes will be escaped in
1408
+ * the json output.
1409
+ */
1410
+ static VALUE cState_escape_slash_set(VALUE self, VALUE enable)
1411
+ {
1412
+ GET_STATE(self);
1413
+ state->escape_slash = RTEST(enable);
1414
+ return Qnil;
1415
+ }
1416
+
1255
1417
  /*
1256
1418
  * call-seq: allow_nan?
1257
1419
  *
@@ -1267,7 +1429,7 @@ static VALUE cState_allow_nan_p(VALUE self)
1267
1429
  /*
1268
1430
  * call-seq: ascii_only?
1269
1431
  *
1270
- * Returns true, if NaN, Infinity, and -Infinity should be generated, otherwise
1432
+ * Returns true, if only ASCII characters should be generated. Otherwise
1271
1433
  * returns false.
1272
1434
  */
1273
1435
  static VALUE cState_ascii_only_p(VALUE self)
@@ -1335,6 +1497,11 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
1335
1497
  */
1336
1498
  void Init_generator(void)
1337
1499
  {
1500
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
1501
+ rb_ext_ractor_safe(true);
1502
+ #endif
1503
+
1504
+ #undef rb_intern
1338
1505
  rb_require("json/common");
1339
1506
 
1340
1507
  mJSON = rb_define_module("JSON");
@@ -1343,6 +1510,8 @@ void Init_generator(void)
1343
1510
 
1344
1511
  eGeneratorError = rb_path2class("JSON::GeneratorError");
1345
1512
  eNestingError = rb_path2class("JSON::NestingError");
1513
+ rb_gc_register_mark_object(eGeneratorError);
1514
+ rb_gc_register_mark_object(eNestingError);
1346
1515
 
1347
1516
  cState = rb_define_class_under(mGenerator, "State", rb_cObject);
1348
1517
  rb_define_alloc_func(cState, cState_s_allocate);
@@ -1361,6 +1530,9 @@ void Init_generator(void)
1361
1530
  rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
1362
1531
  rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
1363
1532
  rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
1533
+ rb_define_method(cState, "escape_slash", cState_escape_slash, 0);
1534
+ rb_define_method(cState, "escape_slash?", cState_escape_slash, 0);
1535
+ rb_define_method(cState, "escape_slash=", cState_escape_slash_set, 1);
1364
1536
  rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
1365
1537
  rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
1366
1538
  rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
@@ -1408,7 +1580,6 @@ void Init_generator(void)
1408
1580
  mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
1409
1581
  rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
1410
1582
 
1411
- CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
1412
1583
  i_to_s = rb_intern("to_s");
1413
1584
  i_to_json = rb_intern("to_json");
1414
1585
  i_new = rb_intern("new");
@@ -1418,6 +1589,7 @@ void Init_generator(void)
1418
1589
  i_object_nl = rb_intern("object_nl");
1419
1590
  i_array_nl = rb_intern("array_nl");
1420
1591
  i_max_nesting = rb_intern("max_nesting");
1592
+ i_escape_slash = rb_intern("escape_slash");
1421
1593
  i_allow_nan = rb_intern("allow_nan");
1422
1594
  i_ascii_only = rb_intern("ascii_only");
1423
1595
  i_depth = rb_intern("depth");
@@ -1433,11 +1605,4 @@ void Init_generator(void)
1433
1605
  i_match = rb_intern("match");
1434
1606
  i_keys = rb_intern("keys");
1435
1607
  i_dup = rb_intern("dup");
1436
- #ifdef HAVE_RUBY_ENCODING_H
1437
- CEncoding_UTF_8 = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-8"));
1438
- i_encoding = rb_intern("encoding");
1439
- i_encode = rb_intern("encode");
1440
- #endif
1441
- i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
1442
- CJSON_SAFE_STATE_PROTOTYPE = Qnil;
1443
1608
  }
@@ -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)))
@@ -2,5 +2,31 @@
2
2
  require 'mkmf'
3
3
 
4
4
  have_func("rb_enc_raise", "ruby.h")
5
+ have_func("rb_enc_interned_str", "ruby.h")
6
+
7
+ # checking if String#-@ (str_uminus) dedupes... '
8
+ begin
9
+ a = -(%w(t e s t).join)
10
+ b = -(%w(t e s t).join)
11
+ if a.equal?(b)
12
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=1 '
13
+ else
14
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=0 '
15
+ end
16
+ rescue NoMethodError
17
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=0 '
18
+ end
19
+
20
+ # checking if String#-@ (str_uminus) directly interns frozen strings... '
21
+ begin
22
+ s = rand.to_s.freeze
23
+ if (-s).equal?(s) && (-s.dup).equal?(s)
24
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=1 '
25
+ else
26
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
27
+ end
28
+ rescue NoMethodError
29
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
30
+ end
5
31
 
6
32
  create_makefile 'json/ext/parser'