json 1.8.6 → 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.
Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.travis.yml +13 -5
  4. data/{CHANGES → CHANGES.md} +212 -95
  5. data/Gemfile +10 -3
  6. data/{README-json-jruby.markdown → README-json-jruby.md} +0 -0
  7. data/README.md +187 -107
  8. data/Rakefile +36 -104
  9. data/VERSION +1 -1
  10. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  11. data/ext/json/ext/generator/generator.c +175 -98
  12. data/ext/json/ext/generator/generator.h +0 -6
  13. data/ext/json/ext/parser/extconf.rb +3 -0
  14. data/ext/json/ext/parser/parser.c +380 -483
  15. data/ext/json/ext/parser/parser.h +4 -5
  16. data/ext/json/ext/parser/parser.rl +109 -175
  17. data/ext/json/extconf.rb +0 -1
  18. data/java/src/json/ext/Generator.java +35 -15
  19. data/java/src/json/ext/GeneratorState.java +2 -54
  20. data/java/src/json/ext/OptionsReader.java +1 -1
  21. data/java/src/json/ext/Parser.java +131 -413
  22. data/java/src/json/ext/Parser.rl +47 -122
  23. data/java/src/json/ext/RuntimeInfo.java +0 -4
  24. data/json-java.gemspec +4 -5
  25. data/json.gemspec +0 -0
  26. data/json_pure.gemspec +11 -15
  27. data/lib/json.rb +379 -29
  28. data/lib/json/add/bigdecimal.rb +3 -2
  29. data/lib/json/add/complex.rb +4 -3
  30. data/lib/json/add/core.rb +1 -0
  31. data/lib/json/add/date.rb +1 -1
  32. data/lib/json/add/date_time.rb +1 -1
  33. data/lib/json/add/exception.rb +1 -1
  34. data/lib/json/add/ostruct.rb +3 -3
  35. data/lib/json/add/range.rb +1 -1
  36. data/lib/json/add/rational.rb +3 -2
  37. data/lib/json/add/regexp.rb +3 -3
  38. data/lib/json/add/set.rb +29 -0
  39. data/lib/json/add/struct.rb +1 -1
  40. data/lib/json/add/symbol.rb +1 -1
  41. data/lib/json/add/time.rb +1 -1
  42. data/lib/json/common.rb +335 -128
  43. data/lib/json/ext.rb +0 -6
  44. data/lib/json/generic_object.rb +5 -4
  45. data/lib/json/pure.rb +2 -8
  46. data/lib/json/pure/generator.rb +54 -125
  47. data/lib/json/pure/parser.rb +42 -82
  48. data/lib/json/version.rb +2 -1
  49. data/references/rfc7159.txt +899 -0
  50. data/tests/fixtures/obsolete_fail1.json +1 -0
  51. data/tests/{test_json_addition.rb → json_addition_test.rb} +32 -25
  52. data/tests/json_common_interface_test.rb +126 -0
  53. data/tests/json_encoding_test.rb +107 -0
  54. data/tests/json_ext_parser_test.rb +15 -0
  55. data/tests/{test_json_fixtures.rb → json_fixtures_test.rb} +10 -8
  56. data/tests/{test_json_generate.rb → json_generator_test.rb} +112 -39
  57. data/tests/{test_json_generic_object.rb → json_generic_object_test.rb} +15 -8
  58. data/tests/json_parser_test.rb +472 -0
  59. data/tests/json_string_matching_test.rb +38 -0
  60. data/tests/{setup_variant.rb → test_helper.rb} +6 -0
  61. data/tools/fuzz.rb +1 -9
  62. metadata +38 -43
  63. data/TODO +0 -1
  64. data/data/example.json +0 -1
  65. data/data/index.html +0 -38
  66. data/data/prototype.js +0 -4184
  67. data/tests/fixtures/fail1.json +0 -1
  68. data/tests/test_json.rb +0 -519
  69. data/tests/test_json_encoding.rb +0 -65
  70. data/tests/test_json_string_matching.rb +0 -39
  71. data/tests/test_json_unicode.rb +0 -72
