json 2.1.0 → 2.3.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.
@@ -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;
@@ -89,12 +89,13 @@ static int convert_UTF32_to_UTF8(char *buf, UTF32 ch)
89
89
 
90
90
  static VALUE mJSON, mExt, cParser, eParserError, eNestingError;
91
91
  static VALUE CNaN, CInfinity, CMinusInfinity;
92
+ static VALUE cBigDecimal = Qundef;
92
93
 
93
94
  static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
94
95
  i_chr, i_max_nesting, i_allow_nan, i_symbolize_names,
95
96
  i_object_class, i_array_class, i_decimal_class, i_key_p,
96
97
  i_deep_const_get, i_match, i_match_string, i_aset, i_aref,
97
- i_leftshift, i_new;
98
+ i_leftshift, i_new, i_BigDecimal;
98
99
 
99
100
  %%{
100
101
  machine JSON_common;
@@ -137,6 +138,7 @@ static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
137
138
  fhold; fbreak;
138
139
  } else {
139
140
  if (NIL_P(json->object_class)) {
141
+ OBJ_FREEZE(last_name);
140
142
  rb_hash_aset(*result, last_name, v);
141
143
  } else {
142
144
  rb_funcall(*result, i_aset, 2, last_name, v);
@@ -339,6 +341,19 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res
339
341
  ) (^[0-9Ee.\-]? @exit );
340
342
  }%%
341
343
 
344
+ static int is_bigdecimal_class(VALUE obj)
345
+ {
346
+ if (cBigDecimal == Qundef) {
347
+ if (rb_const_defined(rb_cObject, i_BigDecimal)) {
348
+ cBigDecimal = rb_const_get_at(rb_cObject, i_BigDecimal);
349
+ }
350
+ else {
351
+ return 0;
352
+ }
353
+ }
354
+ return obj == cBigDecimal;
355
+ }
356
+
342
357
  static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result)
343
358
  {
344
359
  int cs = EVIL;
@@ -357,7 +372,11 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
357
372
  } else {
358
373
  VALUE text;
359
374
  text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
360
- *result = rb_funcall(json->decimal_class, i_new, 1, text);
375
+ if (is_bigdecimal_class(json->decimal_class)) {
376
+ *result = rb_funcall(Qnil, i_BigDecimal, 1, text);
377
+ } else {
378
+ *result = rb_funcall(json->decimal_class, i_new, 1, text);
379
+ }
361
380
  }
362
381
  return p + 1;
