json 2.0.3 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES.md +66 -0
  3. data/Gemfile +1 -3
  4. data/LICENSE +56 -0
  5. data/README.md +54 -21
  6. data/VERSION +1 -1
  7. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  8. data/ext/json/ext/generator/generator.c +229 -54
  9. data/ext/json/ext/generator/generator.h +5 -3
  10. data/ext/json/ext/parser/extconf.rb +25 -0
  11. data/ext/json/ext/parser/parser.c +180 -85
  12. data/ext/json/ext/parser/parser.h +2 -0
  13. data/ext/json/ext/parser/parser.rl +104 -9
  14. data/ext/json/extconf.rb +1 -0
  15. data/json.gemspec +0 -0
  16. data/lib/json/add/bigdecimal.rb +2 -2
  17. data/lib/json/add/complex.rb +2 -3
  18. data/lib/json/add/ostruct.rb +1 -1
  19. data/lib/json/add/rational.rb +2 -3
  20. data/lib/json/add/regexp.rb +2 -2
  21. data/lib/json/add/set.rb +29 -0
  22. data/lib/json/common.rb +372 -125
  23. data/lib/json/pure/generator.rb +31 -10
  24. data/lib/json/pure/parser.rb +35 -5
  25. data/lib/json/version.rb +1 -1
  26. data/lib/json.rb +549 -29
  27. data/tests/fixtures/fail29.json +1 -0
  28. data/tests/fixtures/fail30.json +1 -0
  29. data/tests/fixtures/fail31.json +1 -0
  30. data/tests/fixtures/fail32.json +1 -0
  31. data/tests/json_addition_test.rb +6 -0
  32. data/tests/json_common_interface_test.rb +47 -4
  33. data/tests/json_encoding_test.rb +2 -0
  34. data/tests/json_fixtures_test.rb +9 -1
  35. data/tests/json_generator_test.rb +30 -8
  36. data/tests/json_parser_test.rb +43 -12
  37. data/tests/lib/core_assertions.rb +763 -0
  38. data/tests/lib/envutil.rb +365 -0
  39. data/tests/lib/find_executable.rb +22 -0
  40. data/tests/lib/helper.rb +4 -0
  41. data/tests/ractor_test.rb +30 -0
  42. data/tests/test_helper.rb +3 -7
  43. metadata +31 -44
  44. data/.gitignore +0 -17
  45. data/.travis.yml +0 -19
  46. data/README-json-jruby.md +0 -33
  47. data/Rakefile +0 -408
  48. data/data/example.json +0 -1
  49. data/data/index.html +0 -38
  50. data/data/prototype.js +0 -4184
  51. data/diagrams/.keep +0 -0
  52. data/install.rb +0 -23
  53. data/java/src/json/ext/ByteListTranscoder.java +0 -166
  54. data/java/src/json/ext/Generator.java +0 -443
  55. data/java/src/json/ext/GeneratorMethods.java +0 -231
  56. data/java/src/json/ext/GeneratorService.java +0 -42
  57. data/java/src/json/ext/GeneratorState.java +0 -490
  58. data/java/src/json/ext/OptionsReader.java +0 -113
  59. data/java/src/json/ext/Parser.java +0 -2347
  60. data/java/src/json/ext/Parser.rl +0 -878
  61. data/java/src/json/ext/ParserService.java +0 -34
  62. data/java/src/json/ext/RuntimeInfo.java +0 -116
  63. data/java/src/json/ext/StringDecoder.java +0 -166
  64. data/java/src/json/ext/StringEncoder.java +0 -111
  65. data/java/src/json/ext/Utils.java +0 -88
  66. data/json-java.gemspec +0 -38
  67. data/json_pure.gemspec +0 -38
  68. data/references/rfc7159.txt +0 -899
  69. data/tools/diff.sh +0 -18
  70. data/tools/fuzz.rb +0 -131
  71. data/tools/server.rb +0 -62