@@ -50,9 +50,9 @@ public class Parser extends RubyObject {
50
50
  private int maxNesting;
51
51
  private boolean allowNaN;
52
52
  private boolean symbolizeNames;
53
- private boolean quirksMode;
54
53
  private RubyClass objectClass;
55
54
  private RubyClass arrayClass;
55
+ private RubyClass decimalClass;
56
56
  private RubyHash match_string;
57
57
 
58
58
  private static final int DEFAULT_MAX_NESTING = 100;
@@ -121,10 +121,6 @@ public class Parser extends RubyObject {
121
121
  * <dd>If set to <code>true</code>, returns symbols for the names (keys) in
122
122
  * a JSON object. Otherwise strings are returned, which is also the default.
123
123
  *
124
- * <dt><code>:quirks_mode?</code>
125
- * <dd>If set to <code>true</code>, if the parse is in quirks_mode, false
126
- * otherwise.
127
- *
128
124
  * <dt><code>:create_additions</code>
129
125
  * <dd>If set to <code>false</code>, the Parser doesn't create additions
130
126
  * even if a matching class and <code>create_id</code> was found. This option
@@ -136,9 +132,10 @@ public class Parser extends RubyObject {
136
132
  * <dt><code>:array_class</code>
137
133
  * <dd>Defaults to Array.
138
134
  *
139
- * <dt><code>:quirks_mode</code>
140
- * <dd>Enables quirks_mode for parser, that is for example parsing single
141
- * JSON values instead of documents is possible.
135
+ * <dt><code>:decimal_class</code>
136
+ * <dd>Specifies which class to use instead of the default (Float) when
137
+ * parsing decimal numbers. This class must accept a single string argument
138
+ * in its constructor.
142
139
  * </dl>
143
140
  */
144
141
  @JRubyMethod(name = "new", required = 1, optional = 1, meta = true)
@@ -161,15 +158,21 @@ public class Parser extends RubyObject {
161
158
  this.maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING);
162
159
  this.allowNaN = opts.getBool("allow_nan", false);
163
160
  this.symbolizeNames = opts.getBool("symbolize_names", false);
164
- this.quirksMode = opts.getBool("quirks_mode", false);
165
161
  this.createId = opts.getString("create_id", getCreateId(context));
166
162
  this.createAdditions = opts.getBool("create_additions", false);
167
163
  this.objectClass = opts.getClass("object_class", runtime.getHash());
168
164
  this.arrayClass = opts.getClass("array_class", runtime.getArray());
165
+ this.decimalClass = opts.getClass("decimal_class", null);
169
166
  this.match_string = opts.getHash("match_string");
170
167
 
168
+ if(symbolizeNames && createAdditions) {
169
+ throw runtime.newArgumentError(
170
+ "options :symbolize_names and :create_additions cannot be " +
171
+ " used in conjunction"
172
+ );
173
+ }
171
174
  this.vSource = args[0].convertToString();
172
- if (!quirksMode) this.vSource = convertEncoding(context, vSource);
175
+ this.vSource = convertEncoding(context, vSource);
173
176
 
174
177
  return this;
175
178
  }
@@ -180,33 +183,16 @@ public class Parser extends RubyObject {
180
183
  * Returns the source string if no conversion is needed.
181
184
  */
182
185
  private RubyString convertEncoding(ThreadContext context, RubyString source) {
183
- ByteList bl = source.getByteList();
184
- int len = bl.length();
185
- if (len < 2) {
186
- throw Utils.newException(context, Utils.M_PARSER_ERROR,
187
- "A JSON text must at least contain two octets!");
188
- }
189
-
190
- if (info.encodingsSupported()) {
191
- RubyEncoding encoding = (RubyEncoding)source.encoding(context);
192
- if (encoding != info.ascii8bit.get()) {
193
- return (RubyString)source.encode(context, info.utf8.get());
194
- }
195
-
196
- String sniffedEncoding = sniffByteList(bl);
197
- if (sniffedEncoding == null) return source; // assume UTF-8
198
- return reinterpretEncoding(context, source, sniffedEncoding);
199
- }
200
-
201
- String sniffedEncoding = sniffByteList(bl);
202
- if (sniffedEncoding == null) return source; // assume UTF-8
203
- Ruby runtime = context.getRuntime();
204
- return (RubyString)info.jsonModule.get().
205
- callMethod(context, "iconv",
206
- new IRubyObject[] {
207
- runtime.newString("utf-8"),
208
- runtime.newString(sniffedEncoding),
209
- source});
186
+ RubyEncoding encoding = (RubyEncoding)source.encoding(context);
187
+ if (encoding == info.ascii8bit.get()) {
188
+ if (source.isFrozen()) {
189
+ source = (RubyString) source.dup();
190
+ }
191
+ source.force_encoding(context, info.utf8.get());
192
+ } else {
193
+ source = (RubyString) source.encode(context, info.utf8.get());
194
+ }
195
+ return source;
210
196
  }
211
197
 
212
198
  /**
@@ -259,17 +245,6 @@ public class Parser extends RubyObject {
259
245
  return checkAndGetSource().dup();
260
246
  }
261
247
 
262
- /**
263
- * <code>Parser#quirks_mode?()</code>
264
- *
265
- * <p>If set to <code>true</code>, if the parse is in quirks_mode, false
266
- * otherwise.
267
- */
268
- @JRubyMethod(name = "quirks_mode?")
269
- public IRubyObject quirks_mode_p(ThreadContext context) {
270
- return context.getRuntime().newBoolean(quirksMode);
271
- }
272
-
273
248
  public RubyString checkAndGetSource() {
274
249
  if (vSource != null) {
275
250
  return vSource;
@@ -393,7 +368,7 @@ public class Parser extends RubyObject {
393
368
  }
394
369
  }
395
370
  action parse_number {
396
- if (pe > fpc + 9 - (parser.quirksMode ? 1 : 0) &&
371
+ if (pe > fpc + 8 &&
397
372
  absSubSequence(fpc, fpc + 9).equals(JSON_MINUS_INFINITY)) {
398
373
 
399
374
  if (parser.allowNaN) {
@@ -520,13 +495,13 @@ public class Parser extends RubyObject {
520
495
 
521
496
  return p;
522
497
  }
523
-
498
+
524
499
  RubyInteger createInteger(int p, int new_p) {
525
500
  Ruby runtime = getRuntime();
526
501
  ByteList num = absSubSequence(p, new_p);
527
502
  return bytesToInum(runtime, num);
528
503
  }
529
-
504
+
530
505
  RubyInteger bytesToInum(Ruby runtime, ByteList num) {
531
506
  return runtime.is1_9() ?
532
507
  ConvertBytes.byteListToInum19(runtime, num, 10, true) :
@@ -556,7 +531,9 @@ public class Parser extends RubyObject {
556
531
  res.update(null, p);
557
532
  return;
558
533
  }
559
- RubyFloat number = createFloat(p, new_p);
534
+ IRubyObject number = parser.decimalClass == null ?
535
+ createFloat(p, new_p) : createCustomDecimal(p, new_p);
536
+
560
537
  res.update(number, new_p + 1);
561
538
  return;
562
539
  }
@@ -571,16 +548,23 @@ public class Parser extends RubyObject {
571
548
  if (cs < JSON_float_first_final) {
572
549
  return -1;
573
550
  }
574
-
551
+
575
552
  return p;
576
553
  }
577
-
554
+
578
555
  RubyFloat createFloat(int p, int new_p) {
579
556
  Ruby runtime = getRuntime();
580
557
  ByteList num = absSubSequence(p, new_p);
581
558
  return RubyFloat.newFloat(runtime, dc.parse(num, true, runtime.is1_9()));
582
559
  }
583
560
 
561
+ IRubyObject createCustomDecimal(int p, int new_p) {
562
+ Ruby runtime = getRuntime();
563
+ ByteList num = absSubSequence(p, new_p);
564
+ IRubyObject numString = runtime.newString(num.toString());
565
+ return parser.decimalClass.callMethod(context, "new", numString);
566
+ }
567
+
584
568
  %%{
585
569
  machine JSON_string;
586
570
  include JSON_common;
@@ -623,11 +607,11 @@ public class Parser extends RubyObject {
623
607
  %% write exec;
624
608
 
625
609
  if (parser.createAdditions) {
626
- RubyHash match_string = parser.match_string;
627
- if (match_string != null) {
610
+ RubyHash matchString = parser.match_string;
611
+ if (matchString != null) {
628
612
  final IRubyObject[] memoArray = { result, null };
629
613
  try {
630
- match_string.visitAll(new RubyHash.Visitor() {
614
+ matchString.visitAll(new RubyHash.Visitor() {
631
615
  @Override
632
616
  public void visit(IRubyObject pattern, IRubyObject klass) {
633
617
  if (pattern.callMethod(context, "===", memoArray[0]).isTrue()) {
@@ -647,8 +631,8 @@ public class Parser extends RubyObject {
647
631
  }
648
632
  }
649
633
 
650
- if (cs >= JSON_string_first_final && result != null) {
651
- if (info.encodingsSupported() && result instanceof RubyString) {
634
+ if (cs >= JSON_string_first_final && result != null) {
635
+ if (result instanceof RubyString) {
652
636
  ((RubyString)result).force_encoding(context, info.utf8.get());
653
637
  }
654
638
  res.update(result, p + 1);
@@ -765,7 +749,7 @@ public class Parser extends RubyObject {
765
749
  fhold;
766
750
  fbreak;
767
751
  }
768
-
752
+
769
753
  pair = ignore* begin_name >parse_name ignore* name_separator
770
754
  ignore* begin_value >parse_value;
771
755
  next_pair = ignore* value_separator pair;
@@ -835,60 +819,6 @@ public class Parser extends RubyObject {
835
819
 
836
820
  write data;
837
821
 
838
- action parse_object {
839
- currentNesting = 1;
840
- parseObject(res, fpc, pe);
841
- if (res.result == null) {
842
- fhold;
843
- fbreak;
844
- } else {
845
- result = res.result;
846
- fexec res.p;
847
- }
848
- }
849
-
850
- action parse_array {
851
- currentNesting = 1;
852
- parseArray(res, fpc, pe);
853
- if (res.result == null) {
854
- fhold;
855
- fbreak;
856
- } else {
857
- result = res.result;
858
- fexec res.p;
859
- }
860
- }
861
-
862
- main := ignore*
863
- ( begin_object >parse_object
864
- | begin_array >parse_array )
865
- ignore*;
866
- }%%
867
-
868
- public IRubyObject parseStrict() {
869
- int cs = EVIL;
870
- int p, pe;
871
- IRubyObject result = null;
872
- ParserResult res = new ParserResult();
873
-
874
- %% write init;
875
- p = byteList.begin();
876
- pe = p + byteList.length();
877
- %% write exec;
878
-
879
- if (cs >= JSON_first_final && p == pe) {
880
- return result;
881
- } else {
882
- throw unexpectedToken(p, pe);
883
- }
884
- }
885
-
886
- %%{
887
- machine JSON_quirks_mode;
888
- include JSON_common;
889
-
890
- write data;
891
-
892
822
  action parse_value {
893
823
  parseValue(res, fpc, pe);
894
824
  if (res.result == null) {
@@ -905,7 +835,7 @@ public class Parser extends RubyObject {
905
835
  ignore*;
906
836
  }%%
907
837
 
908
- public IRubyObject parseQuirksMode() {
838
+ public IRubyObject parseImplemetation() {
909
839
  int cs = EVIL;
910
840
  int p, pe;
911
841
  IRubyObject result = null;
@@ -916,7 +846,7 @@ public class Parser extends RubyObject {
916
846
  pe = p + byteList.length();
917
847
  %% write exec;
918
848
 
919
- if (cs >= JSON_quirks_mode_first_final && p == pe) {
849
+ if (cs >= JSON_first_final && p == pe) {
920
850
  return result;
921
851
  } else {
922
852
  throw unexpectedToken(p, pe);
@@ -924,12 +854,7 @@ public class Parser extends RubyObject {
924
854
  }
925
855
 
926
856
  public IRubyObject parse() {
927
- if (parser.quirksMode) {
928
- return parseQuirksMode();
929
- } else {
930
- return parseStrict();
931
- }
932
-
857
+ return parseImplemetation();
933
858
  }
934
859
 
935
860
  /**
@@ -90,10 +90,6 @@ final class RuntimeInfo {
90
90
  }
91
91
  }
92
92
 
93
- public boolean encodingsSupported() {
94
- return utf8 != null && utf8.get() != null;
95
- }
96
-
97
93
  public RubyEncoding getEncoding(ThreadContext context, String name) {
98
94
  synchronized (encodings) {
99
95
  WeakReference<RubyEncoding> encoding = encodings.get(name);
@@ -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,37 +1,33 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: json_pure 1.8.6 ruby lib
3
2
 
4
3
  Gem::Specification.new do |s|
5
4
  s.name = "json_pure".freeze
6
- s.version = "1.8.6"
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-01-13"
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_json.rb".freeze, "./tests/test_json_addition.rb".freeze, "./tests/test_json_encoding.rb".freeze, "./tests/test_json_fixtures.rb".freeze, "./tests/test_json_generate.rb".freeze, "./tests/test_json_generic_object.rb".freeze, "./tests/test_json_string_matching.rb".freeze, "./tests/test_json_unicode.rb".freeze, ".gitignore".freeze, ".travis.yml".freeze, "CHANGES".freeze, "Gemfile".freeze, "README-json-jruby.markdown".freeze, "README.md".freeze, "Rakefile".freeze, "TODO".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, "tests/fixtures/fail1.json".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/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/setup_variant.rb".freeze, "tests/test_json.rb".freeze, "tests/test_json_addition.rb".freeze, "tests/test_json_encoding.rb".freeze, "tests/test_json_fixtures.rb".freeze, "tests/test_json_generate.rb".freeze, "tests/test_json_generic_object.rb".freeze, "tests/test_json_string_matching.rb".freeze, "tests/test_json_unicode.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
- s.rdoc_options = ["--title".freeze, "JSON implemention for Ruby".freeze, "--main".freeze, "README.md".freeze]
19
- s.rubygems_version = "2.6.8".freeze
16
+ s.rdoc_options = ["--title".freeze, "JSON implemention for ruby".freeze, "--main".freeze, "README.md".freeze]
17
+ s.required_ruby_version = Gem::Requirement.new(">= 2.0".freeze)
18
+ s.rubygems_version = "3.1.2".freeze
20
19
  s.summary = "JSON Implementation for Ruby".freeze
21
- s.test_files = ["./tests/test_json.rb".freeze, "./tests/test_json_addition.rb".freeze, "./tests/test_json_encoding.rb".freeze, "./tests/test_json_fixtures.rb".freeze, "./tests/test_json_generate.rb".freeze, "./tests/test_json_generic_object.rb".freeze, "./tests/test_json_string_matching.rb".freeze, "./tests/test_json_unicode.rb".freeze]
20
+ s.test_files = ["./tests/test_helper.rb".freeze]
22
21
 
23
22
  if s.respond_to? :specification_version then
24
23
  s.specification_version = 4
24
+ end
25
25
 
26
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
27
- s.add_development_dependency(%q<rake>.freeze, [">= 0"])
28
- s.add_development_dependency(%q<test-unit>.freeze, ["~> 2.0"])
29
- else
30
- s.add_dependency(%q<rake>.freeze, [">= 0"])
31
- s.add_dependency(%q<test-unit>.freeze, ["~> 2.0"])
32
- 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"])
33
29
  else
34
30
  s.add_dependency(%q<rake>.freeze, [">= 0"])
35
- s.add_dependency(%q<test-unit>.freeze, ["~> 2.0"])
31
+ s.add_dependency(%q<test-unit>.freeze, [">= 2.0", "< 4.0"])
36
32
  end
37
33
  end
@@ -1,55 +1,405 @@
1
+ #frozen_string_literal: false
1
2
  require 'json/common'
2
3
 
3
4
  ##
4
- # = JavaScript Object Notation (JSON)
5
+ # = JavaScript \Object Notation (\JSON)
5
6
  #
6
- # JSON is a lightweight data-interchange format. It is easy for us
7
- # humans to read and write. Plus, equally simple for machines to generate or parse.
8
- # JSON is completely language agnostic, making it the ideal interchange format.
7
+ # \JSON is a lightweight data-interchange format.
9
8
  #
10
- # Built on two universally available structures:
11
- # 1. A collection of name/value pairs. Often referred to as an _object_, hash table, record, struct, keyed list, or associative array.
12
- # 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]
13
16
  #
14
- # 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}
15
21
  #
16
- # == 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]]
17
26
  #
18
- # To parse a JSON string received by another application or generated within
19
- # your existing application:
27
+ # == Using \Module \JSON
20
28
  #
29
+ # To make module \JSON available in your code, begin with:
21
30
  # require 'json'
22
31
  #
23
- # my_hash = JSON.parse('{"hello": "goodbye"}')
24
- # puts my_hash["hello"] => "goodbye"
32
+ # All examples here assume that this has been done.
25
33
  #
26
- # Notice the extra quotes <tt>''</tt> around the hash notation. Ruby expects
27
- # the argument to be a string and can't convert objects like a hash or array.
34
+ # === Parsing \JSON
28
35
  #
29
- # 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>
30
40
  #
31
- # == 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.
32
45
  #
33
- # Creating a JSON string for communication or serialization is
34
- # 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.
35
51
  #
36
- # require 'json'
52
+ # ==== Parsing \JSON Arrays
37
53
  #
38
- # my_hash = {:hello => "goodbye"}
39
- # 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
40
59
  #
41
- # 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]]
42
64
  #
43
- # require 'json'
44
- # 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.
45
188
  #
46
- # <tt>JSON.generate</tt> only allows objects or arrays to be converted
47
- # to JSON syntax. <tt>to_json</tt>, however, accepts many Ruby classes
48
- # 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
49
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:
50
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:
51
396
  #
52
- # 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)
53
403
  #
54
404
  module JSON
55
405
  require 'json/version'