363
382
  } else {
@@ -553,7 +572,7 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
553
572
 
554
573
  if (json->symbolize_names && json->parsing_name) {
555
574
  *result = rb_str_intern(*result);
556
- } else {
575
+ } else if (RB_TYPE_P(*result, T_STRING)) {
557
576
  rb_str_resize(*result, RSTRING_LEN(*result));
558
577
  }
559
578
  if (cs >= JSON_string_first_final) {
@@ -710,7 +729,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
710
729
  } else {
711
730
  json->max_nesting = 100;
712
731
  json->allow_nan = 0;
713
- json->create_additions = 1;
732
+ json->create_additions = 0;
714
733
  json->create_id = rb_funcall(mJSON, i_create_id, 0);
715
734
  json->object_class = Qnil;
716
735
  json->array_class = Qnil;
@@ -824,20 +843,28 @@ static VALUE cParser_source(VALUE self)
824
843
 
825
844
  void Init_parser(void)
826
845
  {
846
+ #undef rb_intern
827
847
  rb_require("json/common");
828
848
  mJSON = rb_define_module("JSON");
829
849
  mExt = rb_define_module_under(mJSON, "Ext");
830
850
  cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
831
851
  eParserError = rb_path2class("JSON::ParserError");
832
852
  eNestingError = rb_path2class("JSON::NestingError");
853
+ rb_gc_register_mark_object(eParserError);
854
+ rb_gc_register_mark_object(eNestingError);
833
855
  rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
834
856
  rb_define_method(cParser, "initialize", cParser_initialize, -1);
835
857
  rb_define_method(cParser, "parse", cParser_parse, 0);
836
858
  rb_define_method(cParser, "source", cParser_source, 0);
837
859
 
838
860
  CNaN = rb_const_get(mJSON, rb_intern("NaN"));
861
+ rb_gc_register_mark_object(CNaN);
862
+
839
863
  CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
864
+ rb_gc_register_mark_object(CInfinity);
865
+
840
866
  CMinusInfinity = rb_const_get(mJSON, rb_intern("MinusInfinity"));
867
+ rb_gc_register_mark_object(CMinusInfinity);
841
868
 
842
869
  i_json_creatable_p = rb_intern("json_creatable?");
843
870
  i_json_create = rb_intern("json_create");
@@ -858,6 +885,7 @@ void Init_parser(void)
858
885
  i_aref = rb_intern("[]");
859
886
  i_leftshift = rb_intern("<<");
860
887
  i_new = rb_intern("new");
888
+ i_BigDecimal = rb_intern("BigDecimal");
861
889
  }
862
890
 
863
891
  /*
@@ -7,6 +7,7 @@ package json.ext;
7
7
 
8
8
  import org.jruby.Ruby;
9
9
  import org.jruby.RubyArray;
10
+ import org.jruby.RubyBasicObject;
10
11
  import org.jruby.RubyBignum;
11
12
  import org.jruby.RubyBoolean;
12
13
  import org.jruby.RubyClass;
@@ -15,6 +16,7 @@ import org.jruby.RubyFloat;
15
16
  import org.jruby.RubyHash;
16
17
  import org.jruby.RubyNumeric;
17
18
  import org.jruby.RubyString;
19
+ import org.jruby.runtime.ClassIndex;
18
20
  import org.jruby.runtime.ThreadContext;
19
21
  import org.jruby.runtime.builtin.IRubyObject;
20
22
  import org.jruby.util.ByteList;
@@ -57,6 +59,19 @@ public final class Generator {
57
59
  return handler.generateNew(session, object);
58
60
  }
59
61
 
62
+ // NOTE: drop this once Ruby 1.9.3 support is gone!
63
+ private static final int FIXNUM = 1;
64
+ private static final int BIGNUM = 2;
65
+ private static final int ARRAY = 3;
66
+ private static final int STRING = 4;
67
+ private static final int NIL = 5;
68
+ private static final int TRUE = 6;
69
+ private static final int FALSE = 7;
70
+ private static final int HASH = 10;
71
+ private static final int FLOAT = 11;
72
+ // hard-coded due JRuby 1.7 compatibility
73
+ // https://github.com/jruby/jruby/blob/1.7.27/core/src/main/java/org/jruby/runtime/ClassIndex.java
74
+
60
75
  /**
61
76
  * Returns the best serialization handler for the given object.
62
77
  */
@@ -65,16 +80,24 @@ public final class Generator {
65
80
  @SuppressWarnings("unchecked")
66
81
  private static <T extends IRubyObject>
67
82
  Handler<? super T> getHandlerFor(Ruby runtime, T object) {
68
- RubyClass metaClass = object.getMetaClass();
69
- if (metaClass == runtime.getString()) return (Handler)STRING_HANDLER;
70
- if (metaClass == runtime.getFixnum()) return (Handler)FIXNUM_HANDLER;
71
- if (metaClass == runtime.getHash()) return (Handler)HASH_HANDLER;
72
- if (metaClass == runtime.getArray()) return (Handler)ARRAY_HANDLER;
73
- if (object.isNil()) return (Handler)NIL_HANDLER;
74
- if (object == runtime.getTrue()) return (Handler)TRUE_HANDLER;
75
- if (object == runtime.getFalse()) return (Handler)FALSE_HANDLER;
76
- if (metaClass == runtime.getFloat()) return (Handler)FLOAT_HANDLER;
77
- if (metaClass == runtime.getBignum()) return (Handler)BIGNUM_HANDLER;
83
+ switch (((RubyBasicObject) object).getNativeTypeIndex()) {
84
+ // can not use getNativeClassIndex due 1.7 compatibility
85
+ case NIL : return (Handler) NIL_HANDLER;
86
+ case TRUE : return (Handler) TRUE_HANDLER;
87
+ case FALSE : return (Handler) FALSE_HANDLER;
88
+ case FLOAT : return (Handler) FLOAT_HANDLER;
89
+ case FIXNUM : return (Handler) FIXNUM_HANDLER;
90
+ case BIGNUM : return (Handler) BIGNUM_HANDLER;
91
+ case STRING :
92
+ if (((RubyBasicObject) object).getMetaClass() != runtime.getString()) break;
93
+ return (Handler) STRING_HANDLER;
94
+ case ARRAY :
95
+ if (((RubyBasicObject) object).getMetaClass() != runtime.getArray()) break;
96
+ return (Handler) ARRAY_HANDLER;
97
+ case HASH :
98
+ if (((RubyBasicObject) object).getMetaClass() != runtime.getHash()) break;
99
+ return (Handler) HASH_HANDLER;
100
+ }
78
101
  return GENERIC_HANDLER;
79
102
  }
80
103
 
@@ -55,7 +55,7 @@ public class Parser extends RubyObject {
55
55
  private RubyClass objectClass;
56
56
  private RubyClass arrayClass;
57
57
  private RubyClass decimalClass;
58
- private RubyHash matchString;
58
+ private RubyHash match_string;
59
59
 
60
60
  private static final int DEFAULT_MAX_NESTING = 100;
61
61
 
@@ -165,7 +165,7 @@ public class Parser extends RubyObject {
165
165
  this.objectClass = opts.getClass("object_class", runtime.getHash());
166
166
  this.arrayClass = opts.getClass("array_class", runtime.getArray());
167
167
  this.decimalClass = opts.getClass("decimal_class", null);
168
- this.matchString = opts.getHash("match_string");
168
+ this.match_string = opts.getHash("match_string");
169
169
 
170
170
  if(symbolizeNames && createAdditions) {
171
171
  throw runtime.newArgumentError(
@@ -1437,7 +1437,7 @@ case 5:
1437
1437
  // line 608 "Parser.rl"
1438
1438
 
1439
1439
  if (parser.createAdditions) {
1440
- RubyHash matchString = parser.matchString;
1440
+ RubyHash matchString = parser.match_string;
1441
1441
  if (matchString != null) {
1442
1442
  final IRubyObject[] memoArray = { result, null };
1443
1443
  try {
@@ -607,7 +607,7 @@ public class Parser extends RubyObject {
607
607
  %% write exec;
608
608
 
609
609
  if (parser.createAdditions) {
610
- RubyHash matchString = parser.matchString;
610
+ RubyHash matchString = parser.match_string;
611
611
  if (matchString != null) {
612
612
  final IRubyObject[] memoArray = { result, null };
613
613
  try {
@@ -8,9 +8,8 @@ spec = Gem::Specification.new do |s|
8
8
  s.description = "A JSON implementation as a JRuby extension."
9
9
  s.author = "Daniel Luz"
10
10
  s.email = "dev+ruby@mernen.com"
11
- s.homepage = "http://json-jruby.rubyforge.org/"
11
+ s.homepage = "http://flori.github.com/json"
12
12
  s.platform = 'java'
13
- s.rubyforge_project = "json-jruby"
14
13
  s.licenses = ["Ruby"]
15
14
 
16
15
  s.files = Dir["{docs,lib,tests}/**/*"]
@@ -20,14 +19,14 @@ spec = Gem::Specification.new do |s|
20
19
 
21
20
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
22
21
  s.add_development_dependency(%q<rake>, [">= 0"])
23
- s.add_development_dependency(%q<test-unit>, ["~> 2.0"])
22
+ s.add_development_dependency(%q<test-unit>, [">= 2.0", "< 4.0"])
24
23
  else
25
24
  s.add_dependency(%q<rake>, [">= 0"])
26
- s.add_dependency(%q<test-unit>, ["~> 2.0"])
25
+ s.add_dependency(%q<test-unit>, [">= 2.0", "< 4.0"])
27
26
  end
28
27
  else
29
28
  s.add_dependency(%q<rake>, [">= 0"])
30
- s.add_dependency(%q<test-unit>, ["~> 2.0"])
29
+ s.add_dependency(%q<test-unit>, [">= 2.0", "< 4.0"])
31
30
  end
32
31
  end
33
32
 
Binary file
@@ -1,38 +1,33 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: json_pure 2.1.0 ruby lib
3
2
 
4
3
  Gem::Specification.new do |s|
5
4
  s.name = "json_pure".freeze
6
- s.version = "2.1.0"
5
+ s.version = File.read("VERSION").chomp
7
6
 
8
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
8
  s.require_paths = ["lib".freeze]
10
9
  s.authors = ["Florian Frank".freeze]
11
- s.date = "2017-04-18"
12
10
  s.description = "This is a JSON implementation in pure Ruby.".freeze
13
11
  s.email = "flori@ping.de".freeze
14
12
  s.extra_rdoc_files = ["README.md".freeze]
15
- s.files = ["./tests/test_helper.rb".freeze, ".gitignore".freeze, ".travis.yml".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "README-json-jruby.md".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "data/example.json".freeze, "data/index.html".freeze, "data/prototype.js".freeze, "diagrams/.keep".freeze, "ext/json/ext/fbuffer/fbuffer.h".freeze, "ext/json/ext/generator/depend".freeze, "ext/json/ext/generator/extconf.rb".freeze, "ext/json/ext/generator/generator.c".freeze, "ext/json/ext/generator/generator.h".freeze, "ext/json/ext/parser/depend".freeze, "ext/json/ext/parser/extconf.rb".freeze, "ext/json/ext/parser/parser.c".freeze, "ext/json/ext/parser/parser.h".freeze, "ext/json/ext/parser/parser.rl".freeze, "ext/json/extconf.rb".freeze, "install.rb".freeze, "java/src/json/ext/ByteListTranscoder.java".freeze, "java/src/json/ext/Generator.java".freeze, "java/src/json/ext/GeneratorMethods.java".freeze, "java/src/json/ext/GeneratorService.java".freeze, "java/src/json/ext/GeneratorState.java".freeze, "java/src/json/ext/OptionsReader.java".freeze, "java/src/json/ext/Parser.java".freeze, "java/src/json/ext/Parser.rl".freeze, "java/src/json/ext/ParserService.java".freeze, "java/src/json/ext/RuntimeInfo.java".freeze, "java/src/json/ext/StringDecoder.java".freeze, "java/src/json/ext/StringEncoder.java".freeze, "java/src/json/ext/Utils.java".freeze, "json-java.gemspec".freeze, "json.gemspec".freeze, "json_pure.gemspec".freeze, "lib/json.rb".freeze, "lib/json/add/bigdecimal.rb".freeze, "lib/json/add/complex.rb".freeze, "lib/json/add/core.rb".freeze, "lib/json/add/date.rb".freeze, "lib/json/add/date_time.rb".freeze, "lib/json/add/exception.rb".freeze, "lib/json/add/ostruct.rb".freeze, "lib/json/add/range.rb".freeze, "lib/json/add/rational.rb".freeze, "lib/json/add/regexp.rb".freeze, "lib/json/add/struct.rb".freeze, "lib/json/add/symbol.rb".freeze, "lib/json/add/time.rb".freeze, "lib/json/common.rb".freeze, "lib/json/ext.rb".freeze, "lib/json/ext/.keep".freeze, "lib/json/generic_object.rb".freeze, "lib/json/pure.rb".freeze, "lib/json/pure/generator.rb".freeze, "lib/json/pure/parser.rb".freeze, "lib/json/version.rb".freeze, "references/rfc7159.txt".freeze, "tests/fixtures/fail10.json".freeze, "tests/fixtures/fail11.json".freeze, "tests/fixtures/fail12.json".freeze, "tests/fixtures/fail13.json".freeze, "tests/fixtures/fail14.json".freeze, "tests/fixtures/fail18.json".freeze, "tests/fixtures/fail19.json".freeze, "tests/fixtures/fail2.json".freeze, "tests/fixtures/fail20.json".freeze, "tests/fixtures/fail21.json".freeze, "tests/fixtures/fail22.json".freeze, "tests/fixtures/fail23.json".freeze, "tests/fixtures/fail24.json".freeze, "tests/fixtures/fail25.json".freeze, "tests/fixtures/fail27.json".freeze, "tests/fixtures/fail28.json".freeze, "tests/fixtures/fail3.json".freeze, "tests/fixtures/fail4.json".freeze, "tests/fixtures/fail5.json".freeze, "tests/fixtures/fail6.json".freeze, "tests/fixtures/fail7.json".freeze, "tests/fixtures/fail8.json".freeze, "tests/fixtures/fail9.json".freeze, "tests/fixtures/obsolete_fail1.json".freeze, "tests/fixtures/pass1.json".freeze, "tests/fixtures/pass15.json".freeze, "tests/fixtures/pass16.json".freeze, "tests/fixtures/pass17.json".freeze, "tests/fixtures/pass2.json".freeze, "tests/fixtures/pass26.json".freeze, "tests/fixtures/pass3.json".freeze, "tests/json_addition_test.rb".freeze, "tests/json_common_interface_test.rb".freeze, "tests/json_encoding_test.rb".freeze, "tests/json_ext_parser_test.rb".freeze, "tests/json_fixtures_test.rb".freeze, "tests/json_generator_test.rb".freeze, "tests/json_generic_object_test.rb".freeze, "tests/json_parser_test.rb".freeze, "tests/json_string_matching_test.rb".freeze, "tests/test_helper.rb".freeze, "tools/diff.sh".freeze, "tools/fuzz.rb".freeze, "tools/server.rb".freeze]
13
+ s.files = ["./tests/test_helper.rb".freeze, ".gitignore".freeze, ".travis.yml".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README-json-jruby.md".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "diagrams/.keep".freeze, "ext/json/ext/fbuffer/fbuffer.h".freeze, "ext/json/ext/generator/depend".freeze, "ext/json/ext/generator/extconf.rb".freeze, "ext/json/ext/generator/generator.c".freeze, "ext/json/ext/generator/generator.h".freeze, "ext/json/ext/parser/depend".freeze, "ext/json/ext/parser/extconf.rb".freeze, "ext/json/ext/parser/parser.c".freeze, "ext/json/ext/parser/parser.h".freeze, "ext/json/ext/parser/parser.rl".freeze, "ext/json/extconf.rb".freeze, "install.rb".freeze, "java/src/json/ext/ByteListTranscoder.java".freeze, "java/src/json/ext/Generator.java".freeze, "java/src/json/ext/GeneratorMethods.java".freeze, "java/src/json/ext/GeneratorService.java".freeze, "java/src/json/ext/GeneratorState.java".freeze, "java/src/json/ext/OptionsReader.java".freeze, "java/src/json/ext/Parser.java".freeze, "java/src/json/ext/Parser.rl".freeze, "java/src/json/ext/ParserService.java".freeze, "java/src/json/ext/RuntimeInfo.java".freeze, "java/src/json/ext/StringDecoder.java".freeze, "java/src/json/ext/StringEncoder.java".freeze, "java/src/json/ext/Utils.java".freeze, "json-java.gemspec".freeze, "json.gemspec".freeze, "json_pure.gemspec".freeze, "lib/json.rb".freeze, "lib/json/add/bigdecimal.rb".freeze, "lib/json/add/complex.rb".freeze, "lib/json/add/core.rb".freeze, "lib/json/add/date.rb".freeze, "lib/json/add/date_time.rb".freeze, "lib/json/add/exception.rb".freeze, "lib/json/add/ostruct.rb".freeze, "lib/json/add/range.rb".freeze, "lib/json/add/rational.rb".freeze, "lib/json/add/regexp.rb".freeze, "lib/json/add/set.rb".freeze, "lib/json/add/struct.rb".freeze, "lib/json/add/symbol.rb".freeze, "lib/json/add/time.rb".freeze, "lib/json/common.rb".freeze, "lib/json/ext.rb".freeze, "lib/json/ext/.keep".freeze, "lib/json/generic_object.rb".freeze, "lib/json/pure.rb".freeze, "lib/json/pure/generator.rb".freeze, "lib/json/pure/parser.rb".freeze, "lib/json/version.rb".freeze, "references/rfc7159.txt".freeze, "tests/fixtures/fail10.json".freeze, "tests/fixtures/fail11.json".freeze, "tests/fixtures/fail12.json".freeze, "tests/fixtures/fail13.json".freeze, "tests/fixtures/fail14.json".freeze, "tests/fixtures/fail18.json".freeze, "tests/fixtures/fail19.json".freeze, "tests/fixtures/fail2.json".freeze, "tests/fixtures/fail20.json".freeze, "tests/fixtures/fail21.json".freeze, "tests/fixtures/fail22.json".freeze, "tests/fixtures/fail23.json".freeze, "tests/fixtures/fail24.json".freeze, "tests/fixtures/fail25.json".freeze, "tests/fixtures/fail27.json".freeze, "tests/fixtures/fail28.json".freeze, "tests/fixtures/fail3.json".freeze, "tests/fixtures/fail4.json".freeze, "tests/fixtures/fail5.json".freeze, "tests/fixtures/fail6.json".freeze, "tests/fixtures/fail7.json".freeze, "tests/fixtures/fail8.json".freeze, "tests/fixtures/fail9.json".freeze, "tests/fixtures/obsolete_fail1.json".freeze, "tests/fixtures/pass1.json".freeze, "tests/fixtures/pass15.json".freeze, "tests/fixtures/pass16.json".freeze, "tests/fixtures/pass17.json".freeze, "tests/fixtures/pass2.json".freeze, "tests/fixtures/pass26.json".freeze, "tests/fixtures/pass3.json".freeze, "tests/json_addition_test.rb".freeze, "tests/json_common_interface_test.rb".freeze, "tests/json_encoding_test.rb".freeze, "tests/json_ext_parser_test.rb".freeze, "tests/json_fixtures_test.rb".freeze, "tests/json_generator_test.rb".freeze, "tests/json_generic_object_test.rb".freeze, "tests/json_parser_test.rb".freeze, "tests/json_string_matching_test.rb".freeze, "tests/test_helper.rb".freeze, "tools/diff.sh".freeze, "tools/fuzz.rb".freeze, "tools/server.rb".freeze]
16
14
  s.homepage = "http://flori.github.com/json".freeze
17
15
  s.licenses = ["Ruby".freeze]
18
16
  s.rdoc_options = ["--title".freeze, "JSON implemention for ruby".freeze, "--main".freeze, "README.md".freeze]
19
- s.required_ruby_version = Gem::Requirement.new(">= 1.9".freeze)
20
- s.rubygems_version = "2.6.11".freeze
17
+ s.required_ruby_version = Gem::Requirement.new(">= 2.0".freeze)
18
+ s.rubygems_version = "3.1.2".freeze
21
19
  s.summary = "JSON Implementation for Ruby".freeze
22
20
  s.test_files = ["./tests/test_helper.rb".freeze]
23
21
 
24
22
  if s.respond_to? :specification_version then
25
23
  s.specification_version = 4
24
+ end
26
25
 
27
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
28
- s.add_development_dependency(%q<rake>.freeze, [">= 0"])
29
- s.add_development_dependency(%q<test-unit>.freeze, ["~> 2.0"])
30
- else
31
- s.add_dependency(%q<rake>.freeze, [">= 0"])
32
- s.add_dependency(%q<test-unit>.freeze, ["~> 2.0"])
33
- end
26
+ if s.respond_to? :add_runtime_dependency then
27
+ s.add_development_dependency(%q<rake>.freeze, [">= 0"])
28
+ s.add_development_dependency(%q<test-unit>.freeze, [">= 2.0", "< 4.0"])
34
29
  else
35
30
  s.add_dependency(%q<rake>.freeze, [">= 0"])
36
- s.add_dependency(%q<test-unit>.freeze, ["~> 2.0"])
31
+ s.add_dependency(%q<test-unit>.freeze, [">= 2.0", "< 4.0"])
37
32
  end
38
33
  end
@@ -2,55 +2,404 @@
2
2
  require 'json/common'
3
3
 
4
4
  ##
5
- # = JavaScript Object Notation (JSON)
5
+ # = JavaScript \Object Notation (\JSON)
6
6
  #
7
- # JSON is a lightweight data-interchange format. It is easy for us
8
- # humans to read and write. Plus, equally simple for machines to generate or parse.
9
- # JSON is completely language agnostic, making it the ideal interchange format.
7
+ # \JSON is a lightweight data-interchange format.
10
8
  #
11
- # Built on two universally available structures:
12
- # 1. A collection of name/value pairs. Often referred to as an _object_, hash table, record, struct, keyed list, or associative array.
13
- # 2. An ordered list of values. More commonly called an _array_, vector, sequence or list.
9
+ # A \JSON value is one of the following:
10
+ # - Double-quoted text: <tt>"foo"</tt>.
11
+ # - Number: +1+, +1.0+, +2.0e2+.
12
+ # - Boolean: +true+, +false+.
13
+ # - Null: +null+.
14
+ # - \Array: an ordered list of values, enclosed by square brackets:
15
+ # ["foo", 1, 1.0, 2.0e2, true, false, null]
14
16
  #
15
- # To read more about JSON visit: http://json.org
17
+ # - \Object: a collection of name/value pairs, enclosed by curly braces;
18
+ # each name is double-quoted text;
19
+ # the values may be any \JSON values:
20
+ # {"a": "foo", "b": 1, "c": 1.0, "d": 2.0e2, "e": true, "f": false, "g": null}
16
21
  #
17
- # == Parsing JSON
22
+ # A \JSON array or object may contain nested arrays, objects, and scalars
23
+ # to any depth:
24
+ # {"foo": {"bar": 1, "baz": 2}, "bat": [0, 1, 2]}
25
+ # [{"foo": 0, "bar": 1}, ["baz", 2]]
18
26
  #
19
- # To parse a JSON string received by another application or generated within
20
- # your existing application:
27
+ # == Using \Module \JSON
21
28
  #
29
+ # To make module \JSON available in your code, begin with:
22
30
  # require 'json'
23
31
  #
24
- # my_hash = JSON.parse('{"hello": "goodbye"}')
25
- # puts my_hash["hello"] => "goodbye"
32
+ # All examples here assume that this has been done.
26
33
  #
27
- # Notice the extra quotes <tt>''</tt> around the hash notation. Ruby expects
28
- # the argument to be a string and can't convert objects like a hash or array.
34
+ # === Parsing \JSON
29
35
  #
30
- # Ruby converts your string into a hash
36
+ # You can parse a \String containing \JSON data using
37
+ # either of two methods:
38
+ # - <tt>JSON.parse(source, opts)</tt>
39
+ # - <tt>JSON.parse!(source, opts)</tt>
31
40
  #
32
- # == Generating JSON
41
+ # where
42
+ # - +source+ is a Ruby object.
43
+ # - +opts+ is a \Hash object containing options
44
+ # that control both input allowed and output formatting.
33
45
  #
34
- # Creating a JSON string for communication or serialization is
35
- # just as simple.
46
+ # The difference between the two methods
47
+ # is that JSON.parse! omits some checks
48
+ # and may not be safe for some +source+ data;
49
+ # use it only for data from trusted sources.
50
+ # Use the safer method JSON.parse for less trusted sources.
36
51
  #
37
- # require 'json'
52
+ # ==== Parsing \JSON Arrays
38
53
  #
39
- # my_hash = {:hello => "goodbye"}
40
- # puts JSON.generate(my_hash) => "{\"hello\":\"goodbye\"}"
54
+ # When +source+ is a \JSON array, JSON.parse by default returns a Ruby \Array:
55
+ # json = '["foo", 1, 1.0, 2.0e2, true, false, null]'
56
+ # ruby = JSON.parse(json)
57
+ # ruby # => ["foo", 1, 1.0, 200.0, true, false, nil]
58
+ # ruby.class # => Array
41
59
  #
42
- # Or an alternative way:
60
+ # The \JSON array may contain nested arrays, objects, and scalars
61
+ # to any depth:
62
+ # json = '[{"foo": 0, "bar": 1}, ["baz", 2]]'
63
+ # JSON.parse(json) # => [{"foo"=>0, "bar"=>1}, ["baz", 2]]
43
64
  #
44
- # require 'json'
45
- # puts {:hello => "goodbye"}.to_json => "{\"hello\":\"goodbye\"}"
65
+ # ==== Parsing \JSON \Objects
66
+ #
67
+ # When the source is a \JSON object, JSON.parse by default returns a Ruby \Hash:
68
+ # json = '{"a": "foo", "b": 1, "c": 1.0, "d": 2.0e2, "e": true, "f": false, "g": null}'
69
+ # ruby = JSON.parse(json)
70
+ # ruby # => {"a"=>"foo", "b"=>1, "c"=>1.0, "d"=>200.0, "e"=>true, "f"=>false, "g"=>nil}
71
+ # ruby.class # => Hash
72
+ #
73
+ # The \JSON object may contain nested arrays, objects, and scalars
74
+ # to any depth:
75
+ # json = '{"foo": {"bar": 1, "baz": 2}, "bat": [0, 1, 2]}'
76
+ # JSON.parse(json) # => {"foo"=>{"bar"=>1, "baz"=>2}, "bat"=>[0, 1, 2]}
77
+ #
78
+ # ==== Parsing \JSON Scalars
79
+ #
80
+ # When the source is a \JSON scalar (not an array or object),
81
+ # JSON.parse returns a Ruby scalar.
82
+ #
83
+ # \String:
84
+ # ruby = JSON.parse('"foo"')
85
+ # ruby # => 'foo'
86
+ # ruby.class # => String
87
+ # \Integer:
88
+ # ruby = JSON.parse('1')
89
+ # ruby # => 1
90
+ # ruby.class # => Integer
91
+ # \Float:
92
+ # ruby = JSON.parse('1.0')
93
+ # ruby # => 1.0
94
+ # ruby.class # => Float
95
+ # ruby = JSON.parse('2.0e2')
96
+ # ruby # => 200
97
+ # ruby.class # => Float
98
+ # Boolean:
99
+ # ruby = JSON.parse('true')
100
+ # ruby # => true
101
+ # ruby.class # => TrueClass
102
+ # ruby = JSON.parse('false')
103
+ # ruby # => false
104
+ # ruby.class # => FalseClass
105
+ # Null:
106
+ # ruby = JSON.parse('null')
107
+ # ruby # => nil
108
+ # ruby.class # => NilClass
109
+ #
110
+ # === Generating \JSON
111
+ #
112
+ # To generate a Ruby \String containing \JSON data,
113
+ # use method <tt>JSON.generate(source, opts)</tt>, where
114
+ # - +source+ is a Ruby object.
115
+ # - +opts+ is a \Hash object containing options
116
+ # that control both input allowed and output formatting.
117
+ #
118
+ # ==== Generating \JSON from Arrays
119
+ #
120
+ # When the source is a Ruby \Array, JSON.generate returns
121
+ # a \String containing a \JSON array:
122
+ # ruby = [0, 's', :foo]
123
+ # json = JSON.generate(ruby)
124
+ # json # => '[0,"s","foo"]'
125
+ #
126
+ # The Ruby \Array array may contain nested arrays, hashes, and scalars
127
+ # to any depth:
128
+ # ruby = [0, [1, 2], {foo: 3, bar: 4}]
129
+ # json = JSON.generate(ruby)
130
+ # json # => '[0,[1,2],{"foo":3,"bar":4}]'
131
+ #
132
+ # ==== Generating \JSON from Hashes
133
+ #
134
+ # When the source is a Ruby \Hash, JSON.generate returns
135
+ # a \String containing a \JSON object:
136
+ # ruby = {foo: 0, bar: 's', baz: :bat}
137
+ # json = JSON.generate(ruby)
138
+ # json # => '{"foo":0,"bar":"s","baz":"bat"}'
139
+ #
140
+ # The Ruby \Hash array may contain nested arrays, hashes, and scalars
141
+ # to any depth:
142
+ # ruby = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad}
143
+ # json = JSON.generate(ruby)
144
+ # json # => '{"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}'
145
+ #
146
+ # ==== Generating \JSON from Other Objects
147
+ #
148
+ # When the source is neither an \Array nor a \Hash,
149
+ # the generated \JSON data depends on the class of the source.
150
+ #
151
+ # When the source is a Ruby \Integer or \Float, JSON.generate returns
152
+ # a \String containing a \JSON number:
153
+ # JSON.generate(42) # => '42'
154
+ # JSON.generate(0.42) # => '0.42'
155
+ #
156
+ # When the source is a Ruby \String, JSON.generate returns
157
+ # a \String containing a \JSON string (with double-quotes):
158
+ # JSON.generate('A string') # => '"A string"'
159
+ #
160
+ # When the source is +true+, +false+ or +nil+, JSON.generate returns
161
+ # a \String containing the corresponding \JSON token:
162
+ # JSON.generate(true) # => 'true'
163
+ # JSON.generate(false) # => 'false'
164
+ # JSON.generate(nil) # => 'null'
165
+ #
166
+ # When the source is none of the above, JSON.generate returns
167
+ # a \String containing a \JSON string representation of the source:
168
+ # JSON.generate(:foo) # => '"foo"'
169
+ # JSON.generate(Complex(0, 0)) # => '"0+0i"'
170
+ # JSON.generate(Dir.new('.')) # => '"#<Dir>"'
171
+ #
172
+ # == \JSON Additions
173
+ #
174
+ # When you "round trip" a non-\String object from Ruby to \JSON and back,
175
+ # you have a new \String, instead of the object you began with:
176
+ # ruby0 = Range.new(0, 2)
177
+ # json = JSON.generate(ruby0)
178
+ # json # => '0..2"'
179
+ # ruby1 = JSON.parse(json)
180
+ # ruby1 # => '0..2'
181
+ # ruby1.class # => String
182
+ #
183
+ # You can use \JSON _additions_ to preserve the original object.
184
+ # The addition is an extension of a ruby class, so that:
185
+ # - \JSON.generate stores more information in the \JSON string.
186
+ # - \JSON.parse, called with option +create_additions+,
187
+ # uses that information to create a proper Ruby object.
46
188
  #
47
- # <tt>JSON.generate</tt> only allows objects or arrays to be converted
48
- # to JSON syntax. <tt>to_json</tt>, however, accepts many Ruby classes
49
- # even though it acts only as a method for serialization:
189
+ # This example shows a \Range being generated into \JSON
190
+ # and parsed back into Ruby, both without and with
191
+ # the addition for \Range:
192
+ # ruby = Range.new(0, 2)
193
+ # # This passage does not use the addition for Range.
194
+ # json0 = JSON.generate(ruby)
195
+ # ruby0 = JSON.parse(json0)
196
+ # # This passage uses the addition for Range.
197
+ # require 'json/add/range'
198
+ # json1 = JSON.generate(ruby)
199
+ # ruby1 = JSON.parse(json1, create_additions: true)
200
+ # # Make a nice display.
201
+ # display = <<EOT
202
+ # Generated JSON:
203
+ # Without addition: #{json0} (#{json0.class})
204
+ # With addition: #{json1} (#{json1.class})
205
+ # Parsed JSON:
206
+ # Without addition: #{ruby0.inspect} (#{ruby0.class})
207
+ # With addition: #{ruby1.inspect} (#{ruby1.class})
208
+ # EOT
209
+ # puts display
50
210
  #
211
+ # This output shows the different results:
212
+ # Generated JSON:
213
+ # Without addition: "0..2" (String)
214
+ # With addition: {"json_class":"Range","a":[0,2,false]} (String)
215
+ # Parsed JSON:
216
+ # Without addition: "0..2" (String)
217
+ # With addition: 0..2 (Range)
218
+ #
219
+ # The \JSON module includes additions for certain classes.
220
+ # You can also craft custom additions.
221
+ # See {Custom \JSON Additions}[#module-JSON-label-Custom+JSON+Additions].
222
+ #
223
+ # === Built-in Additions
224
+ #
225
+ # The \JSON module includes additions for certain classes.
226
+ # To use an addition, +require+ its source:
227
+ # - BigDecimal: <tt>require 'json/add/bigdecimal'</tt>
228
+ # - Complex: <tt>require 'json/add/complex'</tt>
229
+ # - Date: <tt>require 'json/add/date'</tt>
230
+ # - DateTime: <tt>require 'json/add/date_time'</tt>
231
+ # - Exception: <tt>require 'json/add/exception'</tt>
232
+ # - OpenStruct: <tt>require 'json/add/ostruct'</tt>
233
+ # - Range: <tt>require 'json/add/range'</tt>
234
+ # - Rational: <tt>require 'json/add/rational'</tt>
235
+ # - Regexp: <tt>require 'json/add/regexp'</tt>
236
+ # - Set: <tt>require 'json/add/set'</tt>
237
+ # - Struct: <tt>require 'json/add/struct'</tt>
238
+ # - Symbol: <tt>require 'json/add/symbol'</tt>
239
+ # - Time: <tt>require 'json/add/time'</tt>
240
+ #
241
+ # To reduce punctuation clutter, the examples below
242
+ # show the generated \JSON via +puts+, rather than the usual +inspect+,
243
+ #
244
+ # \BigDecimal:
245
+ # require 'json/add/bigdecimal'
246
+ # ruby0 = BigDecimal(0) # 0.0
247
+ # json = JSON.generate(ruby0) # {"json_class":"BigDecimal","b":"27:0.0"}
248
+ # ruby1 = JSON.parse(json, create_additions: true) # 0.0
249
+ # ruby1.class # => BigDecimal
250
+ #
251
+ # \Complex:
252
+ # require 'json/add/complex'
253
+ # ruby0 = Complex(1+0i) # 1+0i
254
+ # json = JSON.generate(ruby0) # {"json_class":"Complex","r":1,"i":0}
255
+ # ruby1 = JSON.parse(json, create_additions: true) # 1+0i
256
+ # ruby1.class # Complex
257
+ #
258
+ # \Date:
259
+ # require 'json/add/date'
260
+ # ruby0 = Date.today # 2020-05-02
261
+ # json = JSON.generate(ruby0) # {"json_class":"Date","y":2020,"m":5,"d":2,"sg":2299161.0}
262
+ # ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02
263
+ # ruby1.class # Date
264
+ #
265
+ # \DateTime:
266
+ # require 'json/add/date_time'
267
+ # ruby0 = DateTime.now # 2020-05-02T10:38:13-05:00
268
+ # json = JSON.generate(ruby0) # {"json_class":"DateTime","y":2020,"m":5,"d":2,"H":10,"M":38,"S":13,"of":"-5/24","sg":2299161.0}
269
+ # ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02T10:38:13-05:00
270
+ # ruby1.class # DateTime
271
+ #
272
+ # \Exception (and its subclasses including \RuntimeError):
273
+ # require 'json/add/exception'
274
+ # ruby0 = Exception.new('A message') # A message
275
+ # json = JSON.generate(ruby0) # {"json_class":"Exception","m":"A message","b":null}
276
+ # ruby1 = JSON.parse(json, create_additions: true) # A message
277
+ # ruby1.class # Exception
278
+ # ruby0 = RuntimeError.new('Another message') # Another message
279
+ # json = JSON.generate(ruby0) # {"json_class":"RuntimeError","m":"Another message","b":null}
280
+ # ruby1 = JSON.parse(json, create_additions: true) # Another message
281
+ # ruby1.class # RuntimeError
282
+ #
283
+ # \OpenStruct:
284
+ # require 'json/add/ostruct'
285
+ # ruby0 = OpenStruct.new(name: 'Matz', language: 'Ruby') # #<OpenStruct name="Matz", language="Ruby">
286
+ # json = JSON.generate(ruby0) # {"json_class":"OpenStruct","t":{"name":"Matz","language":"Ruby"}}
287
+ # ruby1 = JSON.parse(json, create_additions: true) # #<OpenStruct name="Matz", language="Ruby">
288
+ # ruby1.class # OpenStruct
289
+ #
290
+ # \Range:
291
+ # require 'json/add/range'
292
+ # ruby0 = Range.new(0, 2) # 0..2
293
+ # json = JSON.generate(ruby0) # {"json_class":"Range","a":[0,2,false]}
294
+ # ruby1 = JSON.parse(json, create_additions: true) # 0..2
295
+ # ruby1.class # Range
296
+ #
297
+ # \Rational:
298
+ # require 'json/add/rational'
299
+ # ruby0 = Rational(1, 3) # 1/3
300
+ # json = JSON.generate(ruby0) # {"json_class":"Rational","n":1,"d":3}
301
+ # ruby1 = JSON.parse(json, create_additions: true) # 1/3
302
+ # ruby1.class # Rational
303
+ #
304
+ # \Regexp:
305
+ # require 'json/add/regexp'
306
+ # ruby0 = Regexp.new('foo') # (?-mix:foo)
307
+ # json = JSON.generate(ruby0) # {"json_class":"Regexp","o":0,"s":"foo"}
308
+ # ruby1 = JSON.parse(json, create_additions: true) # (?-mix:foo)
309
+ # ruby1.class # Regexp
310
+ #
311
+ # \Set:
312
+ # require 'json/add/set'
313
+ # ruby0 = Set.new([0, 1, 2]) # #<Set: {0, 1, 2}>
314
+ # json = JSON.generate(ruby0) # {"json_class":"Set","a":[0,1,2]}
315
+ # ruby1 = JSON.parse(json, create_additions: true) # #<Set: {0, 1, 2}>
316
+ # ruby1.class # Set
317
+ #
318
+ # \Struct:
319
+ # require 'json/add/struct'
320
+ # Customer = Struct.new(:name, :address) # Customer
321
+ # ruby0 = Customer.new("Dave", "123 Main") # #<struct Customer name="Dave", address="123 Main">
322
+ # json = JSON.generate(ruby0) # {"json_class":"Customer","v":["Dave","123 Main"]}
323
+ # ruby1 = JSON.parse(json, create_additions: true) # #<struct Customer name="Dave", address="123 Main">
324
+ # ruby1.class # Customer
325
+ #
326
+ # \Symbol:
327
+ # require 'json/add/symbol'
328
+ # ruby0 = :foo # foo
329
+ # json = JSON.generate(ruby0) # {"json_class":"Symbol","s":"foo"}
330
+ # ruby1 = JSON.parse(json, create_additions: true) # foo
331
+ # ruby1.class # Symbol
332
+ #
333
+ # \Time:
334
+ # require 'json/add/time'
335
+ # ruby0 = Time.now # 2020-05-02 11:28:26 -0500
336
+ # json = JSON.generate(ruby0) # {"json_class":"Time","s":1588436906,"n":840560000}
337
+ # ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02 11:28:26 -0500
338
+ # ruby1.class # Time
339
+ #
340
+ #
341
+ # === Custom \JSON Additions
342
+ #
343
+ # In addition to the \JSON additions provided,
344
+ # you can craft \JSON additions of your own,
345
+ # either for Ruby built-in classes or for user-defined classes.
346
+ #
347
+ # Here's a user-defined class +Foo+:
348
+ # class Foo
349
+ # attr_accessor :bar, :baz
350
+ # def initialize(bar, baz)
351
+ # self.bar = bar
352
+ # self.baz = baz
353
+ # end
354
+ # end
355
+ #
356
+ # Here's the \JSON addition for it:
357
+ # # Extend class Foo with JSON addition.
358
+ # class Foo
359
+ # # Serialize Foo object with its class name and arguments
360
+ # def to_json(*args)
361
+ # {
362
+ # JSON.create_id => self.class.name,
363
+ # 'a' => [ bar, baz ]
364
+ # }.to_json(*args)
365
+ # end
366
+ # # Deserialize JSON string by constructing new Foo object with arguments.
367
+ # def self.json_create(object)
368
+ # new(*object['a'])
369
+ # end
370
+ # end
371
+ #
372
+ # Demonstration:
51
373
  # require 'json'
374
+ # # This Foo object has no custom addition.
375
+ # foo0 = Foo.new(0, 1)
376
+ # json0 = JSON.generate(foo0)
377
+ # obj0 = JSON.parse(json0)
378
+ # # Lood the custom addition.
379
+ # require_relative 'foo_addition'
380
+ # # This foo has the custom addition.
381
+ # foo1 = Foo.new(0, 1)
382
+ # json1 = JSON.generate(foo1)
383
+ # obj1 = JSON.parse(json1, create_additions: true)
384
+ # # Make a nice display.
385
+ # display = <<EOT
386
+ # Generated JSON:
387
+ # Without custom addition: #{json0} (#{json0.class})
388
+ # With custom addition: #{json1} (#{json1.class})
389
+ # Parsed JSON:
390
+ # Without custom addition: #{obj0.inspect} (#{obj0.class})
391
+ # With custom addition: #{obj1.inspect} (#{obj1.class})
392
+ # EOT
393
+ # puts display
394
+ #
395
+ # Output:
52
396
  #
53
- # 1.to_json => "1"
397
+ # Generated JSON:
398
+ # Without custom addition: "#<Foo:0x0000000006534e80>" (String)
399
+ # With custom addition: {"json_class":"Foo","a":[0,1]} (String)
400
+ # Parsed JSON:
401
+ # Without custom addition: "#<Foo:0x0000000006534e80>" (String)
402
+ # With custom addition: #<Foo:0x0000000006473bb8 @bar=0, @baz=1> (Foo)
54
403
  #
55
404
  module JSON
56
405
  require 'json/version'