@@ -37,8 +37,10 @@ typedef struct JSON_ParserStruct {
37
37
  int allow_nan;
38
38
  int parsing_name;
39
39
  int symbolize_names;
40
+ int freeze;
40
41
  VALUE object_class;
41
42
  VALUE array_class;
43
+ VALUE decimal_class;
42
44
  int create_additions;
43
45
  VALUE match_string;
44
46
  FBuffer *fbuffer;
@@ -25,7 +25,7 @@ enc_raise(rb_encoding *enc, VALUE exc, const char *fmt, ...)
25
25
 
26
26
  /* unicode */
27
27
 
28
- static const char digit_values[256] = {
28
+ static const signed char digit_values[256] = {
29
29
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30
30
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31
31
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
@@ -44,7 +44,7 @@ static const char digit_values[256] = {
44
44
 
45
45
  static UTF32 unescape_unicode(const unsigned char *p)
46
46
  {
47
- char b;
47
+ signed char b;
48
48
  UTF32 result = 0;
49
49
  b = digit_values[p[0]];
50
50
  if (b < 0) return UNI_REPLACEMENT_CHAR;
@@ -92,8 +92,9 @@ static VALUE CNaN, CInfinity, CMinusInfinity;
92
92
 
93
93
  static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
94
94
  i_chr, i_max_nesting, i_allow_nan, i_symbolize_names,
95
- i_object_class, i_array_class, i_key_p, i_deep_const_get, i_match,
96
- i_match_string, i_aset, i_aref, i_leftshift;
95
+ i_object_class, i_array_class, i_decimal_class, i_key_p,
96
+ i_deep_const_get, i_match, i_match_string, i_aset, i_aref,
97
+ i_leftshift, i_new, i_try_convert, i_freeze, i_uminus;
97
98
 
98
99
  %%{
99
100
  machine JSON_common;
@@ -136,6 +137,7 @@ static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
136
137
  fhold; fbreak;
137
138
  } else {
138
139
  if (NIL_P(json->object_class)) {
140
+ OBJ_FREEZE(last_name);
139
141
  rb_hash_aset(*result, last_name, v);
140
142
  } else {
141
143
  rb_funcall(*result, i_aset, 2, last_name, v);
@@ -287,6 +289,10 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul
287
289
  %% write init;
288
290
  %% write exec;
289
291
 
292
+ if (json->freeze) {
293
+ OBJ_FREEZE(*result);
294
+ }
295
+
290
296
  if (cs >= JSON_value_first_final) {
291
297
  return p;
292
298
  } else {
@@ -347,11 +353,46 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
347
353
  %% write exec;
348
354
 
349
355
  if (cs >= JSON_float_first_final) {
356
+ VALUE mod = Qnil;
357
+ ID method_id = 0;
358
+ if (rb_respond_to(json->decimal_class, i_try_convert)) {
359
+ mod = json->decimal_class;
360
+ method_id = i_try_convert;
361
+ } else if (rb_respond_to(json->decimal_class, i_new)) {
362
+ mod = json->decimal_class;
363
+ method_id = i_new;
364
+ } else if (RB_TYPE_P(json->decimal_class, T_CLASS)) {
365
+ VALUE name = rb_class_name(json->decimal_class);
366
+ const char *name_cstr = RSTRING_PTR(name);
367
+ const char *last_colon = strrchr(name_cstr, ':');
368
+ if (last_colon) {
369
+ const char *mod_path_end = last_colon - 1;
370
+ VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
371
+ mod = rb_path_to_class(mod_path);
372
+
373
+ const char *method_name_beg = last_colon + 1;
374
+ long before_len = method_name_beg - name_cstr;
375
+ long len = RSTRING_LEN(name) - before_len;
376
+ VALUE method_name = rb_str_substr(name, before_len, len);
377
+ method_id = SYM2ID(rb_str_intern(method_name));
378
+ } else {
379
+ mod = rb_mKernel;
380
+ method_id = SYM2ID(rb_str_intern(name));
381
+ }
382
+ }
383
+
350
384
  long len = p - json->memo;
351
385
  fbuffer_clear(json->fbuffer);
352
386
  fbuffer_append(json->fbuffer, json->memo, len);
353
387
  fbuffer_append_char(json->fbuffer, '\0');
354
- *result = rb_float_new(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
388
+
389
+ if (method_id) {
390
+ VALUE text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
391
+ *result = rb_funcallv(mod, method_id, 1, &text);
392
+ } else {
393
+ *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
394
+ }
395
+
355
396
  return p + 1;
356
397
  } else {
357
398
  return NULL;
@@ -446,13 +487,21 @@ static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)
446
487
  break;
447
488
  case 'u':
448
489
  if (pe > stringEnd - 4) {
449
- return Qnil;
490
+ rb_enc_raise(
491
+ EXC_ENCODING eParserError,
492
+ "%u: incomplete unicode character escape sequence at '%s'", __LINE__, p
493
+ );
450
494
  } else {
451
495
  UTF32 ch = unescape_unicode((unsigned char *) ++pe);
452
496
  pe += 3;
453
497
  if (UNI_SUR_HIGH_START == (ch & 0xFC00)) {
454
498
  pe++;
455
- if (pe > stringEnd - 6) return Qnil;
499
+ if (pe > stringEnd - 6) {
500
+ rb_enc_raise(
501
+ EXC_ENCODING eParserError,
502
+ "%u: incomplete surrogate pair at '%s'", __LINE__, p
503
+ );
504
+ }
456
505
  if (pe[0] == '\\' && pe[1] == 'u') {
457
506
  UTF32 sur = unescape_unicode((unsigned char *) pe + 2);
458
507
  ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
@@ -538,8 +587,23 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
538
587
 
539
588
  if (json->symbolize_names && json->parsing_name) {
540
589
  *result = rb_str_intern(*result);
541
- } else {
590
+ } else if (RB_TYPE_P(*result, T_STRING)) {
591
+ # if STR_UMINUS_DEDUPE_FROZEN
592
+ if (json->freeze) {
593
+ // Starting from MRI 2.8 it is preferable to freeze the string
594
+ // before deduplication so that it can be interned directly
595
+ // otherwise it would be duplicated first which is wasteful.
596
+ *result = rb_funcall(rb_str_freeze(*result), i_uminus, 0);
597
+ }
598
+ # elif STR_UMINUS_DEDUPE
599
+ if (json->freeze) {
600
+ // MRI 2.5 and older do not deduplicate strings that are already
601
+ // frozen.
602
+ *result = rb_funcall(*result, i_uminus, 0);
603
+ }
604
+ # else
542
605
  rb_str_resize(*result, RSTRING_LEN(*result));
606
+ # endif
543
607
  }
544
608
  if (cs >= JSON_string_first_final) {
545
609
  return p + 1;
@@ -647,6 +711,12 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
647
711
  } else {
648
712
  json->symbolize_names = 0;
649
713
  }
714
+ tmp = ID2SYM(i_freeze);
715
+ if (option_given_p(opts, tmp)) {
716
+ json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
717
+ } else {
718
+ json->freeze = 0;
719
+ }
650
720
  tmp = ID2SYM(i_create_additions);
651
721
  if (option_given_p(opts, tmp)) {
652
722
  json->create_additions = RTEST(rb_hash_aref(opts, tmp));
@@ -676,6 +746,12 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
676
746
  } else {
677
747
  json->array_class = Qnil;
678
748
  }
749
+ tmp = ID2SYM(i_decimal_class);
750
+ if (option_given_p(opts, tmp)) {
751
+ json->decimal_class = rb_hash_aref(opts, tmp);
752
+ } else {
753
+ json->decimal_class = Qnil;
754
+ }
679
755
  tmp = ID2SYM(i_match_string);
680
756
  if (option_given_p(opts, tmp)) {
681
757
  VALUE match_string = rb_hash_aref(opts, tmp);
@@ -689,10 +765,11 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
689
765
  } else {
690
766
  json->max_nesting = 100;
691
767
  json->allow_nan = 0;
692
- json->create_additions = 1;
768
+ json->create_additions = 0;
693
769
  json->create_id = rb_funcall(mJSON, i_create_id, 0);
694
770
  json->object_class = Qnil;
695
771
  json->array_class = Qnil;
772
+ json->decimal_class = Qnil;
696
773
  }
697
774
  source = convert_encoding(StringValue(source));
698
775
  StringValue(source);
@@ -752,6 +829,7 @@ static void JSON_mark(void *ptr)
752
829
  rb_gc_mark_maybe(json->create_id);
753
830
  rb_gc_mark_maybe(json->object_class);
754
831
  rb_gc_mark_maybe(json->array_class);
832
+ rb_gc_mark_maybe(json->decimal_class);
755
833
  rb_gc_mark_maybe(json->match_string);
756
834
  }
757
835
 
@@ -801,20 +879,32 @@ static VALUE cParser_source(VALUE self)
801
879
 
802
880
  void Init_parser(void)
803
881
  {
882
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
883
+ rb_ext_ractor_safe(true);
884
+ #endif
885
+
886
+ #undef rb_intern
804
887
  rb_require("json/common");
805
888
  mJSON = rb_define_module("JSON");
806
889
  mExt = rb_define_module_under(mJSON, "Ext");
807
890
  cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
808
891
  eParserError = rb_path2class("JSON::ParserError");
809
892
  eNestingError = rb_path2class("JSON::NestingError");
893
+ rb_gc_register_mark_object(eParserError);
894
+ rb_gc_register_mark_object(eNestingError);
810
895
  rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
811
896
  rb_define_method(cParser, "initialize", cParser_initialize, -1);
812
897
  rb_define_method(cParser, "parse", cParser_parse, 0);
813
898
  rb_define_method(cParser, "source", cParser_source, 0);
814
899
 
815
900
  CNaN = rb_const_get(mJSON, rb_intern("NaN"));
901
+ rb_gc_register_mark_object(CNaN);
902
+
816
903
  CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
904
+ rb_gc_register_mark_object(CInfinity);
905
+
817
906
  CMinusInfinity = rb_const_get(mJSON, rb_intern("MinusInfinity"));
907
+ rb_gc_register_mark_object(CMinusInfinity);
818
908
 
819
909
  i_json_creatable_p = rb_intern("json_creatable?");
820
910
  i_json_create = rb_intern("json_create");
@@ -826,6 +916,7 @@ void Init_parser(void)
826
916
  i_symbolize_names = rb_intern("symbolize_names");
827
917
  i_object_class = rb_intern("object_class");
828
918
  i_array_class = rb_intern("array_class");
919
+ i_decimal_class = rb_intern("decimal_class");
829
920
  i_match = rb_intern("match");
830
921
  i_match_string = rb_intern("match_string");
831
922
  i_key_p = rb_intern("key?");
@@ -833,6 +924,10 @@ void Init_parser(void)
833
924
  i_aset = rb_intern("[]=");
834
925
  i_aref = rb_intern("[]");
835
926
  i_leftshift = rb_intern("<<");
927
+ i_new = rb_intern("new");
928
+ i_try_convert = rb_intern("try_convert");
929
+ i_freeze = rb_intern("freeze");
930
+ i_uminus = rb_intern("-@");
836
931
  }
837
932
 
838
933
  /*
data/ext/json/extconf.rb CHANGED
@@ -1,2 +1,3 @@
1
1
  require 'mkmf'
2
+
2
3
  create_makefile('json')
data/json.gemspec CHANGED
Binary file
@@ -23,7 +23,7 @@ class BigDecimal
23
23
  end
24
24
 
25
25
  # return the JSON value
26
- def to_json(*)
27
- as_json.to_json
26
+ def to_json(*args)
27
+ as_json.to_json(*args)
28
28
  end
29
29
  end
@@ -2,7 +2,6 @@
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
5
- defined?(::Complex) or require 'complex'
6
5
 
7
6
  class Complex
8
7
 
@@ -23,7 +22,7 @@ class Complex
23
22
  end
24
23
 
25
24
  # Stores class name (Complex) along with real value <tt>r</tt> and imaginary value <tt>i</tt> as JSON string
26
- def to_json(*)
27
- as_json.to_json
25
+ def to_json(*args)
26
+ as_json.to_json(*args)
28
27
  end
29
28
  end
@@ -23,7 +23,7 @@ class OpenStruct
23
23
  }
24
24
  end
25
25
 
26
- # Stores class name (OpenStruct) with this struct's values <tt>v</tt> as a
26
+ # Stores class name (OpenStruct) with this struct's values <tt>t</tt> as a
27
27
  # JSON string.
28
28
  def to_json(*args)
29
29
  as_json.to_json(*args)
@@ -2,7 +2,6 @@
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
5
- defined?(::Rational) or require 'rational'
6
5
 
7
6
  class Rational
8
7
  # Deserializes JSON string by converting numerator value <tt>n</tt>,
@@ -22,7 +21,7 @@ class Rational
22
21
  end
23
22
 
24
23
  # Stores class name (Rational) along with numerator value <tt>n</tt> and denominator value <tt>d</tt> as JSON string
25
- def to_json(*)
26
- as_json.to_json
24
+ def to_json(*args)
25
+ as_json.to_json(*args)
27
26
  end
28
27
  end
@@ -24,7 +24,7 @@ class Regexp
24
24
 
25
25
  # Stores class name (Regexp) with options <tt>o</tt> and source <tt>s</tt>
26
26
  # (Regexp or String) as JSON string
27
- def to_json(*)
28
- as_json.to_json
27
+ def to_json(*args)
28
+ as_json.to_json(*args)
29
29
  end
30
30
  end
@@ -0,0 +1,29 @@
1
+ unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
2
+ require 'json'
3
+ end
4
+ defined?(::Set) or require 'set'
5
+
6
+ class Set
7
+ # Import a JSON Marshalled object.
8
+ #
9
+ # method used for JSON marshalling support.
10
+ def self.json_create(object)
11
+ new object['a']
12
+ end
13
+
14
+ # Marshal the object to JSON.
15
+ #
16
+ # method used for JSON marshalling support.
17
+ def as_json(*)
18
+ {
19
+ JSON.create_id => self.class.name,
20
+ 'a' => to_a,
21
+ }
22
+ end
23
+
24
+ # return the JSON value
25
+ def to_json(*args)
26
+ as_json.to_json(*args)
27
+ end
28
+ end
29
+