oj 2.18.5 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -226
  3. data/ext/oj/circarray.c +0 -25
  4. data/ext/oj/circarray.h +0 -25
  5. data/ext/oj/code.c +227 -0
  6. data/ext/oj/code.h +40 -0
  7. data/ext/oj/compat.c +126 -38
  8. data/ext/oj/custom.c +1097 -0
  9. data/ext/oj/dump.c +658 -2376
  10. data/ext/oj/dump.h +92 -0
  11. data/ext/oj/dump_compat.c +937 -0
  12. data/ext/oj/dump_leaf.c +254 -0
  13. data/ext/oj/dump_object.c +810 -0
  14. data/ext/oj/dump_rails.c +329 -0
  15. data/ext/oj/dump_strict.c +416 -0
  16. data/ext/oj/err.c +0 -25
  17. data/ext/oj/err.h +8 -2
  18. data/ext/oj/fast.c +24 -24
  19. data/ext/oj/mimic_json.c +817 -0
  20. data/ext/oj/mimic_rails.c +806 -0
  21. data/ext/oj/mimic_rails.h +17 -0
  22. data/ext/oj/object.c +18 -72
  23. data/ext/oj/odd.c +0 -25
  24. data/ext/oj/odd.h +2 -27
  25. data/ext/oj/oj.c +655 -1503
  26. data/ext/oj/oj.h +93 -40
  27. data/ext/oj/parse.c +99 -46
  28. data/ext/oj/parse.h +12 -26
  29. data/ext/oj/reader.c +1 -25
  30. data/ext/oj/reader.h +3 -25
  31. data/ext/oj/resolve.c +9 -11
  32. data/ext/oj/resolve.h +2 -2
  33. data/ext/oj/rxclass.c +133 -0
  34. data/ext/oj/rxclass.h +27 -0
  35. data/ext/oj/saj.c +4 -25
  36. data/ext/oj/scp.c +3 -25
  37. data/ext/oj/sparse.c +89 -13
  38. data/ext/oj/stream_writer.c +301 -0
  39. data/ext/oj/strict.c +4 -27
  40. data/ext/oj/string_writer.c +480 -0
  41. data/ext/oj/val_stack.h +6 -2
  42. data/lib/oj.rb +1 -23
  43. data/lib/oj/easy_hash.rb +12 -4
  44. data/lib/oj/json.rb +172 -0
  45. data/lib/oj/mimic.rb +123 -18
  46. data/lib/oj/state.rb +131 -0
  47. data/lib/oj/version.rb +1 -1
  48. data/pages/Advanced.md +22 -0
  49. data/pages/Compatibility.md +25 -0
  50. data/pages/Custom.md +23 -0
  51. data/pages/Encoding.md +65 -0
  52. data/pages/JsonGem.md +79 -0
  53. data/pages/Modes.md +140 -0
  54. data/pages/Options.md +250 -0
  55. data/pages/Rails.md +60 -0
  56. data/pages/Security.md +20 -0
  57. data/test/activesupport4/decoding_test.rb +105 -0
  58. data/test/activesupport4/encoding_test.rb +531 -0
  59. data/test/activesupport4/test_helper.rb +41 -0
  60. data/test/activesupport5/decoding_test.rb +125 -0
  61. data/test/activesupport5/encoding_test.rb +483 -0
  62. data/test/activesupport5/encoding_test_cases.rb +90 -0
  63. data/test/activesupport5/test_helper.rb +50 -0
  64. data/test/activesupport5/time_zone_test_helpers.rb +24 -0
  65. data/test/json_gem/json_addition_test.rb +216 -0
  66. data/test/json_gem/json_common_interface_test.rb +143 -0
  67. data/test/json_gem/json_encoding_test.rb +109 -0
  68. data/test/json_gem/json_ext_parser_test.rb +20 -0
  69. data/test/json_gem/json_fixtures_test.rb +35 -0
  70. data/test/json_gem/json_generator_test.rb +383 -0
  71. data/test/json_gem/json_generic_object_test.rb +90 -0
  72. data/test/json_gem/json_parser_test.rb +470 -0
  73. data/test/json_gem/json_string_matching_test.rb +42 -0
  74. data/test/json_gem/test_helper.rb +18 -0
  75. data/test/perf_compat.rb +30 -28
  76. data/test/perf_object.rb +1 -1
  77. data/test/perf_strict.rb +18 -1
  78. data/test/sample.rb +0 -1
  79. data/test/test_compat.rb +169 -93
  80. data/test/test_custom.rb +355 -0
  81. data/test/test_file.rb +0 -8
  82. data/test/test_null.rb +376 -0
  83. data/test/test_object.rb +268 -3
  84. data/test/test_scp.rb +22 -1
  85. data/test/test_strict.rb +160 -4
  86. data/test/test_various.rb +52 -620
  87. data/test/tests.rb +14 -0
  88. data/test/tests_mimic.rb +14 -0
  89. data/test/tests_mimic_addition.rb +7 -0
  90. metadata +89 -47
  91. data/test/activesupport_datetime_test.rb +0 -23
  92. data/test/bug.rb +0 -51
  93. data/test/bug2.rb +0 -10
  94. data/test/bug3.rb +0 -46
  95. data/test/bug_fast.rb +0 -32
  96. data/test/bug_load.rb +0 -24
  97. data/test/crash.rb +0 -111
  98. data/test/curl/curl_oj.rb +0 -46
  99. data/test/curl/get_oj.rb +0 -24
  100. data/test/curl/just_curl.rb +0 -31
  101. data/test/curl/just_oj.rb +0 -51
  102. data/test/example.rb +0 -11
  103. data/test/foo.rb +0 -24
  104. data/test/io.rb +0 -48
  105. data/test/isolated/test_mimic_rails_datetime.rb +0 -27
  106. data/test/mod.rb +0 -16
  107. data/test/rails.rb +0 -50
  108. data/test/russian.rb +0 -18
  109. data/test/struct.rb +0 -29
  110. data/test/test_serializer.rb +0 -59
  111. data/test/write_timebars.rb +0 -31
@@ -0,0 +1,17 @@
1
+ /* mimic_rails.h
2
+ * Copyright (c) 2017, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #ifndef __OJ_MIMIC_RAILS_H__
7
+ #define __OJ_MIMIC_RAILS_H__
8
+
9
+ #include "dump.h"
10
+
11
+ extern void oj_mimic_rails_init();
12
+ extern ROpt oj_rails_get_opt(ROptTable rot, VALUE clas);
13
+
14
+ extern bool oj_rails_hash_opt;
15
+ extern bool oj_rails_array_opt;
16
+
17
+ #endif /* __OJ_MIMIC_RAILS_H__ */
@@ -1,31 +1,6 @@
1
1
  /* object.c
2
2
  * Copyright (c) 2012, Peter Ohler
3
3
  * All rights reserved.
4
- *
5
- * Redistribution and use in source and binary forms, with or without
6
- * modification, are permitted provided that the following conditions are met:
7
- *
8
- * - Redistributions of source code must retain the above copyright notice, this
9
- * list of conditions and the following disclaimer.
10
- *
11
- * - Redistributions in binary form must reproduce the above copyright notice,
12
- * this list of conditions and the following disclaimer in the documentation
13
- * and/or other materials provided with the distribution.
14
- *
15
- * - Neither the name of Peter Ohler nor the names of its contributors may be
16
- * used to endorse or promote products derived from this software without
17
- * specific prior written permission.
18
- *
19
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
4
  */
30
5
 
31
6
  #include <stdio.h>
@@ -96,7 +71,7 @@ str_to_value(ParseInfo pi, const char *str, size_t len, const char *orig) {
96
71
 
97
72
  #if (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
98
73
  static VALUE
99
- parse_xml_time(const char *str, int len) {
74
+ oj_parse_xml_time(const char *str, int len) {
100
75
  return rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(str, len));
101
76
  }
102
77
  #else
@@ -117,8 +92,8 @@ parse_num(const char *str, const char *end, int cnt) {
117
92
  return n;
118
93
  }
119
94
 
120
- static VALUE
121
- parse_xml_time(const char *str, int len) {
95
+ VALUE
96
+ oj_parse_xml_time(const char *str, int len) {
122
97
  VALUE args[8];
123
98
  const char *end = str + len;
124
99
  int n;
@@ -242,8 +217,8 @@ hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
242
217
  if (2 == klen) {
243
218
  switch (key[1]) {
244
219
  case 'o': // object
245
- { // name2class sets and error if the class is not found or created
246
- VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define);
220
+ { // name2class sets an error if the class is not found or created
221
+ VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
247
222
 
248
223
  if (Qundef != clas) {
249
224
  parent->val = rb_obj_alloc(clas);
@@ -272,7 +247,7 @@ hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
272
247
  break;
273
248
  case 'c': // class
274
249
  {
275
- VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define);
250
+ VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
276
251
 
277
252
  if (Qundef == clas) {
278
253
  return 0;
@@ -282,7 +257,7 @@ hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
282
257
  }
283
258
  break;
284
259
  case 't': // time
285
- parent->val = parse_xml_time(str, len);
260
+ parent->val = oj_parse_xml_time(str, len);
286
261
  break;
287
262
  default:
288
263
  return 0;
@@ -309,11 +284,7 @@ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
309
284
  }
310
285
  }
311
286
  if (86400 == ni->exp) { // UTC time
312
- #if HAS_NANO_TIME
313
287
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
314
- #else
315
- parent->val = rb_time_new(ni->i, (long)(nsec / 1000));
316
- #endif
317
288
  // Since the ruby C routines alway create local time, the
318
289
  // offset and then a convertion to UTC keeps makes the time
319
290
  // match the expected value.
@@ -321,24 +292,6 @@ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
321
292
  } else if (ni->hasExp) {
322
293
  time_t t = (time_t)(ni->i + ni->exp);
323
294
  struct tm *st = gmtime(&t);
324
- #if RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8
325
- // The only methods that allow the UTC offset to be set in
326
- // 1.8.7 is the parse() and xmlschema() methods. The
327
- // xmlschema() method always returns a Time instance that is
328
- // UTC time. (true on some platforms anyway) Time.parse()
329
- // fails on other Ruby versions until 2.2.0.
330
- char buf[64];
331
- int z = (0 > ni->exp ? -ni->exp : ni->exp) / 60;
332
- int tzhour = z / 60;
333
- int tzmin = z - tzhour * 60;
334
- int cnt;
335
-
336
- cnt = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d",
337
- 1900 + st->tm_year, 1 + st->tm_mon, st->tm_mday,
338
- st->tm_hour, st->tm_min, st->tm_sec, (long)nsec,
339
- (0 > ni->exp ? '-' : '+'), tzhour, tzmin);
340
- parent->val = rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(buf, cnt));
341
- #else
342
295
  VALUE args[8];
343
296
 
344
297
  args[0] = LONG2NUM(1900 + st->tm_year);
@@ -346,20 +299,11 @@ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
346
299
  args[2] = LONG2NUM(st->tm_mday);
347
300
  args[3] = LONG2NUM(st->tm_hour);
348
301
  args[4] = LONG2NUM(st->tm_min);
349
- #if NO_TIME_ROUND_PAD
350
- args[5] = rb_float_new((double)st->tm_sec + ((double)nsec) / 1000000000.0);
351
- #else
352
302
  args[5] = rb_float_new((double)st->tm_sec + ((double)nsec + 0.5) / 1000000000.0);
353
- #endif
354
303
  args[6] = LONG2NUM(ni->exp);
355
304
  parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
356
- #endif
357
305
  } else {
358
- #if HAS_NANO_TIME
359
306
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
360
- #else
361
- parent->val = rb_time_new(ni->i, (long)(nsec / 1000));
362
- #endif
363
307
  }
364
308
  }
365
309
  break;
@@ -410,7 +354,7 @@ hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, volatile VALUE
410
354
  sc = rb_funcall2(rb_cStruct, oj_new_id, cnt, args);
411
355
  } else {
412
356
  // If struct is not defined then we let this fail and raise an exception.
413
- sc = oj_name2struct(pi, *RARRAY_PTR(value));
357
+ sc = oj_name2struct(pi, *RARRAY_PTR(value), rb_eArgError);
414
358
  }
415
359
  // Create a properly initialized struct instance without calling the initialize method.
416
360
  parent->val = rb_obj_alloc(sc);
@@ -469,8 +413,8 @@ copy_ivars(VALUE target, VALUE src) {
469
413
  }
470
414
  }
471
415
 
472
- static void
473
- set_obj_ivar(Val parent, Val kval, VALUE value) {
416
+ void
417
+ oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
474
418
  const char *key = kval->key;
475
419
  int klen = kval->klen;
476
420
  ID var_id;
@@ -552,11 +496,11 @@ hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *o
552
496
  if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
553
497
  rb_funcall(parent->val, oj_replace_id, 1, str_to_value(pi, str, len, orig));
554
498
  } else {
555
- set_obj_ivar(parent, kval, str_to_value(pi, str, len, orig));
499
+ oj_set_obj_ivar(parent, kval, str_to_value(pi, str, len, orig));
556
500
  }
557
501
  break;
558
502
  case T_OBJECT:
559
- set_obj_ivar(parent, kval, str_to_value(pi, str, len, orig));
503
+ oj_set_obj_ivar(parent, kval, str_to_value(pi, str, len, orig));
560
504
  break;
561
505
  case T_CLASS:
562
506
  if (0 == parent->odd_args) {
@@ -602,7 +546,7 @@ hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
602
546
  !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
603
547
  oj_circ_array_set(pi->circ_array, parent->val, ni->i);
604
548
  } else {
605
- set_obj_ivar(parent, kval, oj_num_as_value(ni));
549
+ oj_set_obj_ivar(parent, kval, oj_num_as_value(ni));
606
550
  }
607
551
  break;
608
552
  case T_CLASS:
@@ -646,7 +590,7 @@ hash_set_value(ParseInfo pi, Val kval, VALUE value) {
646
590
  if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
647
591
  rb_funcall(parent->val, oj_replace_id, 1, value);
648
592
  } else {
649
- set_obj_ivar(parent, kval, value);
593
+ oj_set_obj_ivar(parent, kval, value);
650
594
  }
651
595
  } else {
652
596
  if (3 <= klen && '^' == *key && '#' == key[1] && T_ARRAY == rb_type(value)) {
@@ -667,12 +611,12 @@ hash_set_value(ParseInfo pi, Val kval, VALUE value) {
667
611
  if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
668
612
  rb_funcall(parent->val, oj_replace_id, 1, value);
669
613
  } else {
670
- set_obj_ivar(parent, kval, value);
614
+ oj_set_obj_ivar(parent, kval, value);
671
615
  }
672
616
  break;
673
617
  case T_STRING: // for subclassed strings
674
618
  case T_OBJECT:
675
- set_obj_ivar(parent, kval, value);
619
+ oj_set_obj_ivar(parent, kval, value);
676
620
  break;
677
621
  case T_MODULE:
678
622
  case T_CLASS:
@@ -772,6 +716,7 @@ VALUE
772
716
  oj_object_parse(int argc, VALUE *argv, VALUE self) {
773
717
  struct _ParseInfo pi;
774
718
 
719
+ parse_info_init(&pi);
775
720
  pi.options = oj_default_options;
776
721
  pi.handler = Qnil;
777
722
  pi.err_class = Qnil;
@@ -788,6 +733,7 @@ VALUE
788
733
  oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
789
734
  struct _ParseInfo pi;
790
735
 
736
+ parse_info_init(&pi);
791
737
  pi.options = oj_default_options;
792
738
  pi.handler = Qnil;
793
739
  pi.err_class = Qnil;
@@ -1,31 +1,6 @@
1
1
  /* odd.c
2
2
  * Copyright (c) 2011, Peter Ohler
3
3
  * All rights reserved.
4
- *
5
- * Redistribution and use in source and binary forms, with or without
6
- * modification, are permitted provided that the following conditions are met:
7
- *
8
- * - Redistributions of source code must retain the above copyright notice, this
9
- * list of conditions and the following disclaimer.
10
- *
11
- * - Redistributions in binary form must reproduce the above copyright notice,
12
- * this list of conditions and the following disclaimer in the documentation
13
- * and/or other materials provided with the distribution.
14
- *
15
- * - Neither the name of Peter Ohler nor the names of its contributors may be
16
- * used to endorse or promote products derived from this software without
17
- * specific prior written permission.
18
- *
19
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
4
  */
30
5
 
31
6
  #include <string.h>
@@ -1,31 +1,6 @@
1
1
  /* odd.h
2
2
  * Copyright (c) 2011, Peter Ohler
3
3
  * All rights reserved.
4
- *
5
- * Redistribution and use in source and binary forms, with or without
6
- * modification, are permitted provided that the following conditions are met:
7
- *
8
- * - Redistributions of source code must retain the above copyright notice, this
9
- * list of conditions and the following disclaimer.
10
- *
11
- * - Redistributions in binary form must reproduce the above copyright notice,
12
- * this list of conditions and the following disclaimer in the documentation
13
- * and/or other materials provided with the distribution.
14
- *
15
- * - Neither the name of Peter Ohler nor the names of its contributors may be
16
- * used to endorse or promote products derived from this software without
17
- * specific prior written permission.
18
- *
19
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
4
  */
30
5
 
31
6
  #ifndef __OJ_ODD_H__
@@ -48,8 +23,8 @@ typedef struct _Odd {
48
23
  int attr_cnt;
49
24
  bool is_module;
50
25
  bool raw;
51
- const char *attr_names[MAX_ODD_ARGS]; // 0 terminated attr IDs
52
- ID attrs[MAX_ODD_ARGS]; // 0 terminated attr IDs
26
+ const char *attr_names[MAX_ODD_ARGS]; // NULL terminated attr names
27
+ ID attrs[MAX_ODD_ARGS]; // 0 terminated attr IDs
53
28
  AttrGetFunc attrFuncs[MAX_ODD_ARGS];
54
29
  } *Odd;
55
30
 
@@ -1,32 +1,6 @@
1
1
  /* oj.c
2
2
  * Copyright (c) 2012, Peter Ohler
3
- *
4
3
  * All rights reserved.
5
- *
6
- * Redistribution and use in source and binary forms, with or without
7
- * modification, are permitted provided that the following conditions are met:
8
- *
9
- * - Redistributions of source code must retain the above copyright notice, this
10
- * list of conditions and the following disclaimer.
11
- *
12
- * - Redistributions in binary form must reproduce the above copyright notice,
13
- * this list of conditions and the following disclaimer in the documentation
14
- * and/or other materials provided with the distribution.
15
- *
16
- * - Neither the name of Peter Ohler nor the names of its contributors may be
17
- * used to endorse or promote products derived from this software without
18
- * specific prior written permission.
19
- *
20
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
4
  */
31
5
 
32
6
  #include <stdlib.h>
@@ -41,8 +15,14 @@
41
15
  #include "parse.h"
42
16
  #include "hash.h"
43
17
  #include "odd.h"
18
+ #include "dump.h"
19
+ #include "mimic_rails.h"
44
20
  #include "encode.h"
45
21
 
22
+ #if !HAS_ENCODING_SUPPORT || defined(RUBINIUS_RUBY)
23
+ #define rb_eEncodingError rb_eException
24
+ #endif
25
+
46
26
  typedef struct _YesNoOpt {
47
27
  VALUE sym;
48
28
  char *attr;
@@ -57,10 +37,14 @@ ID oj_array_append_id;
57
37
  ID oj_array_end_id;
58
38
  ID oj_array_start_id;
59
39
  ID oj_as_json_id;
40
+ ID oj_begin_id;
41
+ ID oj_end_id;
42
+ ID oj_exclude_end_id;
60
43
  ID oj_error_id;
61
44
  ID oj_file_id;
62
45
  ID oj_fileno_id;
63
46
  ID oj_ftype_id;
47
+ ID oj_has_key_id;
64
48
  ID oj_hash_end_id;
65
49
  ID oj_hash_key_id;
66
50
  ID oj_hash_set_id;
@@ -77,6 +61,7 @@ ID oj_readpartial_id;
77
61
  ID oj_replace_id;
78
62
  ID oj_stat_id;
79
63
  ID oj_string_id;
64
+ ID oj_to_h_id;
80
65
  ID oj_to_hash_id;
81
66
  ID oj_to_json_id;
82
67
  ID oj_to_s_id;
@@ -90,13 +75,13 @@ ID oj_utc_offset_id;
90
75
  ID oj_utcq_id;
91
76
  ID oj_write_id;
92
77
 
93
- static ID has_key_id;
94
78
 
95
79
  VALUE oj_bag_class;
96
80
  VALUE oj_bigdecimal_class;
97
81
  VALUE oj_cstack_class;
98
82
  VALUE oj_date_class;
99
83
  VALUE oj_datetime_class;
84
+ VALUE oj_enumerable_class;
100
85
  VALUE oj_parse_error_class;
101
86
  VALUE oj_stream_writer_class;
102
87
  VALUE oj_string_writer_class;
@@ -105,9 +90,17 @@ VALUE oj_struct_class;
105
90
 
106
91
  VALUE oj_slash_string;
107
92
 
93
+ VALUE oj_allow_nan_sym;
94
+ VALUE oj_array_class_sym;
95
+ VALUE oj_create_additions_sym;
96
+ VALUE oj_hash_class_sym;
97
+ VALUE oj_indent_sym;
98
+ VALUE oj_object_class_sym;
99
+ VALUE oj_quirks_mode_sym;
100
+
101
+ static VALUE allow_blank_sym;
108
102
  static VALUE allow_gc_sym;
109
103
  static VALUE allow_invalid_unicode_sym;
110
- static VALUE ascii_only_sym;
111
104
  static VALUE ascii_sym;
112
105
  static VALUE auto_define_sym;
113
106
  static VALUE auto_sym;
@@ -118,46 +111,38 @@ static VALUE circular_sym;
118
111
  static VALUE class_cache_sym;
119
112
  static VALUE compat_sym;
120
113
  static VALUE create_id_sym;
114
+ static VALUE custom_sym;
115
+ static VALUE empty_string_sym;
121
116
  static VALUE escape_mode_sym;
122
117
  static VALUE float_prec_sym;
123
118
  static VALUE float_sym;
124
- static VALUE hash_class_sym;
125
119
  static VALUE huge_sym;
126
- static VALUE indent_sym;
127
- static VALUE json_parser_error_class;
128
120
  static VALUE json_sym;
121
+ static VALUE match_string_sym;
129
122
  static VALUE mode_sym;
130
123
  static VALUE nan_sym;
131
124
  static VALUE newline_sym;
132
125
  static VALUE nilnil_sym;
133
- static VALUE empty_string_sym;
134
126
  static VALUE null_sym;
135
127
  static VALUE object_sym;
136
128
  static VALUE omit_nil_sym;
137
- static VALUE quirks_mode_sym;
129
+ static VALUE rails_sym;
138
130
  static VALUE raise_sym;
139
131
  static VALUE ruby_sym;
140
132
  static VALUE sec_prec_sym;
141
133
  static VALUE strict_sym;
142
134
  static VALUE symbol_keys_sym;
143
135
  static VALUE time_format_sym;
136
+ static VALUE unicode_xss_sym;
144
137
  static VALUE unix_sym;
145
138
  static VALUE unix_zone_sym;
146
139
  static VALUE use_as_json_sym;
140
+ static VALUE use_to_hash_sym;
147
141
  static VALUE use_to_json_sym;
148
142
  static VALUE word_sym;
149
143
  static VALUE xmlschema_sym;
150
144
  static VALUE xss_safe_sym;
151
145
 
152
- static VALUE array_nl_sym;
153
- static VALUE create_additions_sym;
154
- static VALUE object_nl_sym;
155
- static VALUE space_before_sym;
156
- static VALUE space_sym;
157
- static VALUE symbolize_names_sym;
158
-
159
- static VALUE mimic = Qnil;
160
-
161
146
  #if HAS_ENCODING_SUPPORT
162
147
  rb_encoding *oj_utf8_encoding = 0;
163
148
  #else
@@ -169,6 +154,7 @@ pthread_mutex_t oj_cache_mutex;
169
154
  #elif USE_RB_MUTEX
170
155
  VALUE oj_cache_mutex = Qnil;
171
156
  #endif
157
+
172
158
  static const char json_class[] = "json_class";
173
159
 
174
160
  struct _Options oj_default_options = {
@@ -179,22 +165,26 @@ struct _Options oj_default_options = {
179
165
  JSONEsc, // escape_mode
180
166
  ObjectMode, // mode
181
167
  Yes, // class_cache
182
- UnixZTime, // time_format
168
+ UnixTime, // time_format
183
169
  Yes, // bigdec_as_num
184
170
  AutoDec, // bigdec_load
171
+ No, // to_hash
185
172
  No, // to_json
186
173
  No, // as_json
187
174
  No, // nilnil
188
175
  Yes, // empty_string
189
176
  Yes, // allow_gc
190
177
  Yes, // quirks_mode
191
- No, // allow_invalid
178
+ No, // allow_invalid
179
+ No, // create_ok
180
+ Yes, // allow_nan
192
181
  json_class, // create_id
193
182
  10, // create_id_len
194
183
  9, // sec_prec
195
- 15, // float_prec
184
+ 16, // float_prec
196
185
  "%0.15g", // float_fmt
197
186
  Qnil, // hash_class
187
+ Qnil, // array_class
198
188
  { // dump_opts
199
189
  false, //use
200
190
  "", // indent
@@ -209,52 +199,60 @@ struct _Options oj_default_options = {
209
199
  0, // array_size
210
200
  AutoNan,// nan_dump
211
201
  false, // omit_nil
202
+ MAX_DEPTH, // max_depth
203
+ },
204
+ { // str_rx
205
+ NULL, // head
206
+ NULL, // tail
207
+ { '\0' }, // err
212
208
  }
213
209
  };
214
210
 
215
- static VALUE define_mimic_json(int argc, VALUE *argv, VALUE self);
216
-
217
- /* call-seq: default_options() => Hash
211
+ /* Document-method: default_options()
212
+ * call-seq: default_options()
218
213
  *
219
214
  * Returns the default load and dump options as a Hash. The options are
220
- * - indent: [Fixnum|String|nil] number of spaces to indent each element in an JSON document, zero or nil is no newline between JSON elements, negative indicates no newline between top level JSON elements in a stream, a String indicates the string should be used for indentation
221
- * - circular: [true|false|nil] support circular references while dumping
222
- * - auto_define: [true|false|nil] automatically define classes if they do not exist
223
- * - symbol_keys: [true|false|nil] use symbols instead of strings for hash keys
224
- * - escape_mode: [:newline|:json|:xss_safe|:ascii|nil] determines the characters to escape
225
- * - class_cache: [true|false|nil] cache classes for faster parsing (if dynamically modifying classes or reloading classes then don't use this)
226
- * - mode: [:object|:strict|:compat|:null] load and dump modes to use for JSON
227
- * - time_format: [:unix|:unix_zone|:xmlschema|:ruby] time format when dumping in :compat and :object mode
228
- * - bigdecimal_as_decimal: [true|false|nil] dump BigDecimal as a decimal number or as a String
229
- * - bigdecimal_load: [:bigdecimal|:float|:auto] load decimals as BigDecimal instead of as a Float. :auto pick the most precise for the number of digits.
230
- * - create_id: [String|nil] create id for json compatible object encoding, default is 'json_create'
231
- * - second_precision: [Fixnum|nil] number of digits after the decimal when dumping the seconds portion of time
232
- * - float_precision: [Fixnum|nil] number of digits of precision when dumping floats, 0 indicates use Ruby
233
- * - use_to_json: [true|false|nil] call to_json() methods on dump, default is false
234
- * - use_as_json: [true|false|nil] call as_json() methods on dump, default is false
235
- * - nilnil: [true|false|nil] if true a nil input to load will return nil and not raise an Exception
236
- * - empty_string: [true|false|nil] if true an empty input will not raise an Exception
237
- * - allow_gc: [true|false|nil] allow or prohibit GC during parsing, default is true (allow)
238
- * - quirks_mode: [true,|false|nil] Allow single JSON values instead of documents, default is true (allow)
239
- * - allow_invalid_unicode: [true,|false|nil] Allow invalid unicode, default is false (don't allow)
240
- * - indent_str: [String|nil] String to use for indentation, overriding the indent option is not nil
241
- * - space: [String|nil] String to use for the space after the colon in JSON object fields
242
- * - space_before: [String|nil] String to use before the colon separator in JSON object fields
243
- * - object_nl: [String|nil] String to use after a JSON object field value
244
- * - array_nl: [String|nil] String to use after a JSON array value
245
- * - nan: [:null|:huge|:word|:raise|:auto] how to dump Infinity and NaN in null, strict, and compat mode. :null places a null, :huge places a huge number, :word places Infinity or NaN, :raise raises and exception, :auto uses default for each mode.
246
- * - hash_class: [Class|nil] Class to use instead of Hash on load
247
- * - omit_nil: [true|false] if true Hash and Object attributes with nil values are omitted
248
- * @return [Hash] all current option settings.
215
+ * - *:indent* [_Fixnum_|_String_|_nil_] number of spaces to indent each element in an JSON document, zero or nil is no newline between JSON elements, negative indicates no newline between top level JSON elements in a stream, a String indicates the string should be used for indentation
216
+ * - *:circular* [_Boolean_|_nil_] support circular references while dumping
217
+ * - *:auto_define* [_Boolean_|_nil_] automatically define classes if they do not exist
218
+ * - *:symbol_keys* [_Boolean_|_nil_] use symbols instead of strings for hash keys
219
+ * - *:escape_mode* [_:newline_|_:json_|_:xss_safe_|_:ascii_|_unicode_xss_|_nil_] determines the characters to escape
220
+ * - *:class_cache* [_Boolean_|_nil_] cache classes for faster parsing (if dynamically modifying classes or reloading classes then don't use this)
221
+ * - *:mode* [_:object_|_:strict_|_:compat_|_:null_|_:custom_|_:rails_] load and dump modes to use for JSON
222
+ * - *:time_format* [_:unix_|_:unix_zone_|_:xmlschema_|_:ruby_] time format when dumping in :compat and :object mode
223
+ * - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or as a String
224
+ * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_] load decimals as BigDecimal instead of as a Float. :auto pick the most precise for the number of digits.
225
+ * - *:create_id* [_String_|_nil_] create id for json compatible object encoding, default is 'json_create'
226
+ * - *:second_precision* [_Fixnum_|_nil_] number of digits after the decimal when dumping the seconds portion of time
227
+ * - *:float_precision* [_Fixnum_|_nil_] number of digits of precision when dumping floats, 0 indicates use Ruby
228
+ * - *:use_to_json* [_Boolean_|_nil_] call to_json() methods on dump, default is false
229
+ * - *:use_as_json* [_Boolean_|_nil_] call as_json() methods on dump, default is false
230
+ * - *:nilnil* [_Boolean_|_nil_] if true a nil input to load will return nil and not raise an Exception
231
+ * - *:empty_string* [_Boolean_|_nil_] if true an empty input will not raise an Exception
232
+ * - *:allow_gc* [_Boolean_|_nil_] allow or prohibit GC during parsing, default is true (allow)
233
+ * - *:quirks_mode* [_true,_|_false_|_nil_] Allow single JSON values instead of documents, default is true (allow)
234
+ * - *:allow_invalid_unicode* [_true,_|_false_|_nil_] Allow invalid unicode, default is false (don't allow)
235
+ * - *:allow_nan* [_true,_|_false_|_nil_] Allow Nan, Infinity, and -Infinity to be parsed, default is true (allow)
236
+ * - *:indent_str* [_String_|_nil_] String to use for indentation, overriding the indent option is not nil
237
+ * - *:space* [_String_|_nil_] String to use for the space after the colon in JSON object fields
238
+ * - *:space_before* [_String_|_nil_] String to use before the colon separator in JSON object fields
239
+ * - *:object_nl* [_String_|_nil_] String to use after a JSON object field value
240
+ * - *:array_nl* [_String_|_nil_] String to use after a JSON array value
241
+ * - *:nan* [_:null_|_:huge_|_:word_|_:raise_|_:auto_] how to dump Infinity and NaN in null, strict, and compat mode. :null places a null, :huge places a huge number, :word places Infinity or NaN, :raise raises and exception, :auto uses default for each mode.
242
+ * - *:hash_class* [_Class_|_nil_] Class to use instead of Hash on load, :object_class can also be used
243
+ * - *:array_class* [_Class_|_nil_] Class to use instead of Array on load
244
+ * - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted
245
+ *
246
+ * Return [_Hash_] all current option settings.
249
247
  */
250
248
  static VALUE
251
249
  get_def_opts(VALUE self) {
252
250
  VALUE opts = rb_hash_new();
253
251
 
254
252
  if (0 == oj_default_options.dump_opts.indent_size) {
255
- rb_hash_aset(opts, indent_sym, INT2FIX(oj_default_options.indent));
253
+ rb_hash_aset(opts, oj_indent_sym, INT2FIX(oj_default_options.indent));
256
254
  } else {
257
- rb_hash_aset(opts, indent_sym, rb_str_new2(oj_default_options.dump_opts.indent_str));
255
+ rb_hash_aset(opts, oj_indent_sym, rb_str_new2(oj_default_options.dump_opts.indent_str));
258
256
  }
259
257
  rb_hash_aset(opts, sec_prec_sym, INT2FIX(oj_default_options.sec_prec));
260
258
  rb_hash_aset(opts, circular_sym, (Yes == oj_default_options.circular) ? Qtrue : ((No == oj_default_options.circular) ? Qfalse : Qnil));
@@ -263,18 +261,22 @@ get_def_opts(VALUE self) {
263
261
  rb_hash_aset(opts, symbol_keys_sym, (Yes == oj_default_options.sym_key) ? Qtrue : ((No == oj_default_options.sym_key) ? Qfalse : Qnil));
264
262
  rb_hash_aset(opts, bigdecimal_as_decimal_sym, (Yes == oj_default_options.bigdec_as_num) ? Qtrue : ((No == oj_default_options.bigdec_as_num) ? Qfalse : Qnil));
265
263
  rb_hash_aset(opts, use_to_json_sym, (Yes == oj_default_options.to_json) ? Qtrue : ((No == oj_default_options.to_json) ? Qfalse : Qnil));
264
+ rb_hash_aset(opts, use_to_hash_sym, (Yes == oj_default_options.to_hash) ? Qtrue : ((No == oj_default_options.to_hash) ? Qfalse : Qnil));
266
265
  rb_hash_aset(opts, use_as_json_sym, (Yes == oj_default_options.as_json) ? Qtrue : ((No == oj_default_options.as_json) ? Qfalse : Qnil));
267
266
  rb_hash_aset(opts, nilnil_sym, (Yes == oj_default_options.nilnil) ? Qtrue : ((No == oj_default_options.nilnil) ? Qfalse : Qnil));
268
267
  rb_hash_aset(opts, empty_string_sym, (Yes == oj_default_options.empty_string) ? Qtrue : ((No == oj_default_options.empty_string) ? Qfalse : Qnil));
269
268
  rb_hash_aset(opts, allow_gc_sym, (Yes == oj_default_options.allow_gc) ? Qtrue : ((No == oj_default_options.allow_gc) ? Qfalse : Qnil));
270
- rb_hash_aset(opts, quirks_mode_sym, (Yes == oj_default_options.quirks_mode) ? Qtrue : ((No == oj_default_options.quirks_mode) ? Qfalse : Qnil));
269
+ rb_hash_aset(opts, oj_quirks_mode_sym, (Yes == oj_default_options.quirks_mode) ? Qtrue : ((No == oj_default_options.quirks_mode) ? Qfalse : Qnil));
271
270
  rb_hash_aset(opts, allow_invalid_unicode_sym, (Yes == oj_default_options.allow_invalid) ? Qtrue : ((No == oj_default_options.allow_invalid) ? Qfalse : Qnil));
271
+ rb_hash_aset(opts, oj_allow_nan_sym, (Yes == oj_default_options.allow_nan) ? Qtrue : ((No == oj_default_options.allow_nan) ? Qfalse : Qnil));
272
272
  rb_hash_aset(opts, float_prec_sym, INT2FIX(oj_default_options.float_prec));
273
273
  switch (oj_default_options.mode) {
274
274
  case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break;
275
275
  case CompatMode: rb_hash_aset(opts, mode_sym, compat_sym); break;
276
276
  case NullMode: rb_hash_aset(opts, mode_sym, null_sym); break;
277
277
  case ObjectMode:
278
+ case CustomMode: rb_hash_aset(opts, mode_sym, custom_sym); break;
279
+ case RailsMode: rb_hash_aset(opts, mode_sym, rails_sym); break;
278
280
  default: rb_hash_aset(opts, mode_sym, object_sym); break;
279
281
  }
280
282
  switch (oj_default_options.escape_mode) {
@@ -282,6 +284,7 @@ get_def_opts(VALUE self) {
282
284
  case JSONEsc: rb_hash_aset(opts, escape_mode_sym, json_sym); break;
283
285
  case XSSEsc: rb_hash_aset(opts, escape_mode_sym, xss_safe_sym); break;
284
286
  case ASCIIEsc: rb_hash_aset(opts, escape_mode_sym, ascii_sym); break;
287
+ case JXEsc: rb_hash_aset(opts, escape_mode_sym, unicode_xss_sym); break;
285
288
  default: rb_hash_aset(opts, escape_mode_sym, json_sym); break;
286
289
  }
287
290
  switch (oj_default_options.time_format) {
@@ -298,10 +301,10 @@ get_def_opts(VALUE self) {
298
301
  default: rb_hash_aset(opts, bigdecimal_load_sym, auto_sym); break;
299
302
  }
300
303
  rb_hash_aset(opts, create_id_sym, (0 == oj_default_options.create_id) ? Qnil : rb_str_new2(oj_default_options.create_id));
301
- rb_hash_aset(opts, space_sym, (0 == oj_default_options.dump_opts.after_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.after_sep));
302
- rb_hash_aset(opts, space_before_sym, (0 == oj_default_options.dump_opts.before_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.before_sep));
303
- rb_hash_aset(opts, object_nl_sym, (0 == oj_default_options.dump_opts.hash_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.hash_nl));
304
- rb_hash_aset(opts, array_nl_sym, (0 == oj_default_options.dump_opts.array_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.array_nl));
304
+ rb_hash_aset(opts, oj_space_sym, (0 == oj_default_options.dump_opts.after_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.after_sep));
305
+ rb_hash_aset(opts, oj_space_before_sym, (0 == oj_default_options.dump_opts.before_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.before_sep));
306
+ rb_hash_aset(opts, oj_object_nl_sym, (0 == oj_default_options.dump_opts.hash_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.hash_nl));
307
+ rb_hash_aset(opts, oj_array_nl_sym, (0 == oj_default_options.dump_opts.array_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.array_nl));
305
308
 
306
309
  switch (oj_default_options.dump_opts.nan_dump) {
307
310
  case NullNan: rb_hash_aset(opts, nan_sym, null_sym); break;
@@ -312,56 +315,46 @@ get_def_opts(VALUE self) {
312
315
  default: rb_hash_aset(opts, nan_sym, auto_sym); break;
313
316
  }
314
317
  rb_hash_aset(opts, omit_nil_sym, oj_default_options.dump_opts.omit_nil ? Qtrue : Qfalse);
315
- rb_hash_aset(opts, hash_class_sym, oj_default_options.hash_class);
318
+ rb_hash_aset(opts, oj_hash_class_sym, oj_default_options.hash_class);
319
+ rb_hash_aset(opts, oj_array_class_sym, oj_default_options.array_class);
316
320
 
317
321
  return opts;
318
322
  }
319
323
 
320
- /* call-seq: default_options=(opts)
324
+ /* Document-method: default_options=
325
+ * call-seq: default_options=(opts)
321
326
  *
322
327
  * Sets the default options for load and dump.
323
- * @param [Hash] opts options to change
324
- * @param [Fixnum|String|nil] :indent number of spaces to indent each element in a JSON document or the String to use for identation.
325
- * @param [true|false|nil] :circular support circular references while dumping
326
- * @param [true|false|nil] :auto_define automatically define classes if they do not exist
327
- * @param [true|false|nil] :symbol_keys convert hash keys to symbols
328
- * @param [true|false|nil] :class_cache cache classes for faster parsing
329
- * @param [:newline|:json|:xss_safe|:ascii|nil] :escape mode encodes all high-bit characters as
330
- * escaped sequences if :ascii, :json is standand UTF-8 JSON encoding,
331
- * :newline is the same as :json but newlines are not escaped,
332
- * and :xss_safe escapes &, <, and >, and some others.
333
- * @param [true|false|nil] :bigdecimal_as_decimal dump BigDecimal as a decimal number or as a String
334
- * @param [:bigdecimal|:float|:auto|nil] :bigdecimal_load load decimals as BigDecimal instead of as a Float. :auto pick the most precise for the number of digits.
335
- * @param [:object|:strict|:compat|:null] load and dump mode to use for JSON
336
- * :strict raises an exception when a non-supported Object is
337
- * encountered. :compat attempts to extract variable values from an
338
- * Object using to_json() or to_hash() then it walks the Object's
339
- * variables if neither is found. The :object mode ignores to_hash()
340
- * and to_json() methods and encodes variables using code internal to
341
- * the Oj gem. The :null mode ignores non-supported Objects and
342
- * replaces them with a null.
343
- * @param [:unix|:xmlschema|:ruby] time format when dumping in :compat mode
344
- * :unix decimal number denoting the number of seconds since 1/1/1970,
345
- * :unix_zone decimal number denoting the number of seconds since 1/1/1970 plus the utc_offset in the exponent ,
346
- * :xmlschema date-time format taken from XML Schema as a String,
347
- * :ruby Time.to_s formatted String
348
- * @param [String|nil] :create_id create id for json compatible object encoding
349
- * @param [Fixnum|nil] :second_precision number of digits after the decimal when dumping the seconds portion of time
350
- * @param [Fixnum|nil] :float_precision number of digits of precision when dumping floats, 0 indicates use Ruby
351
- * @param [true|false|nil] :use_to_json call to_json() methods on dump, default is false
352
- * @param [true|false|nil] :use_as_json call as_json() methods on dump, default is false
353
- * @param [true|false|nil] :nilnil if true a nil input to load will return nil and not raise an Exception
354
- * @param [true|false|nil] :allow_gc allow or prohibit GC during parsing, default is true (allow)
355
- * @param [true|false|nil] :quirks_mode allow single JSON values instead of documents, default is true (allow)
356
- * @param [true|false|nil] :allow_invalid_unicode allow invalid unicode, default is false (don't allow)
357
- * @param [String|nil] :space String to use for the space after the colon in JSON object fields
358
- * @param [String|nil] :space_before String to use before the colon separator in JSON object fields
359
- * @param [String|nil] :object_nl String to use after a JSON object field value
360
- * @param [String|nil] :array_nl String to use after a JSON array value
361
- * @param [:null|:huge|:word|:raise] :nan how to dump Infinity and NaN in null, strict, and compat mode. :null places a null, :huge places a huge number, :word places Infinity or NaN, :raise raises and exception, :auto uses default for each mode.
362
- * @param [Class|nil] :hash_class Class to use instead of Hash on load
363
- * @param [true|false] :omit_nil if true Hash and Object attributes with nil values are omitted
364
- * @return [nil]
328
+ * - *opts* [_Hash_] options to change
329
+ * - *:indent* [_Fixnum_|_String_|_nil_] number of spaces to indent each element in a JSON document or the String to use for identation.
330
+ * - :circular [_Boolean_|_nil_] support circular references while dumping.
331
+ * - *:auto_define* [_Boolean_|_nil_] automatically define classes if they do not exist.
332
+ * - *:symbol_keys* [_Boolean_|_nil_] convert hash keys to symbols.
333
+ * - *:class_cache* [_Boolean_|_nil_] cache classes for faster parsing.
334
+ * - *:escape* [_:newline_|_:json_|_:xss_safe_|_:ascii_|_unicode_xss_|_nil_] mode encodes all high-bit characters as escaped sequences if :ascii, :json is standand UTF-8 JSON encoding, :newline is the same as :json but newlines are not escaped, :unicode_xss allows unicode but escapes &, <, and >, and any \u20xx characters along with some others, and :xss_safe escapes &, <, and >, and some others.
335
+ * - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or as a String.
336
+ * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_nil_] load decimals as BigDecimal instead of as a Float. :auto pick the most precise for the number of digits.
337
+ * - *:mode* [_:object_|_:strict_|_:compat_|_:null_|_:custom_|_:rails_] load and dump mode to use for JSON :strict raises an exception when a non-supported Object is encountered. :compat attempts to extract variable values from an Object using to_json() or to_hash() then it walks the Object's variables if neither is found. The :object mode ignores to_hash() and to_json() methods and encodes variables using code internal to the Oj gem. The :null mode ignores non-supported Objects and replaces them with a null. The :custom mode honors all dump options. The :rails more mimics rails and Active behavior.
338
+ * - *:time_format* [_:unix_|_:xmlschema_|_:ruby_] time format when dumping in :compat mode :unix decimal number denoting the number of seconds since 1/1/1970, :unix_zone decimal number denoting the number of seconds since 1/1/1970 plus the utc_offset in the exponent, :xmlschema date-time format taken from XML Schema as a String, :ruby Time.to_s formatted String.
339
+ * - *:create_id* [_String_|_nil_] create id for json compatible object encoding
340
+ * - *:second_precision* [_Fixnum_|_nil_] number of digits after the decimal when dumping the seconds portion of time.
341
+ * - *:float_precision* [_Fixnum_|_nil_] number of digits of precision when dumping floats, 0 indicates use Ruby.
342
+ * - *:use_to_json* [_Boolean_|_nil_] call to_json() methods on dump, default is false.
343
+ * - *:use_as_json* [_Boolean_|_nil_] call as_json() methods on dump, default is false.
344
+ * - *:use_to_hash* [_Boolean_|_nil_] call to_hash() methods on dump, default is false.
345
+ * - *:nilnil* [_Boolean_|_nil_] if true a nil input to load will return nil and not raise an Exception.
346
+ * - *:allow_gc* [_Boolean_|_nil_] allow or prohibit GC during parsing, default is true (allow).
347
+ * - *:quirks_mode* [_Boolean_|_nil_] allow single JSON values instead of documents, default is true (allow).
348
+ * - *:allow_invalid_unicode* [_Boolean_|_nil_] allow invalid unicode, default is false (don't allow).
349
+ * - *:allow_nan* [_Boolean_|_nil_] allow Nan, Infinity, and -Infinity, default is true (allow).
350
+ * - *:space* [_String_|_nil_] String to use for the space after the colon in JSON object fields.
351
+ * - *:space_before* [_String_|_nil_] String to use before the colon separator in JSON object fields.
352
+ * - *:object_nl* [_String_|_nil_] String to use after a JSON object field value.
353
+ * - *:array_nl* [_String_|_nil_] String to use after a JSON array value
354
+ * - *:nan* [_:null_|_:huge_|_:word_|_:raise_] how to dump Infinity and NaN in null, strict, and compat mode. :null places a null, :huge places a huge number, :word places Infinity or NaN, :raise raises and exception, :auto uses default for each mode.
355
+ * - *:hash_class* [_Class_|_nil_] Class to use instead of Hash on load, :object_class can also be used.
356
+ * - *:array_class* [_Class_|_nil_] Class to use instead of Array on load.
357
+ * - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted.
365
358
  */
366
359
  static VALUE
367
360
  set_def_opts(VALUE self, VALUE opts) {
@@ -379,13 +372,17 @@ oj_parse_options(VALUE ropts, Options copts) {
379
372
  { symbol_keys_sym, &copts->sym_key },
380
373
  { class_cache_sym, &copts->class_cache },
381
374
  { bigdecimal_as_decimal_sym, &copts->bigdec_as_num },
375
+ { use_to_hash_sym, &copts->to_hash },
382
376
  { use_to_json_sym, &copts->to_json },
383
377
  { use_as_json_sym, &copts->as_json },
384
378
  { nilnil_sym, &copts->nilnil },
379
+ { allow_blank_sym, &copts->nilnil }, // same as nilnil
385
380
  { empty_string_sym, &copts->empty_string },
386
381
  { allow_gc_sym, &copts->allow_gc },
387
- { quirks_mode_sym, &copts->quirks_mode },
382
+ { oj_quirks_mode_sym, &copts->quirks_mode },
388
383
  { allow_invalid_unicode_sym, &copts->allow_invalid },
384
+ { oj_allow_nan_sym, &copts->allow_nan },
385
+ { oj_create_additions_sym, &copts->create_ok },
389
386
  { Qnil, 0 }
390
387
  };
391
388
  YesNoOpt o;
@@ -395,8 +392,8 @@ oj_parse_options(VALUE ropts, Options copts) {
395
392
  if (T_HASH != rb_type(ropts)) {
396
393
  return;
397
394
  }
398
- if (Qtrue == rb_funcall(ropts, has_key_id, 1, indent_sym)) {
399
- v = rb_hash_lookup(ropts, indent_sym);
395
+ if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_indent_sym)) {
396
+ v = rb_hash_lookup(ropts, oj_indent_sym);
400
397
  switch (rb_type(v)) {
401
398
  case T_NIL:
402
399
  copts->dump_opts.indent_size = 0;
@@ -429,11 +426,10 @@ oj_parse_options(VALUE ropts, Options copts) {
429
426
  rb_raise(rb_eArgError, ":float_precision must be a Integer.");
430
427
  }
431
428
  #else
432
- if (rb_cFixnum != rb_obj_class(v)) {
429
+ if (T_FIXNUM != rb_type(v)) {
433
430
  rb_raise(rb_eArgError, ":float_precision must be a Fixnum.");
434
431
  }
435
432
  #endif
436
- Check_Type(v, T_FIXNUM);
437
433
  n = FIX2INT(v);
438
434
  if (0 >= n) {
439
435
  *copts->float_fmt = '\0';
@@ -454,7 +450,7 @@ oj_parse_options(VALUE ropts, Options copts) {
454
450
  rb_raise(rb_eArgError, ":second_precision must be a Integer.");
455
451
  }
456
452
  #else
457
- if (rb_cFixnum != rb_obj_class(v)) {
453
+ if (T_FIXNUM != rb_type(v)) {
458
454
  rb_raise(rb_eArgError, ":second_precision must be a Fixnum.");
459
455
  }
460
456
  #endif
@@ -471,12 +467,16 @@ oj_parse_options(VALUE ropts, Options copts) {
471
467
  copts->mode = ObjectMode;
472
468
  } else if (strict_sym == v) {
473
469
  copts->mode = StrictMode;
474
- } else if (compat_sym == v) {
470
+ } else if (compat_sym == v || json_sym == v) {
475
471
  copts->mode = CompatMode;
476
472
  } else if (null_sym == v) {
477
473
  copts->mode = NullMode;
474
+ } else if (custom_sym == v) {
475
+ copts->mode = CustomMode;
476
+ } else if (rails_sym == v) {
477
+ copts->mode = RailsMode;
478
478
  } else {
479
- rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.");
479
+ rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, :null, :custom, or :rails.");
480
480
  }
481
481
  }
482
482
  if (Qnil != (v = rb_hash_lookup(ropts, time_format_sym))) {
@@ -501,8 +501,10 @@ oj_parse_options(VALUE ropts, Options copts) {
501
501
  copts->escape_mode = XSSEsc;
502
502
  } else if (ascii_sym == v) {
503
503
  copts->escape_mode = ASCIIEsc;
504
+ } else if (unicode_xss_sym == v) {
505
+ copts->escape_mode = JXEsc;
504
506
  } else {
505
- rb_raise(rb_eArgError, ":encoding must be :newline, :json, :xss_safe, or :ascii.");
507
+ rb_raise(rb_eArgError, ":encoding must be :newline, :json, :xss_safe, :unicode_xss, or :ascii.");
506
508
  }
507
509
  }
508
510
  if (Qnil != (v = rb_hash_lookup(ropts, bigdecimal_load_sym))) {
@@ -516,7 +518,7 @@ oj_parse_options(VALUE ropts, Options copts) {
516
518
  rb_raise(rb_eArgError, ":bigdecimal_load must be :bigdecimal, :float, or :auto.");
517
519
  }
518
520
  }
519
- if (Qtrue == rb_funcall(ropts, has_key_id, 1, create_id_sym)) {
521
+ if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, create_id_sym)) {
520
522
  v = rb_hash_lookup(ropts, create_id_sym);
521
523
  if (Qnil == v) {
522
524
  if (json_class != oj_default_options.create_id) {
@@ -549,8 +551,8 @@ oj_parse_options(VALUE ropts, Options copts) {
549
551
  }
550
552
  }
551
553
  }
552
- if (Qtrue == rb_funcall(ropts, has_key_id, 1, space_sym)) {
553
- if (Qnil == (v = rb_hash_lookup(ropts, space_sym))) {
554
+ if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_space_sym)) {
555
+ if (Qnil == (v = rb_hash_lookup(ropts, oj_space_sym))) {
554
556
  copts->dump_opts.after_size = 0;
555
557
  *copts->dump_opts.after_sep = '\0';
556
558
  } else {
@@ -562,8 +564,8 @@ oj_parse_options(VALUE ropts, Options copts) {
562
564
  copts->dump_opts.after_size = (uint8_t)len;
563
565
  }
564
566
  }
565
- if (Qtrue == rb_funcall(ropts, has_key_id, 1, space_before_sym)) {
566
- if (Qnil == (v = rb_hash_lookup(ropts, space_before_sym))) {
567
+ if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_space_before_sym)) {
568
+ if (Qnil == (v = rb_hash_lookup(ropts, oj_space_before_sym))) {
567
569
  copts->dump_opts.before_size = 0;
568
570
  *copts->dump_opts.before_sep = '\0';
569
571
  } else {
@@ -575,8 +577,8 @@ oj_parse_options(VALUE ropts, Options copts) {
575
577
  copts->dump_opts.before_size = (uint8_t)len;
576
578
  }
577
579
  }
578
- if (Qtrue == rb_funcall(ropts, has_key_id, 1, object_nl_sym)) {
579
- if (Qnil == (v = rb_hash_lookup(ropts, object_nl_sym))) {
580
+ if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_object_nl_sym)) {
581
+ if (Qnil == (v = rb_hash_lookup(ropts, oj_object_nl_sym))) {
580
582
  copts->dump_opts.hash_size = 0;
581
583
  *copts->dump_opts.hash_nl = '\0';
582
584
  } else {
@@ -588,8 +590,8 @@ oj_parse_options(VALUE ropts, Options copts) {
588
590
  copts->dump_opts.hash_size = (uint8_t)len;
589
591
  }
590
592
  }
591
- if (Qtrue == rb_funcall(ropts, has_key_id, 1, array_nl_sym)) {
592
- if (Qnil == (v = rb_hash_lookup(ropts, array_nl_sym))) {
593
+ if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_array_nl_sym)) {
594
+ if (Qnil == (v = rb_hash_lookup(ropts, oj_array_nl_sym))) {
593
595
  copts->dump_opts.array_size = 0;
594
596
  *copts->dump_opts.array_nl = '\0';
595
597
  } else {
@@ -631,115 +633,76 @@ oj_parse_options(VALUE ropts, Options copts) {
631
633
  }
632
634
  }
633
635
  // This is here only for backwards compatibility with the original Oj.
634
- v = rb_hash_lookup(ropts, ascii_only_sym);
636
+ v = rb_hash_lookup(ropts, oj_ascii_only_sym);
635
637
  if (Qtrue == v) {
636
638
  copts->escape_mode = ASCIIEsc;
637
639
  } else if (Qfalse == v) {
638
640
  copts->escape_mode = JSONEsc;
639
641
  }
640
- if (Qtrue == rb_funcall(ropts, has_key_id, 1, hash_class_sym)) {
641
- if (Qnil == (v = rb_hash_lookup(ropts, hash_class_sym))) {
642
+ if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_hash_class_sym)) {
643
+ if (Qnil == (v = rb_hash_lookup(ropts, oj_hash_class_sym))) {
642
644
  copts->hash_class = Qnil;
643
645
  } else {
644
646
  rb_check_type(v, T_CLASS);
645
647
  copts->hash_class = v;
646
648
  }
647
649
  }
650
+ if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_object_class_sym)) {
651
+ if (Qnil == (v = rb_hash_lookup(ropts, oj_object_class_sym))) {
652
+ copts->hash_class = Qnil;
653
+ } else {
654
+ rb_check_type(v, T_CLASS);
655
+ copts->hash_class = v;
656
+ }
657
+ }
658
+ if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_array_class_sym)) {
659
+ if (Qnil == (v = rb_hash_lookup(ropts, oj_array_class_sym))) {
660
+ copts->array_class = Qnil;
661
+ } else {
662
+ rb_check_type(v, T_CLASS);
663
+ copts->array_class = v;
664
+ }
665
+ }
666
+ oj_parse_opt_match_string(&copts->str_rx, ropts);
648
667
  }
649
668
 
650
- /* Document-method: strict_load
651
- * call-seq: strict_load(json, options) => Hash, Array, String, Fixnum, Float, true, false, or nil
652
- *
653
- * Parses a JSON document String into an Hash, Array, String, Fixnum, Float,
654
- * true, false, or nil. It parses using a mode that is strict in that it maps
655
- * each primitive JSON type to a similar Ruby type. The :create_id is not
656
- * honored in this mode. Note that a Ruby Hash is used to represent the JSON
657
- * Object type. These two are not the same since the JSON Object type can have
658
- * repeating entries with the same key and Ruby Hash can not.
659
- *
660
- * When used with a document that has multiple JSON elements the block, if
661
- * any, will be yielded to. If no block then the last element read will be
662
- * returned.
663
- *
664
- * Raises an exception if the JSON is malformed or the classes specified are not
665
- * valid. If the input is not a valid JSON document (an empty string is not a
666
- * valid JSON document) an exception is raised.
667
- *
668
- * A block can also be provided with a single argument. That argument will be
669
- * the parsed JSON document. This is useful when parsing a string that includes
670
- * multiple JSON documents.
671
- *
672
- * @param [String|IO] json JSON String or an Object that responds to read()
673
- * @param [Hash] options load options (same as default_options)
674
- */
669
+ static int
670
+ match_string_cb(VALUE key, VALUE value, RxClass rc) {
671
+ if (T_CLASS != rb_type(value)) {
672
+ rb_raise(rb_eArgError, "for :match_string, the hash values must be a Class.");
673
+ }
674
+ switch (rb_type(key)) {
675
+ case T_REGEXP:
676
+ oj_rxclass_rappend(rc, key, value);
677
+ break;
678
+ case T_STRING:
679
+ if (0 != oj_rxclass_append(rc, StringValuePtr(key), value)) {
680
+ rb_raise(rb_eArgError, "%s", rc->err);
681
+ }
682
+ break;
683
+ default:
684
+ rb_raise(rb_eArgError, "for :match_string, keys must either a String or RegExp.");
685
+ break;
686
+ }
687
+ return ST_CONTINUE;
688
+ }
675
689
 
676
- /* Document-method: compat_load
677
- * call-seq: compat_load(json, options) => Object, Hash, Array, String, Fixnum, Float, true, false, or nil
678
- *
679
- * Parses a JSON document String into an Object, Hash, Array, String, Fixnum,
680
- * Float, true, false, or nil. It parses using a mode that is generally
681
- * compatible with other Ruby JSON parsers in that it will create objects based
682
- * on the :create_id value. It is not compatible in every way to every other
683
- * parser though as each parser has it's own variations.
684
- *
685
- * When used with a document that has multiple JSON elements the block, if
686
- * any, will be yielded to. If no block then the last element read will be
687
- * returned.
688
- *
689
- * Raises an exception if the JSON is malformed or the classes specified are not
690
- * valid. If the input is not a valid JSON document (an empty string is not a
691
- * valid JSON document) an exception is raised.
692
- *
693
- * A block can also be provided with a single argument. That argument will be
694
- * the parsed JSON document. This is useful when parsing a string that includes
695
- * multiple JSON documents.
696
- *
697
- * @param [String|IO] json JSON String or an Object that responds to read()
698
- * @param [Hash] options load options (same as default_options)
699
- */
690
+ void
691
+ oj_parse_opt_match_string(RxClass rc, VALUE ropts) {
692
+ VALUE v;
700
693
 
701
- /* Document-method: object_load
702
- * call-seq: object_load(json, options) => Object, Hash, Array, String, Fixnum, Float, true, false, or nil
703
- *
704
- * Parses a JSON document String into an Object, Hash, Array, String, Fixnum,
705
- * Float, true, false, or nil. In the :object mode the JSON should have been
706
- * generated by Oj.dump(). The parser will reconstitute the original marshalled
707
- * or dumped Object. The :auto_define and :circular options have meaning with
708
- * this parsing mode.
709
- *
710
- * When used with a document that has multiple JSON elements the block, if
711
- * any, will be yielded to. If no block then the last element read will be
712
- * returned.
713
- *
714
- * Raises an exception if the JSON is malformed or the classes specified are not
715
- * valid. If the input is not a valid JSON document (an empty string is not a
716
- * valid JSON document) an exception is raised.
717
- *
718
- * Note: Oj is not able to automatically deserialize all classes that are a
719
- * subclass of a Ruby Exception. Only exception that take one required string
720
- * argument in the initialize() method are supported. This is an example of how
721
- * to write an Exception subclass that supports both a single string intializer
722
- * and an Exception as an argument. Additional optional arguments can be added
723
- * as well.
724
- *
725
- * The reason for this restriction has to do with a design decision on the part
726
- * of the Ruby developers. Exceptions are special Objects. They do not follow the
727
- * rules of other Objects. Exceptions have 'mesg' and a 'bt' attribute. Note that
728
- * these are not '@mesg' and '@bt'. They can not be set using the normal C or
729
- * Ruby calls. The only way I have found to set the 'mesg' attribute is through
730
- * the initializer. Unfortunately that means any subclass that provides a
731
- * different initializer can not be automatically decoded. A way around this is
732
- * to use a create function but this example shows an alternative.
733
- *
734
- * A block can also be provided with a single argument. That argument will be
735
- * the parsed JSON document. This is useful when parsing a string that includes
736
- * multiple JSON documents.
737
- *
738
- * @param [String|IO] json JSON String or an Object that responds to read()
739
- * @param [Hash] options load options (same as default_options)
740
- */
694
+ if (Qnil != (v = rb_hash_lookup(ropts, match_string_sym))) {
695
+ rb_check_type(v, T_HASH);
696
+ // Zero out rc. Pattern are not appended but override.
697
+ rc->head = NULL;
698
+ rc->tail = NULL;
699
+ *rc->err = '\0';
700
+ rb_hash_foreach(v, match_string_cb, (VALUE)rc);
701
+ }
702
+ }
741
703
 
742
- /* call-seq: load(json, options) => Object, Hash, Array, String, Fixnum, Float, true, false, or nil
704
+ /* Document-method: load
705
+ * call-seq: load(json, options) { _|_obj, start, len_|_ }
743
706
  *
744
707
  * Parses a JSON document String into a Object, Hash, Array, String, Fixnum,
745
708
  * Float, true, false, or nil according to the default mode or the mode
@@ -755,12 +718,21 @@ oj_parse_options(VALUE ropts, Options copts) {
755
718
  * a file object is passed as the first argument. A stream input will be parsed
756
719
  * using a stream parser but others use the slightly faster string parser.
757
720
  *
758
- * A block can also be provided with a single argument. That argument will be
759
- * the parsed JSON document. This is useful when parsing a string that includes
760
- * multiple JSON documents.
761
- *
762
- * @param [String|IO] json JSON String or an Object that responds to read()
763
- * @param [Hash] options load options (same as default_options)
721
+ * A block can be provided with a single argument. That argument will be the
722
+ * parsed JSON document. This is useful when parsing a string that includes
723
+ * multiple JSON documents. The block can take up to 3 arguments, the parsed
724
+ * object, the position in the string or stream of the start of the JSON for
725
+ * that object, and the length of the JSON for that object plus trailing
726
+ * whitespace.
727
+ *
728
+ * - *json* [_String_|_IO_] JSON String or an Object that responds to read()
729
+ * - *options* [_Hash_] load options (same as default_options)
730
+ * - -
731
+ * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
732
+ * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
733
+ * - *len* [_optional, _Integer_] length of parsed JSON for obj.
734
+ *
735
+ * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_]
764
736
  */
765
737
  static VALUE
766
738
  load(int argc, VALUE *argv, VALUE self) {
@@ -779,21 +751,28 @@ load(int argc, VALUE *argv, VALUE self) {
779
751
  mode = ObjectMode;
780
752
  } else if (strict_sym == v) {
781
753
  mode = StrictMode;
782
- } else if (compat_sym == v) {
754
+ } else if (compat_sym == v || json_sym == v) {
783
755
  mode = CompatMode;
784
756
  } else if (null_sym == v) {
785
757
  mode = NullMode;
758
+ } else if (custom_sym == v) {
759
+ mode = CustomMode;
760
+ } else if (rails_sym == v) {
761
+ mode = RailsMode;
786
762
  } else {
787
- rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.");
763
+ rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, :null, :custom, or :rails.");
788
764
  }
789
765
  }
790
766
  }
791
767
  switch (mode) {
792
768
  case StrictMode:
793
- return oj_strict_parse(argc, argv, self);
794
769
  case NullMode:
770
+ return oj_strict_parse(argc, argv, self);
795
771
  case CompatMode:
772
+ case RailsMode:
796
773
  return oj_compat_parse(argc, argv, self);
774
+ case CustomMode:
775
+ return oj_custom_parse(argc, argv, self);
797
776
  case ObjectMode:
798
777
  default:
799
778
  break;
@@ -802,7 +781,7 @@ load(int argc, VALUE *argv, VALUE self) {
802
781
  }
803
782
 
804
783
  /* Document-method: load_file
805
- * call-seq: load_file(path, options) => Object, Hash, Array, String, Fixnum, Float, true, false, or nil
784
+ * call-seq: load_file(path, options) { _|_obj, start, len_|_ }
806
785
  *
807
786
  * Parses a JSON document String into a Object, Hash, Array, String, Fixnum,
808
787
  * Float, true, false, or nil according to the default mode or the mode
@@ -820,12 +799,21 @@ load(int argc, VALUE *argv, VALUE self) {
820
799
  * This is a stream based parser which allows a large or huge file to be loaded
821
800
  * without pulling the whole file into memory.
822
801
  *
823
- * A block can also be provided with a single argument. That argument will be
824
- * the parsed JSON document. This is useful when parsing a string that includes
825
- * multiple JSON documents.
826
- *
827
- * @param [String] path path to a file containing a JSON document
828
- * @param [Hash] options load options (same as default_options)
802
+ * A block can be provided with a single argument. That argument will be the
803
+ * parsed JSON document. This is useful when parsing a string that includes
804
+ * multiple JSON documents. The block can take up to 3 arguments, the parsed
805
+ * object, the position in the string or stream of the start of the JSON for
806
+ * that object, and the length of the JSON for that object plus trailing
807
+ * whitespace.
808
+ *
809
+ * - *path* [_String_] to a file containing a JSON document
810
+ * - *options* [_Hash_] load options (same as default_options)
811
+ * - -
812
+ * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
813
+ * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
814
+ * - *len* [_optional, _Integer_] length of parsed JSON for obj.
815
+ *
816
+ * Returns [_Object_|_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_]
829
817
  */
830
818
  static VALUE
831
819
  load_file(int argc, VALUE *argv, VALUE self) {
@@ -838,9 +826,11 @@ load_file(int argc, VALUE *argv, VALUE self) {
838
826
  rb_raise(rb_eArgError, "Wrong number of arguments to load().");
839
827
  }
840
828
  Check_Type(*argv, T_STRING);
829
+ parse_info_init(&pi);
841
830
  pi.options = oj_default_options;
842
831
  pi.handler = Qnil;
843
832
  pi.err_class = Qnil;
833
+ pi.max_depth = 0;
844
834
  if (2 <= argc) {
845
835
  VALUE ropts = argv[1];
846
836
  VALUE v;
@@ -851,12 +841,16 @@ load_file(int argc, VALUE *argv, VALUE self) {
851
841
  mode = ObjectMode;
852
842
  } else if (strict_sym == v) {
853
843
  mode = StrictMode;
854
- } else if (compat_sym == v) {
844
+ } else if (compat_sym == v || json_sym == v) {
855
845
  mode = CompatMode;
856
846
  } else if (null_sym == v) {
857
847
  mode = NullMode;
848
+ } else if (custom_sym == v) {
849
+ mode = CustomMode;
850
+ } else if (rails_sym == v) {
851
+ mode = RailsMode;
858
852
  } else {
859
- rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.");
853
+ rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, :null, :custom, :rails.");
860
854
  }
861
855
  }
862
856
  }
@@ -870,6 +864,8 @@ load_file(int argc, VALUE *argv, VALUE self) {
870
864
  return oj_pi_sparse(argc, argv, &pi, fd);
871
865
  case NullMode:
872
866
  case CompatMode:
867
+ case CustomMode:
868
+ case RailsMode:
873
869
  oj_set_compat_callbacks(&pi);
874
870
  return oj_pi_sparse(argc, argv, &pi, fd);
875
871
  case ObjectMode:
@@ -881,21 +877,25 @@ load_file(int argc, VALUE *argv, VALUE self) {
881
877
  return oj_pi_sparse(argc, argv, &pi, fd);
882
878
  }
883
879
 
884
- /* call-seq: safe_load(doc)
880
+ /* Document-method: safe_load
881
+ * call-seq: safe_load(doc)
885
882
  *
886
883
  * Loads a JSON document in strict mode with :auto_define and :symbol_keys
887
884
  * turned off. This function should be safe to use with JSON received on an
888
885
  * unprotected public interface.
889
886
  *
890
- * @param [String|IO] doc JSON String or IO to load
891
- * @return [Hash|Array|String|Fixnum|Bignum|BigDecimal|nil|True|False]
887
+ * - *doc* [_String__|_IO_] JSON String or IO to load.
888
+ *
889
+ * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Bignum_|_BigDecimal_|_nil_|_True_|_False_]
892
890
  */
893
891
  static VALUE
894
892
  safe_load(VALUE self, VALUE doc) {
895
893
  struct _ParseInfo pi;
896
894
  VALUE args[1];
897
895
 
896
+ parse_info_init(&pi);
898
897
  pi.err_class = Qnil;
898
+ pi.max_depth = 0;
899
899
  pi.options = oj_default_options;
900
900
  pi.options.auto_define = No;
901
901
  pi.options.sym_key = No;
@@ -906,18 +906,20 @@ safe_load(VALUE self, VALUE doc) {
906
906
  return oj_pi_parse(1, args, &pi, 0, 0, 1);
907
907
  }
908
908
 
909
- /* call-seq: saj_parse(handler, io)
909
+ /* Document-method: saj_parse
910
+ * call-seq: saj_parse(handler, io)
910
911
  *
911
912
  * Parses an IO stream or file containing a JSON document. Raises an exception
912
913
  * if the JSON is malformed. This is a callback parser that calls the methods in
913
914
  * the handler if they exist. A sample is the Oj::Saj class which can be used as
914
915
  * a base class for the handler.
915
916
  *
916
- * @param [Oj::Saj] handler responds to Oj::Saj methods
917
- * @param [IO|String] io IO Object to read from
917
+ * - *handler* [_Oj::Saj_] responds to Oj::Saj methods
918
+ * - *io* [_IO_|_String_] IO Object to read from
918
919
  */
919
920
 
920
- /* call-seq: sc_parse(handler, io)
921
+ /* Document-method: sc_parse
922
+ * call-seq: sc_parse(handler, io)
921
923
  *
922
924
  * Parses an IO stream or file containing a JSON document. Raises an exception
923
925
  * if the JSON is malformed. This is a callback parser (Simple Callback Parser)
@@ -926,15 +928,16 @@ safe_load(VALUE self, VALUE doc) {
926
928
  * callback parser is slightly more efficient than the Saj callback parser and
927
929
  * requires less argument checking.
928
930
  *
929
- * @param [Oj::ScHandler] handler responds to Oj::ScHandler methods
930
- * @param [IO|String] io IO Object to read from
931
+ * - *handler* [_Oj_::ScHandler_] responds to Oj::ScHandler methods
932
+ * - *io* [_IO__|_String_] IO Object to read from
931
933
  */
932
934
 
933
- /* call-seq: dump(obj, options) => json-string
935
+ /* Document-method: dump
936
+ * call-seq: dump(obj, options)
934
937
  *
935
938
  * Dumps an Object (obj) to a string.
936
- * @param [Object] obj Object to serialize as an JSON document String
937
- * @param [Hash] options same as default_options
939
+ * - *obj* [_Object_] Object to serialize as an JSON document String
940
+ * - *options* [_Hash_] same as default_options
938
941
  */
939
942
  static VALUE
940
943
  dump(int argc, VALUE *argv, VALUE self) {
@@ -949,10 +952,15 @@ dump(int argc, VALUE *argv, VALUE self) {
949
952
  if (2 == argc) {
950
953
  oj_parse_options(argv[1], &copts);
951
954
  }
955
+ if (CompatMode == copts.mode) {
956
+ copts.to_json = No;
957
+ copts.dump_opts.nan_dump = true;
958
+ }
952
959
  out.buf = buf;
953
960
  out.end = buf + sizeof(buf) - 10;
954
961
  out.allocated = 0;
955
962
  out.omit_nil = copts.dump_opts.omit_nil;
963
+ out.caller = CALLER_DUMP;
956
964
  oj_dump_obj_to_json(*argv, &copts, &out);
957
965
  if (0 == out.buf) {
958
966
  rb_raise(rb_eNoMemError, "Not enough memory.");
@@ -965,15 +973,68 @@ dump(int argc, VALUE *argv, VALUE self) {
965
973
  return rstr;
966
974
  }
967
975
 
976
+ /* Document-method: to_json
977
+ * call-seq: to_json(obj, options)
978
+ *
979
+ * Dumps an Object (obj) to a string. If the object has a to_json method that
980
+ * will be called. The mode is set to :compat.
981
+ * - *obj* [_Object_] Object to serialize as an JSON document String
982
+ * - *options* [_Hash_]
983
+ * - *:max_nesting* [_boolean_] It true nesting is limited to 100. The option to detect circular references is available but is not compatible with the json gem., default is false
984
+ * - *:allow_nan* [_boolean_] If true non JSON compliant words such as Nan and Infinity will be used as appropriate, default is true.
985
+ * - *:quirks_mode* [_boolean_] Allow single JSON values instead of documents, default is true (allow).
986
+ * - *:indent_str* [_String_|_nil_] String to use for indentation, overriding the indent option if not nil.
987
+ * - *:space* [_String_|_nil_] String to use for the space after the colon in JSON object fields.
988
+ * - *:space_before* [_String_|_nil_] String to use before the colon separator in JSON object fields.
989
+ * - *:object_nl* [_String_|_nil_] String to use after a JSON object field value.
990
+ * - *:array_nl* [_String_|_nil_] String to use after a JSON array value.
991
+ *
992
+ * Returns [_String_] the encoded JSON.
993
+ */
994
+ static VALUE
995
+ to_json(int argc, VALUE *argv, VALUE self) {
996
+ char buf[4096];
997
+ struct _Out out;
998
+ struct _Options copts = oj_default_options;
999
+ VALUE rstr;
1000
+
1001
+ if (1 > argc) {
1002
+ rb_raise(rb_eArgError, "wrong number of arguments (0 for 1).");
1003
+ }
1004
+ copts.dump_opts.nan_dump = false;
1005
+ if (2 == argc) {
1006
+ oj_parse_mimic_dump_options(argv[1], &copts);
1007
+ }
1008
+ copts.mode = CompatMode;
1009
+ copts.to_json = Yes;
1010
+ out.buf = buf;
1011
+ out.end = buf + sizeof(buf) - 10;
1012
+ out.allocated = 0;
1013
+ out.omit_nil = copts.dump_opts.omit_nil;
1014
+ // For obj.to_json or generate nan is not allowed but if called from dump
1015
+ // it is.
1016
+ copts.dump_opts.nan_dump = false;
1017
+ oj_dump_obj_to_json(*argv, &copts, &out);
1018
+ if (0 == out.buf) {
1019
+ rb_raise(rb_eNoMemError, "Not enough memory.");
1020
+ }
1021
+ rstr = rb_str_new2(out.buf);
1022
+ rstr = oj_encode(rstr);
1023
+ if (out.allocated) {
1024
+ xfree(out.buf);
1025
+ }
1026
+ return rstr;
1027
+ }
968
1028
 
969
- /* call-seq: to_file(file_path, obj, options)
1029
+ /* Document-method: to_file
1030
+ * call-seq: to_file(file_path, obj, options)
970
1031
  *
971
1032
  * Dumps an Object to the specified file.
972
- * @param [String] file_path file path to write the JSON document to
973
- * @param [Object] obj Object to serialize as an JSON document String
974
- * @param [Hash] options formating options
975
- * @param [Fixnum] :indent format expected
976
- * @param [true|false] :circular allow circular references, default: false
1033
+ * - *file* [_String_] _path file path to write the JSON document to
1034
+ * - *obj* [_Object_] Object to serialize as an JSON document String
1035
+ * - *options* [_Hash_] formating options
1036
+ * - *:indent* [_Fixnum_] format expected
1037
+ * - *:circular* [_Boolean_] allow circular references, default: false
977
1038
  */
978
1039
  static VALUE
979
1040
  to_file(int argc, VALUE *argv, VALUE self) {
@@ -988,14 +1049,15 @@ to_file(int argc, VALUE *argv, VALUE self) {
988
1049
  return Qnil;
989
1050
  }
990
1051
 
991
- /* call-seq: to_stream(io, obj, options)
1052
+ /* Document-method: to_stream
1053
+ * call-seq: to_stream(io, obj, options)
992
1054
  *
993
1055
  * Dumps an Object to the specified IO stream.
994
- * @param [IO] io IO stream to write the JSON document to
995
- * @param [Object] obj Object to serialize as an JSON document String
996
- * @param [Hash] options formating options
997
- * @param [Fixnum] :indent format expected
998
- * @param [true|false] :circular allow circular references, default: false
1056
+ * - *io* [_IO_] IO stream to write the JSON document to
1057
+ * - *obj* [_Object_] Object to serialize as an JSON document String
1058
+ * - *options* [_Hash_] formating options
1059
+ * - *:indent* [_Fixnum_] format expected
1060
+ * - *:circular* [_Boolean_] allow circular references, default: false
999
1061
  */
1000
1062
  static VALUE
1001
1063
  to_stream(int argc, VALUE *argv, VALUE self) {
@@ -1009,7 +1071,8 @@ to_stream(int argc, VALUE *argv, VALUE self) {
1009
1071
  return Qnil;
1010
1072
  }
1011
1073
 
1012
- /* call-seq: register_odd(clas, create_object, create_method, *members)
1074
+ /* Document-method: register_odd
1075
+ * call-seq: register_odd(clas, create_object, create_method, *members)
1013
1076
  *
1014
1077
  * Registers a class as special. This is useful for working around subclasses of
1015
1078
  * primitive types as is done with ActiveSupport classes. The use of this
@@ -1017,13 +1080,10 @@ to_stream(int argc, VALUE *argv, VALUE self) {
1017
1080
  * normal way. It is not intended as a hook for changing the output of all
1018
1081
  * classes as it is not optimized for large numbers of classes.
1019
1082
  *
1020
- * @param [Class|Module] clas Class or Module to be made special
1021
- * @param [Object] create_object object to call the create method on
1022
- * @param [Symbol] create_method method on the clas that will create a new
1023
- * instance of the clas when given all the member values in the
1024
- * order specified.
1025
- * @param [Symbol|String] members methods used to get the member values from
1026
- * instances of the clas
1083
+ * - *clas* [_Class__|_Module_] Class or Module to be made special
1084
+ * - *create_object* [_Object_] object to call the create method on
1085
+ * - *create_method* [_Symbol_] method on the clas that will create a new instance of the clas when given all the member values in the order specified.
1086
+ * - *members* [_Symbol__|_String_] methods used to get the member values from instances of the clas.
1027
1087
  */
1028
1088
  static VALUE
1029
1089
  register_odd(int argc, VALUE *argv, VALUE self) {
@@ -1047,7 +1107,8 @@ register_odd(int argc, VALUE *argv, VALUE self) {
1047
1107
  return Qnil;
1048
1108
  }
1049
1109
 
1050
- /* call-seq: register_odd_raw(clas, create_object, create_method, dump_method)
1110
+ /* Document-method: register_odd_raw
1111
+ * call-seq: register_odd_raw(clas, create_object, create_method, dump_method)
1051
1112
  *
1052
1113
  * Registers a class as special and expect the output to be a string that can be
1053
1114
  * included in the dumped JSON directly. This is useful for working around
@@ -1057,13 +1118,10 @@ register_odd(int argc, VALUE *argv, VALUE self) {
1057
1118
  * classes as it is not optimized for large numbers of classes. Be careful with
1058
1119
  * this option as the JSON may be incorrect if invalid JSON is returned.
1059
1120
  *
1060
- * @param [Class|Module] clas Class or Module to be made special
1061
- * @param [Object] create_object object to call the create method on
1062
- * @param [Symbol] create_method method on the clas that will create a new
1063
- * instance of the clas when given all the member values in the
1064
- * order specified.
1065
- * @param [Symbol|String] dump_method method to call on the object being
1066
- * serialized to generate the raw JSON.
1121
+ * - *clas* [_Class_|_Module_] Class or Module to be made special
1122
+ * - *create_object* [_Object_] object to call the create method on
1123
+ * - *create_method* [_Symbol_] method on the clas that will create a new instance of the clas when given all the member values in the order specified.
1124
+ * - *dump_method* [_Symbol_|_String_] method to call on the object being serialized to generate the raw JSON.
1067
1125
  */
1068
1126
  static VALUE
1069
1127
  register_odd_raw(int argc, VALUE *argv, VALUE self) {
@@ -1087,1019 +1145,215 @@ register_odd_raw(int argc, VALUE *argv, VALUE self) {
1087
1145
  return Qnil;
1088
1146
  }
1089
1147
 
1090
- static void
1091
- str_writer_free(void *ptr) {
1092
- StrWriter sw;
1148
+ ////////////////////////////////////////////////////////////////////////////////
1149
+ // RDoc entries must be in the same file as the rb_define_method and must be
1150
+ // directly above the C method function. The extern declaration is enough to
1151
+ // get it to work.
1152
+ ////////////////////////////////////////////////////////////////////////////////
1093
1153
 
1094
- if (0 == ptr) {
1095
- return;
1096
- }
1097
- sw = (StrWriter)ptr;
1098
- xfree(sw->out.buf);
1099
- xfree(sw->types);
1100
- xfree(ptr);
1101
- }
1154
+ /* Document-method: strict_load
1155
+ * call-seq: strict_load(json, options) { _|_obj, start, len_|_ }
1156
+ *
1157
+ * Parses a JSON document String into an Hash, Array, String, Fixnum, Float,
1158
+ * true, false, or nil. It parses using a mode that is strict in that it maps
1159
+ * each primitive JSON type to a similar Ruby type. The :create_id is not
1160
+ * honored in this mode. Note that a Ruby Hash is used to represent the JSON
1161
+ * Object type. These two are not the same since the JSON Object type can have
1162
+ * repeating entries with the same key and Ruby Hash can not.
1163
+ *
1164
+ * When used with a document that has multiple JSON elements the block, if
1165
+ * any, will be yielded to. If no block then the last element read will be
1166
+ * returned.
1167
+ *
1168
+ * Raises an exception if the JSON is malformed or the classes specified are not
1169
+ * valid. If the input is not a valid JSON document (an empty string is not a
1170
+ * valid JSON document) an exception is raised.
1171
+ *
1172
+ * A block can be provided with a single argument. That argument will be the
1173
+ * parsed JSON document. This is useful when parsing a string that includes
1174
+ * multiple JSON documents. The block can take up to 3 arguments, the parsed
1175
+ * object, the position in the string or stream of the start of the JSON for
1176
+ * that object, and the length of the JSON for that object plus trailing
1177
+ * whitespace.
1178
+ *
1179
+ * - *json* [_String_|_IO_] JSON String or an Object that responds to read().
1180
+ * - *options* [_Hash_] load options (same as default_options).
1181
+ * - -
1182
+ * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
1183
+ * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
1184
+ * - *len* [_optional, _Integer_] length of parsed JSON for obj.
1185
+ *
1186
+ * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_]
1187
+ */
1188
+ extern VALUE oj_strict_parse(int argc, VALUE *argv, VALUE self);
1102
1189
 
1103
- /* Document-class: Oj::StringWriter
1104
- *
1105
- * Supports building a JSON document one element at a time. Build the document
1106
- * by pushing values into the document. Pushing an array or an object will
1107
- * create that element in the JSON document and subsequent pushes will add the
1108
- * elements to that array or object until a pop() is called. When complete
1109
- * calling to_s() will return the JSON document. Note tha calling to_s() before
1110
- * construction is complete will return the document in it's current state.
1190
+ /* Document-method: compat_load
1191
+ * call-seq: compat_load(json, options) { _|_obj, start, len_|_ }
1192
+ *
1193
+ * Parses a JSON document String into an Object, Hash, Array, String, Fixnum,
1194
+ * Float, true, false, or nil. It parses using a mode that is generally
1195
+ * compatible with other Ruby JSON parsers in that it will create objects based
1196
+ * on the :create_id value. It is not compatible in every way to every other
1197
+ * parser though as each parser has it's own variations.
1198
+ *
1199
+ * When used with a document that has multiple JSON elements the block, if
1200
+ * any, will be yielded to. If no block then the last element read will be
1201
+ * returned.
1202
+ *
1203
+ * Raises an exception if the JSON is malformed or the classes specified are not
1204
+ * valid. If the input is not a valid JSON document (an empty string is not a
1205
+ * valid JSON document) an exception is raised.
1206
+ *
1207
+ * A block can be provided with a single argument. That argument will be the
1208
+ * parsed JSON document. This is useful when parsing a string that includes
1209
+ * multiple JSON documents. The block can take up to 3 arguments, the parsed
1210
+ * object, the position in the string or stream of the start of the JSON for
1211
+ * that object, and the length of the JSON for that object plus trailing
1212
+ * whitespace.
1213
+ *
1214
+ * - *json* [_String_|_IO_] JSON String or an Object that responds to read().
1215
+ * - *options* [_Hash_] load options (same as default_options).
1216
+ * - -
1217
+ * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
1218
+ * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
1219
+ * - *len* [_optional, _Integer_] length of parsed JSON for obj.
1220
+ *
1221
+ * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_]
1111
1222
  */
1223
+ extern VALUE oj_compat_parse(int argc, VALUE *argv, VALUE self);
1112
1224
 
1113
- static void
1114
- str_writer_init(StrWriter sw) {
1115
- sw->opts = oj_default_options;
1116
- sw->depth = 0;
1117
- sw->types = ALLOC_N(char, 256);
1118
- sw->types_end = sw->types + 256;
1119
- *sw->types = '\0';
1120
- sw->keyWritten = 0;
1121
-
1122
- sw->out.buf = ALLOC_N(char, 4096);
1123
- sw->out.end = sw->out.buf + 4086;
1124
- sw->out.allocated = 1;
1125
- sw->out.cur = sw->out.buf;
1126
- *sw->out.cur = '\0';
1127
- sw->out.circ_cnt = 0;
1128
- sw->out.hash_cnt = 0;
1129
- sw->out.opts = &sw->opts;
1130
- sw->out.indent = sw->opts.indent;
1131
- sw->out.depth = 0;
1132
- }
1225
+ /* Document-method: object_load
1226
+ * call-seq: object_load(json, options) { _|_obj, start, len_|_ }
1227
+ *
1228
+ * Parses a JSON document String into an Object, Hash, Array, String, Fixnum,
1229
+ * Float, true, false, or nil. In the :object mode the JSON should have been
1230
+ * generated by Oj.dump(). The parser will reconstitute the original marshalled
1231
+ * or dumped Object. The :auto_define and :circular options have meaning with
1232
+ * this parsing mode.
1233
+ *
1234
+ * Raises an exception if the JSON is malformed or the classes specified are not
1235
+ * valid. If the input is not a valid JSON document (an empty string is not a
1236
+ * valid JSON document) an exception is raised.
1237
+ *
1238
+ * Note: Oj is not able to automatically deserialize all classes that are a
1239
+ * subclass of a Ruby Exception. Only exception that take one required string
1240
+ * argument in the initialize() method are supported. This is an example of how
1241
+ * to write an Exception subclass that supports both a single string intializer
1242
+ * and an Exception as an argument. Additional optional arguments can be added
1243
+ * as well.
1244
+ *
1245
+ * The reason for this restriction has to do with a design decision on the part
1246
+ * of the Ruby developers. Exceptions are special Objects. They do not follow the
1247
+ * rules of other Objects. Exceptions have 'mesg' and a 'bt' attribute. Note that
1248
+ * these are not '@mesg' and '@bt'. They can not be set using the normal C or
1249
+ * Ruby calls. The only way I have found to set the 'mesg' attribute is through
1250
+ * the initializer. Unfortunately that means any subclass that provides a
1251
+ * different initializer can not be automatically decoded. A way around this is
1252
+ * to use a create function but this example shows an alternative.
1253
+ *
1254
+ * A block can be provided with a single argument. That argument will be the
1255
+ * parsed JSON document. This is useful when parsing a string that includes
1256
+ * multiple JSON documents. The block can take up to 3 arguments, the parsed
1257
+ * object, the position in the string or stream of the start of the JSON for
1258
+ * that object, and the length of the JSON for that object plus trailing
1259
+ * whitespace.
1260
+ *
1261
+ * - *json* [_String_|_IO_] JSON String or an Object that responds to read().
1262
+ * - *options* [_Hash_] load options (same as default_options).
1263
+ * - -
1264
+ * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
1265
+ * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
1266
+ * - *len* [_optional, _Integer_] length of parsed JSON for obj.
1267
+ *
1268
+ * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_]
1269
+ */
1270
+ extern VALUE oj_object_parse(int argc, VALUE *argv, VALUE self);
1133
1271
 
1134
- /* call-seq: new(options)
1272
+ /* Document-method: add_to_json
1273
+ * call-seq: add_to_json(*args)
1274
+ *
1275
+ * Override simple to_s dump behavior in :compat mode to instead use an
1276
+ * optimized dump that includes the classname and attributes so that the
1277
+ * object can be re-created on load. The format is the same as the json gem
1278
+ * but does not use the ruby methods for encoding.
1279
+ *
1280
+ * The classes supported for optimization are: Array, BigDecimal, Complex,
1281
+ * Date, DateTime, Exception, Hash, Integer, OpenStruct, Range, Rational,
1282
+ * Regexp, Struct, and Time. Providing no classes will result in all those
1283
+ * classes being optimized.q
1135
1284
  *
1136
- * Creates a new StringWriter.
1137
- * @param [Hash] options formating options
1285
+ * - *args( [_Class_] zero or more classes to optimize.
1138
1286
  */
1139
- static VALUE
1140
- str_writer_new(int argc, VALUE *argv, VALUE self) {
1141
- StrWriter sw = ALLOC(struct _StrWriter);
1142
-
1143
- str_writer_init(sw);
1144
- if (1 == argc) {
1145
- oj_parse_options(argv[0], &sw->opts);
1146
- }
1147
- sw->out.indent = sw->opts.indent;
1287
+ extern VALUE oj_add_to_json(int argc, VALUE *argv, VALUE self);
1148
1288
 
1149
- return Data_Wrap_Struct(oj_string_writer_class, 0, str_writer_free, sw);
1150
- }
1289
+ /* @!method remove_to_json(*args)
1290
+ *
1291
+ * Reverts back to the to_s dump behavior in :compat mode to instead use an
1292
+ * optimized dump that includes the classname and attributes so that the
1293
+ * object can be re-created on load. The format is the same as the json gem
1294
+ * but does not use the ruby methods for encoding.
1295
+ *
1296
+ * The classes supported for optimization are: Array, BigDecimal, Complex,
1297
+ * Date, DateTime, Exception, Hash, Integer, OpenStruct, Range, Rational,
1298
+ * Regexp, Struct, and Time. Providing no classes will result in all those
1299
+ * classes being reverted from the optimized mode.
1300
+ *
1301
+ * - *args* [_Class_] zero or more classes to optimize.
1302
+ */
1303
+ extern VALUE oj_remove_to_json(int argc, VALUE *argv, VALUE self);
1151
1304
 
1152
- /* call-seq: push_key(key)
1305
+ /* Document-method: mimic_JSON
1306
+ * call-seq: mimic_JSON()
1307
+ *
1308
+ * Creates the JSON module with methods and classes to mimic the JSON gem. After
1309
+ * this method is invoked calls that expect the JSON module will use Oj instead
1310
+ * and be faster than the original JSON. Most options that could be passed to
1311
+ * the JSON methods are supported. The calls to set parser or generator will not
1312
+ * raise an Exception but will not have any effect. The method can also be
1313
+ * called after the json gem is loaded. The necessary methods on the json gem
1314
+ * will be replaced with Oj methods.
1315
+ *
1316
+ * Note that this also sets the default options of :mode to :compat and
1317
+ * :encoding to :ascii.
1153
1318
  *
1154
- * Pushes a key onto the JSON document. The key will be used for the next push
1155
- * if currently in a JSON object and ignored otherwise. If a key is provided on
1156
- * the next push then that new key will be ignored.
1157
- * @param [String] key the key pending for the next push
1319
+ * Returns [_Module_] the JSON module.
1158
1320
  */
1159
- static VALUE
1160
- str_writer_push_key(VALUE self, VALUE key) {
1161
- StrWriter sw = (StrWriter)DATA_PTR(self);
1321
+ extern VALUE oj_define_mimic_json(int argc, VALUE *argv, VALUE self);
1322
+
1323
+ /* Document-method: generate
1324
+ * call-seq: generate(obj, opts=nil)
1325
+ *
1326
+ * Encode obj as a JSON String. The obj argument must be a Hash, Array, or
1327
+ * respond to to_h or to_json. Options other than those listed such as
1328
+ * +:allow_nan+ or +:max_nesting+ are ignored.
1329
+ *
1330
+ * - *obj* [_Object__|_Hash_|_Array_] object to convert to a JSON String
1331
+ * - *opts* [_Hash_] options
1332
+ * - - *:indent* [_String_] String to use for indentation.
1333
+ * - *:space* [_String_] String placed after a , or : delimiter
1334
+ * - *:space * _before [_String_] String placed before a : delimiter
1335
+ * - *:object_nl* [_String_] String placed after a JSON object
1336
+ * - *:array_nl* [_String_] String placed after a JSON array
1337
+ * - *:ascii_only* [_Boolean_] if not nil or false then use only ascii characters in the output. Note JSON.generate does support this even if it is not documented.
1338
+ *
1339
+ * Returns [_String_]generated JSON.
1340
+ */
1341
+ extern VALUE oj_mimic_generate(int argc, VALUE *argv, VALUE self);
1162
1342
 
1163
- rb_check_type(key, T_STRING);
1164
- oj_str_writer_push_key(sw, StringValuePtr(key));
1343
+ /*
1344
+ extern void oj_hash_test();
1165
1345
 
1346
+ static VALUE
1347
+ hash_test(VALUE self) {
1348
+ oj_hash_test();
1166
1349
  return Qnil;
1167
1350
  }
1351
+ */
1168
1352
 
1169
- /* call-seq: push_object(key=nil)
1170
- *
1171
- * Pushes an object onto the JSON document. Future pushes will be to this object
1172
- * until a pop() is called.
1173
- * @param [String] key the key if adding to an object in the JSON document
1174
- */
1353
+ #if !HAS_ENCODING_SUPPORT
1175
1354
  static VALUE
1176
- str_writer_push_object(int argc, VALUE *argv, VALUE self) {
1177
- StrWriter sw = (StrWriter)DATA_PTR(self);
1178
-
1179
- switch (argc) {
1180
- case 0:
1181
- oj_str_writer_push_object(sw, 0);
1182
- break;
1183
- case 1:
1184
- if (Qnil == argv[0]) {
1185
- oj_str_writer_push_object(sw, 0);
1186
- } else {
1187
- rb_check_type(argv[0], T_STRING);
1188
- oj_str_writer_push_object(sw, StringValuePtr(argv[0]));
1189
- }
1190
- break;
1191
- default:
1192
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
1193
- break;
1194
- }
1195
- if (rb_block_given_p()) {
1196
- rb_yield(Qnil);
1197
- oj_str_writer_pop(sw);
1198
- }
1199
- return Qnil;
1200
- }
1201
-
1202
- /* call-seq: push_array(key=nil)
1203
- *
1204
- * Pushes an array onto the JSON document. Future pushes will be to this object
1205
- * until a pop() is called.
1206
- * @param [String] key the key if adding to an object in the JSON document
1207
- */
1208
- static VALUE
1209
- str_writer_push_array(int argc, VALUE *argv, VALUE self) {
1210
- StrWriter sw = (StrWriter)DATA_PTR(self);
1211
-
1212
- switch (argc) {
1213
- case 0:
1214
- oj_str_writer_push_array(sw, 0);
1215
- break;
1216
- case 1:
1217
- if (Qnil == argv[0]) {
1218
- oj_str_writer_push_array(sw, 0);
1219
- } else {
1220
- rb_check_type(argv[0], T_STRING);
1221
- oj_str_writer_push_array(sw, StringValuePtr(argv[0]));
1222
- }
1223
- break;
1224
- default:
1225
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
1226
- break;
1227
- }
1228
- if (rb_block_given_p()) {
1229
- rb_yield(Qnil);
1230
- oj_str_writer_pop(sw);
1231
- }
1232
- return Qnil;
1233
- }
1234
-
1235
- /* call-seq: push_value(value, key=nil)
1236
- *
1237
- * Pushes a value onto the JSON document.
1238
- * @param [Object] value value to add to the JSON document
1239
- * @param [String] key the key if adding to an object in the JSON document
1240
- */
1241
- static VALUE
1242
- str_writer_push_value(int argc, VALUE *argv, VALUE self) {
1243
- switch (argc) {
1244
- case 1:
1245
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
1246
- break;
1247
- case 2:
1248
- if (Qnil == argv[1]) {
1249
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
1250
- } else {
1251
- rb_check_type(argv[1], T_STRING);
1252
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
1253
- }
1254
- break;
1255
- default:
1256
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'.");
1257
- break;
1258
- }
1259
- return Qnil;
1260
- }
1261
-
1262
- /* call-seq: push_json(value, key=nil)
1263
- *
1264
- * Pushes a string onto the JSON document. The String must be a valid JSON
1265
- * encoded string. No additional checking is done to verify the validity of the
1266
- * string.
1267
- * @param [String] value JSON document to add to the JSON document
1268
- * @param [String] key the key if adding to an object in the JSON document
1269
- */
1270
- static VALUE
1271
- str_writer_push_json(int argc, VALUE *argv, VALUE self) {
1272
- rb_check_type(argv[0], T_STRING);
1273
- switch (argc) {
1274
- case 1:
1275
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
1276
- break;
1277
- case 2:
1278
- if (Qnil == argv[1]) {
1279
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
1280
- } else {
1281
- rb_check_type(argv[1], T_STRING);
1282
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), StringValuePtr(argv[1]));
1283
- }
1284
- break;
1285
- default:
1286
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'.");
1287
- break;
1288
- }
1289
- return Qnil;
1290
- }
1291
-
1292
- /* call-seq: pop()
1293
- *
1294
- * Pops up a level in the JSON document closing the array or object that is
1295
- * currently open.
1296
- */
1297
- static VALUE
1298
- str_writer_pop(VALUE self) {
1299
- oj_str_writer_pop((StrWriter)DATA_PTR(self));
1300
- return Qnil;
1301
- }
1302
-
1303
- /* call-seq: pop_all()
1304
- *
1305
- * Pops all level in the JSON document closing all the array or object that is
1306
- * currently open.
1307
- */
1308
- static VALUE
1309
- str_writer_pop_all(VALUE self) {
1310
- oj_str_writer_pop_all((StrWriter)DATA_PTR(self));
1311
-
1312
- return Qnil;
1313
- }
1314
-
1315
- /* call-seq: reset()
1316
- *
1317
- * Reset the writer back to the empty state.
1318
- */
1319
- static VALUE
1320
- str_writer_reset(VALUE self) {
1321
- StrWriter sw = (StrWriter)DATA_PTR(self);
1322
-
1323
- sw->depth = 0;
1324
- *sw->types = '\0';
1325
- sw->keyWritten = 0;
1326
- sw->out.cur = sw->out.buf;
1327
- *sw->out.cur = '\0';
1328
-
1329
- return Qnil;
1330
- }
1331
-
1332
- /* call-seq: to_s()
1333
- *
1334
- * Returns the JSON document string in what ever state the construction is at.
1335
- */
1336
- static VALUE
1337
- str_writer_to_s(VALUE self) {
1338
- StrWriter sw = (StrWriter)DATA_PTR(self);
1339
- VALUE rstr = rb_str_new(sw->out.buf, sw->out.cur - sw->out.buf);
1340
-
1341
- return oj_encode(rstr);
1342
- }
1343
-
1344
- // StreamWriter
1345
-
1346
- /* Document-class: Oj::StreamWriter
1347
- *
1348
- * Supports building a JSON document one element at a time. Build the IO stream
1349
- * document by pushing values into the document. Pushing an array or an object
1350
- * will create that element in the JSON document and subsequent pushes will add
1351
- * the elements to that array or object until a pop() is called.
1352
- */
1353
-
1354
- static void
1355
- stream_writer_free(void *ptr) {
1356
- StreamWriter sw;
1357
-
1358
- if (0 == ptr) {
1359
- return;
1360
- }
1361
- sw = (StreamWriter)ptr;
1362
- xfree(sw->sw.out.buf);
1363
- xfree(sw->sw.types);
1364
- xfree(ptr);
1365
- }
1366
-
1367
- static void
1368
- stream_writer_write(StreamWriter sw) {
1369
- ssize_t size = sw->sw.out.cur - sw->sw.out.buf;
1370
-
1371
- switch (sw->type) {
1372
- case STRING_IO:
1373
- rb_funcall(sw->stream, oj_write_id, 1, rb_str_new(sw->sw.out.buf, size));
1374
- break;
1375
- case STREAM_IO:
1376
- rb_funcall(sw->stream, oj_write_id, 1, rb_str_new(sw->sw.out.buf, size));
1377
- break;
1378
- case FILE_IO:
1379
- if (size != write(sw->fd, sw->sw.out.buf, size)) {
1380
- rb_raise(rb_eIOError, "Write failed. [%d:%s]\n", errno, strerror(errno));
1381
- }
1382
- break;
1383
- default:
1384
- rb_raise(rb_eArgError, "expected an IO Object.");
1385
- }
1386
- }
1387
-
1388
- static void
1389
- stream_writer_reset_buf(StreamWriter sw) {
1390
- sw->sw.out.cur = sw->sw.out.buf;
1391
- *sw->sw.out.cur = '\0';
1392
- }
1393
-
1394
- /* call-seq: new(io, options)
1395
- *
1396
- * Creates a new StreamWriter.
1397
- * @param [IO] io stream to write to
1398
- * @param [Hash] options formating options
1399
- */
1400
- static VALUE
1401
- stream_writer_new(int argc, VALUE *argv, VALUE self) {
1402
- StreamWriterType type = STREAM_IO;
1403
- int fd = 0;
1404
- VALUE stream = argv[0];
1405
- VALUE clas = rb_obj_class(stream);
1406
- StreamWriter sw;
1407
- #if !IS_WINDOWS
1408
- VALUE s;
1409
- #endif
1410
-
1411
- if (oj_stringio_class == clas) {
1412
- type = STRING_IO;
1413
- #if !IS_WINDOWS
1414
- } else if (rb_respond_to(stream, oj_fileno_id) &&
1415
- Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) &&
1416
- 0 != (fd = FIX2INT(s))) {
1417
- type = FILE_IO;
1418
- #endif
1419
- } else if (rb_respond_to(stream, oj_write_id)) {
1420
- type = STREAM_IO;
1421
- } else {
1422
- rb_raise(rb_eArgError, "expected an IO Object.");
1423
- }
1424
- sw = ALLOC(struct _StreamWriter);
1425
- str_writer_init(&sw->sw);
1426
- if (2 == argc) {
1427
- oj_parse_options(argv[1], &sw->sw.opts);
1428
- }
1429
- sw->sw.out.indent = sw->sw.opts.indent;
1430
- sw->stream = stream;
1431
- sw->type = type;
1432
- sw->fd = fd;
1433
-
1434
- return Data_Wrap_Struct(oj_stream_writer_class, 0, stream_writer_free, sw);
1435
- }
1436
-
1437
- /* call-seq: push_key(key)
1438
- *
1439
- * Pushes a key onto the JSON document. The key will be used for the next push
1440
- * if currently in a JSON object and ignored otherwise. If a key is provided on
1441
- * the next push then that new key will be ignored.
1442
- * @param [String] key the key pending for the next push
1443
- */
1444
- static VALUE
1445
- stream_writer_push_key(VALUE self, VALUE key) {
1446
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
1447
-
1448
- rb_check_type(key, T_STRING);
1449
- stream_writer_reset_buf(sw);
1450
- oj_str_writer_push_key(&sw->sw, StringValuePtr(key));
1451
- stream_writer_write(sw);
1452
- return Qnil;
1453
- }
1454
-
1455
- /* call-seq: push_object(key=nil)
1456
- *
1457
- * Pushes an object onto the JSON document. Future pushes will be to this object
1458
- * until a pop() is called.
1459
- * @param [String] key the key if adding to an object in the JSON document
1460
- */
1461
- static VALUE
1462
- stream_writer_push_object(int argc, VALUE *argv, VALUE self) {
1463
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
1464
-
1465
- stream_writer_reset_buf(sw);
1466
- switch (argc) {
1467
- case 0:
1468
- oj_str_writer_push_object(&sw->sw, 0);
1469
- break;
1470
- case 1:
1471
- if (Qnil == argv[0]) {
1472
- oj_str_writer_push_object(&sw->sw, 0);
1473
- } else {
1474
- rb_check_type(argv[0], T_STRING);
1475
- oj_str_writer_push_object(&sw->sw, StringValuePtr(argv[0]));
1476
- }
1477
- break;
1478
- default:
1479
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
1480
- break;
1481
- }
1482
- stream_writer_write(sw);
1483
- return Qnil;
1484
- }
1485
-
1486
- /* call-seq: push_array(key=nil)
1487
- *
1488
- * Pushes an array onto the JSON document. Future pushes will be to this object
1489
- * until a pop() is called.
1490
- * @param [String] key the key if adding to an object in the JSON document
1491
- */
1492
- static VALUE
1493
- stream_writer_push_array(int argc, VALUE *argv, VALUE self) {
1494
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
1495
-
1496
- stream_writer_reset_buf(sw);
1497
- switch (argc) {
1498
- case 0:
1499
- oj_str_writer_push_array(&sw->sw, 0);
1500
- break;
1501
- case 1:
1502
- if (Qnil == argv[0]) {
1503
- oj_str_writer_push_array(&sw->sw, 0);
1504
- } else {
1505
- rb_check_type(argv[0], T_STRING);
1506
- oj_str_writer_push_array(&sw->sw, StringValuePtr(argv[0]));
1507
- }
1508
- break;
1509
- default:
1510
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
1511
- break;
1512
- }
1513
- stream_writer_write(sw);
1514
- return Qnil;
1515
- }
1516
-
1517
- /* call-seq: push_value(value, key=nil)
1518
- *
1519
- * Pushes a value onto the JSON document.
1520
- * @param [Object] value value to add to the JSON document
1521
- * @param [String] key the key if adding to an object in the JSON document
1522
- */
1523
- static VALUE
1524
- stream_writer_push_value(int argc, VALUE *argv, VALUE self) {
1525
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
1526
-
1527
- stream_writer_reset_buf(sw);
1528
- switch (argc) {
1529
- case 1:
1530
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
1531
- break;
1532
- case 2:
1533
- if (Qnil == argv[1]) {
1534
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
1535
- } else {
1536
- rb_check_type(argv[1], T_STRING);
1537
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
1538
- }
1539
- break;
1540
- default:
1541
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'.");
1542
- break;
1543
- }
1544
- stream_writer_write(sw);
1545
- return Qnil;
1546
- }
1547
-
1548
- /* call-seq: push_json(value, key=nil)
1549
- *
1550
- * Pushes a string onto the JSON document. The String must be a valid JSON
1551
- * encoded string. No additional checking is done to verify the validity of the
1552
- * string.
1553
- * @param [Object] value value to add to the JSON document
1554
- * @param [String] key the key if adding to an object in the JSON document
1555
- */
1556
- static VALUE
1557
- stream_writer_push_json(int argc, VALUE *argv, VALUE self) {
1558
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
1559
-
1560
- rb_check_type(argv[0], T_STRING);
1561
- stream_writer_reset_buf(sw);
1562
- switch (argc) {
1563
- case 1:
1564
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
1565
- break;
1566
- case 2:
1567
- if (Qnil == argv[0]) {
1568
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
1569
- } else {
1570
- rb_check_type(argv[1], T_STRING);
1571
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), StringValuePtr(argv[1]));
1572
- }
1573
- break;
1574
- default:
1575
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'.");
1576
- break;
1577
- }
1578
- stream_writer_write(sw);
1579
- return Qnil;
1580
- }
1581
-
1582
- /* call-seq: pop()
1583
- *
1584
- * Pops up a level in the JSON document closing the array or object that is
1585
- * currently open.
1586
- */
1587
- static VALUE
1588
- stream_writer_pop(VALUE self) {
1589
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
1590
-
1591
- stream_writer_reset_buf(sw);
1592
- oj_str_writer_pop(&sw->sw);
1593
- stream_writer_write(sw);
1594
- return Qnil;
1595
- }
1596
-
1597
- /* call-seq: pop_all()
1598
- *
1599
- * Pops all level in the JSON document closing all the array or object that is
1600
- * currently open.
1601
- */
1602
- static VALUE
1603
- stream_writer_pop_all(VALUE self) {
1604
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
1605
-
1606
- stream_writer_reset_buf(sw);
1607
- oj_str_writer_pop_all(&sw->sw);
1608
- stream_writer_write(sw);
1609
-
1610
- return Qnil;
1611
- }
1612
-
1613
- // Mimic JSON section
1614
-
1615
- static VALUE
1616
- mimic_dump(int argc, VALUE *argv, VALUE self) {
1617
- char buf[4096];
1618
- struct _Out out;
1619
- struct _Options copts = oj_default_options;
1620
- VALUE rstr;
1621
-
1622
- out.buf = buf;
1623
- out.end = buf + sizeof(buf) - 10;
1624
- out.allocated = 0;
1625
- out.omit_nil = copts.dump_opts.omit_nil;
1626
- oj_dump_obj_to_json(*argv, &copts, &out);
1627
- if (0 == out.buf) {
1628
- rb_raise(rb_eNoMemError, "Not enough memory.");
1629
- }
1630
- rstr = rb_str_new2(out.buf);
1631
- rstr = oj_encode(rstr);
1632
- if (2 <= argc && Qnil != argv[1]) {
1633
- VALUE io = argv[1];
1634
- VALUE args[1];
1635
-
1636
- *args = rstr;
1637
- rb_funcall2(io, oj_write_id, 1, args);
1638
- rstr = io;
1639
- }
1640
- if (out.allocated) {
1641
- xfree(out.buf);
1642
- }
1643
- return rstr;
1644
- }
1645
-
1646
- // This is the signature for the hash_foreach callback also.
1647
- static int
1648
- mimic_walk(VALUE key, VALUE obj, VALUE proc) {
1649
- switch (rb_type(obj)) {
1650
- case T_HASH:
1651
- rb_hash_foreach(obj, mimic_walk, proc);
1652
- break;
1653
- case T_ARRAY:
1654
- {
1655
- size_t cnt = RARRAY_LEN(obj);
1656
- size_t i;
1657
-
1658
- for (i = 0; i < cnt; i++) {
1659
- mimic_walk(Qnil, rb_ary_entry(obj, i), proc);
1660
- }
1661
- break;
1662
- }
1663
- default:
1664
- break;
1665
- }
1666
- if (Qnil == proc) {
1667
- if (rb_block_given_p()) {
1668
- rb_yield(obj);
1669
- }
1670
- } else {
1671
- #if HAS_PROC_WITH_BLOCK
1672
- VALUE args[1];
1673
-
1674
- *args = obj;
1675
- rb_proc_call_with_block(proc, 1, args, Qnil);
1676
- #else
1677
- rb_raise(rb_eNotImpError, "Calling a Proc with a block not supported in this version. Use func() {|x| } syntax instead.");
1678
- #endif
1679
- }
1680
- return ST_CONTINUE;
1681
- }
1682
-
1683
- static VALUE
1684
- mimic_load(int argc, VALUE *argv, VALUE self) {
1685
- struct _ParseInfo pi;
1686
- VALUE obj;
1687
- VALUE p = Qnil;
1688
-
1689
- pi.err_class = json_parser_error_class;
1690
- pi.options = oj_default_options;
1691
- oj_set_compat_callbacks(&pi);
1692
-
1693
- obj = oj_pi_parse(argc, argv, &pi, 0, 0, 0);
1694
- if (2 <= argc) {
1695
- p = argv[1];
1696
- }
1697
- mimic_walk(Qnil, obj, p);
1698
-
1699
- return obj;
1700
- }
1701
-
1702
- static VALUE
1703
- mimic_dump_load(int argc, VALUE *argv, VALUE self) {
1704
- if (1 > argc) {
1705
- rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)");
1706
- } else if (T_STRING == rb_type(*argv)) {
1707
- return mimic_load(argc, argv, self);
1708
- } else {
1709
- return mimic_dump(argc, argv, self);
1710
- }
1711
- return Qnil;
1712
- }
1713
-
1714
- static VALUE
1715
- mimic_generate_core(int argc, VALUE *argv, Options copts) {
1716
- char buf[4096];
1717
- struct _Out out;
1718
- VALUE rstr;
1719
-
1720
- out.buf = buf;
1721
- out.end = buf + sizeof(buf) - 10;
1722
- out.allocated = 0;
1723
- out.omit_nil = copts->dump_opts.omit_nil;
1724
- if (2 == argc && Qnil != argv[1]) {
1725
- VALUE ropts = argv[1];
1726
- VALUE v;
1727
- size_t len;
1728
-
1729
- if (T_HASH != rb_type(ropts)) {
1730
- rb_raise(rb_eArgError, "options must be a hash.");
1731
- }
1732
- if (Qnil != (v = rb_hash_lookup(ropts, indent_sym))) { // TBD fixnum also ok
1733
- rb_check_type(v, T_STRING);
1734
- if (sizeof(copts->dump_opts.indent_str) <= (len = RSTRING_LEN(v))) {
1735
- rb_raise(rb_eArgError, "indent string is limited to %lu characters.", sizeof(copts->dump_opts.indent_str));
1736
- }
1737
- strcpy(copts->dump_opts.indent_str, StringValuePtr(v));
1738
- copts->dump_opts.indent_size = (uint8_t)len;
1739
- copts->dump_opts.use = true;
1740
- }
1741
- if (Qnil != (v = rb_hash_lookup(ropts, space_sym))) {
1742
- rb_check_type(v, T_STRING);
1743
- if (sizeof(copts->dump_opts.after_sep) <= (len = RSTRING_LEN(v))) {
1744
- rb_raise(rb_eArgError, "space string is limited to %lu characters.", sizeof(copts->dump_opts.after_sep));
1745
- }
1746
- strcpy(copts->dump_opts.after_sep, StringValuePtr(v));
1747
- copts->dump_opts.after_size = (uint8_t)len;
1748
- copts->dump_opts.use = true;
1749
- }
1750
- if (Qnil != (v = rb_hash_lookup(ropts, space_before_sym))) {
1751
- rb_check_type(v, T_STRING);
1752
- if (sizeof(copts->dump_opts.before_sep) <= (len = RSTRING_LEN(v))) {
1753
- rb_raise(rb_eArgError, "space_before string is limited to %lu characters.", sizeof(copts->dump_opts.before_sep));
1754
- }
1755
- strcpy(copts->dump_opts.before_sep, StringValuePtr(v));
1756
- copts->dump_opts.before_size = (uint8_t)len;
1757
- copts->dump_opts.use = true;
1758
- }
1759
- if (Qnil != (v = rb_hash_lookup(ropts, object_nl_sym))) {
1760
- rb_check_type(v, T_STRING);
1761
- if (sizeof(copts->dump_opts.hash_nl) <= (len = RSTRING_LEN(v))) {
1762
- rb_raise(rb_eArgError, "object_nl string is limited to %lu characters.", sizeof(copts->dump_opts.hash_nl));
1763
- }
1764
- strcpy(copts->dump_opts.hash_nl, StringValuePtr(v));
1765
- copts->dump_opts.hash_size = (uint8_t)len;
1766
- copts->dump_opts.use = true;
1767
- }
1768
- if (Qnil != (v = rb_hash_lookup(ropts, array_nl_sym))) {
1769
- rb_check_type(v, T_STRING);
1770
- if (sizeof(copts->dump_opts.array_nl) <= (len = RSTRING_LEN(v))) {
1771
- rb_raise(rb_eArgError, "array_nl string is limited to %lu characters.", sizeof(copts->dump_opts.array_nl));
1772
- }
1773
- strcpy(copts->dump_opts.array_nl, StringValuePtr(v));
1774
- copts->dump_opts.array_size = (uint8_t)len;
1775
- copts->dump_opts.use = true;
1776
- }
1777
- if (Qnil != (v = rb_hash_lookup(ropts, ascii_only_sym))) {
1778
- // generate seems to assume anything except nil and false are true.
1779
- if (Qfalse == v || Qnil == v) {
1780
- copts->escape_mode = JSONEsc;
1781
- } else {
1782
- copts->escape_mode = ASCIIEsc;
1783
- }
1784
- }
1785
- // :allow_nan is not supported as Oj always allows_nan
1786
- // :max_nesting is always set to 100
1787
- }
1788
- oj_dump_obj_to_json(*argv, copts, &out);
1789
- if (0 == out.buf) {
1790
- rb_raise(rb_eNoMemError, "Not enough memory.");
1791
- }
1792
- rstr = rb_str_new2(out.buf);
1793
- rstr = oj_encode(rstr);
1794
- if (out.allocated) {
1795
- xfree(out.buf);
1796
- }
1797
- return rstr;
1798
- }
1799
-
1800
- static VALUE
1801
- mimic_generate(int argc, VALUE *argv, VALUE self) {
1802
- struct _Options copts = oj_default_options;
1803
-
1804
- return mimic_generate_core(argc, argv, &copts);
1805
- }
1806
-
1807
- static VALUE
1808
- mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
1809
- struct _Options copts = oj_default_options;
1810
-
1811
- strcpy(copts.dump_opts.indent_str, " ");
1812
- copts.dump_opts.indent_size = (uint8_t)strlen(copts.dump_opts.indent_str);
1813
- strcpy(copts.dump_opts.before_sep, "");
1814
- copts.dump_opts.before_size = (uint8_t)strlen(copts.dump_opts.before_sep);
1815
- strcpy(copts.dump_opts.after_sep, " ");
1816
- copts.dump_opts.after_size = (uint8_t)strlen(copts.dump_opts.after_sep);
1817
- strcpy(copts.dump_opts.hash_nl, "\n");
1818
- copts.dump_opts.hash_size = (uint8_t)strlen(copts.dump_opts.hash_nl);
1819
- strcpy(copts.dump_opts.array_nl, "\n");
1820
- copts.dump_opts.array_size = (uint8_t)strlen(copts.dump_opts.array_nl);
1821
- copts.dump_opts.use = true;
1822
-
1823
- return mimic_generate_core(argc, argv, &copts);
1824
- }
1825
-
1826
- static VALUE
1827
- mimic_parse(int argc, VALUE *argv, VALUE self) {
1828
- struct _ParseInfo pi;
1829
- VALUE args[1];
1830
-
1831
- if (argc < 1) {
1832
- rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
1833
- }
1834
- oj_set_compat_callbacks(&pi);
1835
- pi.err_class = json_parser_error_class;
1836
- pi.options = oj_default_options;
1837
- pi.options.auto_define = No;
1838
- pi.options.quirks_mode = No;
1839
- pi.options.allow_invalid = No;
1840
- pi.options.empty_string = No;
1841
-
1842
- if (2 <= argc) {
1843
- VALUE ropts = argv[1];
1844
- VALUE v;
1845
-
1846
- if (T_HASH != rb_type(ropts)) {
1847
- rb_raise(rb_eArgError, "options must be a hash.");
1848
- }
1849
- if (Qnil != (v = rb_hash_lookup(ropts, symbolize_names_sym))) {
1850
- pi.options.sym_key = (Qtrue == v) ? Yes : No;
1851
- }
1852
-
1853
- if (Qnil != (v = rb_hash_lookup(ropts, quirks_mode_sym))) {
1854
- pi.options.quirks_mode = (Qtrue == v) ? Yes : No;
1855
- }
1856
-
1857
- if (Qnil != (v = rb_hash_lookup(ropts, create_additions_sym))) {
1858
- if (Qfalse == v) {
1859
- oj_set_strict_callbacks(&pi);
1860
- }
1861
- }
1862
- // :allow_nan is not supported as Oj always allows nan
1863
- // :max_nesting is ignored as Oj has not nesting limit
1864
- // :object_class is always Hash
1865
- // :array_class is always Array
1866
- }
1867
- *args = *argv;
1868
-
1869
- return oj_pi_parse(1, args, &pi, 0, 0, 0);
1870
- }
1871
-
1872
- static VALUE
1873
- mimic_recurse_proc(VALUE self, VALUE obj) {
1874
- rb_need_block();
1875
- mimic_walk(Qnil, obj, Qnil);
1876
-
1877
- return Qnil;
1878
- }
1879
-
1880
- static VALUE
1881
- no_op1(VALUE self, VALUE obj) {
1882
- return Qnil;
1883
- }
1884
-
1885
- static VALUE
1886
- mimic_set_create_id(VALUE self, VALUE id) {
1887
- Check_Type(id, T_STRING);
1888
-
1889
- if (0 != oj_default_options.create_id) {
1890
- if (json_class != oj_default_options.create_id) {
1891
- xfree((char*)oj_default_options.create_id);
1892
- }
1893
- oj_default_options.create_id = 0;
1894
- oj_default_options.create_id_len = 0;
1895
- }
1896
- if (Qnil != id) {
1897
- size_t len = RSTRING_LEN(id) + 1;
1898
-
1899
- oj_default_options.create_id = ALLOC_N(char, len);
1900
- strcpy((char*)oj_default_options.create_id, StringValuePtr(id));
1901
- oj_default_options.create_id_len = len - 1;
1902
- }
1903
- return id;
1904
- }
1905
-
1906
- static VALUE
1907
- mimic_create_id(VALUE self) {
1908
- if (0 != oj_default_options.create_id) {
1909
- return oj_encode(rb_str_new_cstr(oj_default_options.create_id));
1910
- }
1911
- return rb_str_new_cstr(json_class);
1912
- }
1913
-
1914
- static struct _Options mimic_object_to_json_options = {
1915
- 0, // indent
1916
- No, // circular
1917
- No, // auto_define
1918
- No, // sym_key
1919
- JSONEsc, // escape_mode
1920
- CompatMode, // mode
1921
- No, // class_cache
1922
- RubyTime, // time_format
1923
- No, // bigdec_as_num
1924
- FloatDec, // bigdec_load
1925
- No, // to_json
1926
- Yes, // as_json
1927
- Yes, // nilnil
1928
- Yes, // empty_string
1929
- Yes, // allow_gc
1930
- Yes, // quirks_mode
1931
- No, // allow_invalid
1932
- json_class, // create_id
1933
- 10, // create_id_len
1934
- 9, // sec_prec
1935
- 15, // float_prec
1936
- "%0.15g", // float_fmt
1937
- Qnil, // hash_class
1938
- { // dump_opts
1939
- false, //use
1940
- "", // indent
1941
- "", // before_sep
1942
- "", // after_sep
1943
- "", // hash_nl
1944
- "", // array_nl
1945
- 0, // indent_size
1946
- 0, // before_size
1947
- 0, // after_size
1948
- 0, // hash_size
1949
- 0, // array_size
1950
- AutoNan,// nan_dump
1951
- false, // omit_nil
1952
- }
1953
- };
1954
-
1955
- static VALUE
1956
- mimic_object_to_json(int argc, VALUE *argv, VALUE self) {
1957
- char buf[4096];
1958
- struct _Out out;
1959
- VALUE rstr;
1960
- struct _Options copts = oj_default_options;
1961
-
1962
- out.buf = buf;
1963
- out.end = buf + sizeof(buf) - 10;
1964
- out.allocated = 0;
1965
- out.omit_nil = copts.dump_opts.omit_nil;
1966
- // Have to turn off to_json to avoid the Active Support recursion problem.
1967
- copts.to_json = No;
1968
- // To be strict the mimic_object_to_json_options should be used but people
1969
- // seem to prefer the option of changing that.
1970
- //oj_dump_obj_to_json(self, &mimic_object_to_json_options, &out);
1971
- oj_dump_obj_to_json_using_params(self, &copts, &out, argc, argv);
1972
- if (0 == out.buf) {
1973
- rb_raise(rb_eNoMemError, "Not enough memory.");
1974
- }
1975
- rstr = rb_str_new2(out.buf);
1976
- rstr = oj_encode(rstr);
1977
- if (out.allocated) {
1978
- xfree(out.buf);
1979
- }
1980
- return rstr;
1981
- }
1982
-
1983
-
1984
- /* Document-method: mimic_JSON
1985
- * call-seq: mimic_JSON() => Module
1986
- *
1987
- * Creates the JSON module with methods and classes to mimic the JSON gem. After
1988
- * this method is invoked calls that expect the JSON module will use Oj instead
1989
- * and be faster than the original JSON. Most options that could be passed to
1990
- * the JSON methods are supported. The calls to set parser or generator will not
1991
- * raise an Exception but will not have any effect. The method can also be
1992
- * called after the json gem is loaded. The necessary methods on the json gem
1993
- * will be replaced with Oj methods.
1994
- *
1995
- * Note that this also sets the default options of :mode to :compat and
1996
- * :encoding to :ascii.
1997
- */
1998
- static VALUE
1999
- define_mimic_json(int argc, VALUE *argv, VALUE self) {
2000
- VALUE ext;
2001
- VALUE dummy;
2002
- VALUE verbose;
2003
- VALUE json_error;
2004
-
2005
- // Either set the paths to indicate JSON has been loaded or replaces the
2006
- // methods if it has been loaded.
2007
- if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) {
2008
- mimic = rb_const_get_at(rb_cObject, rb_intern("JSON"));
2009
- } else {
2010
- mimic = rb_define_module("JSON");
2011
- }
2012
- verbose = rb_gv_get("$VERBOSE");
2013
- rb_gv_set("$VERBOSE", Qfalse);
2014
- rb_define_module_function(rb_cObject, "JSON", mimic_dump_load, -1);
2015
- if (rb_const_defined_at(mimic, rb_intern("Ext"))) {
2016
- ext = rb_const_get_at(mimic, rb_intern("Ext"));
2017
- } else {
2018
- ext = rb_define_module_under(mimic, "Ext");
2019
- }
2020
- if (!rb_const_defined_at(ext, rb_intern("Parser"))) {
2021
- dummy = rb_define_class_under(ext, "Parser", rb_cObject);
2022
- }
2023
- if (!rb_const_defined_at(ext, rb_intern("Generator"))) {
2024
- dummy = rb_define_class_under(ext, "Generator", rb_cObject);
2025
- }
2026
- // convince Ruby that the json gem has already been loaded
2027
- dummy = rb_gv_get("$LOADED_FEATURES");
2028
- if (rb_type(dummy) == T_ARRAY) {
2029
- rb_ary_push(dummy, rb_str_new2("json"));
2030
- if (0 < argc) {
2031
- VALUE mimic_args[1];
2032
-
2033
- *mimic_args = *argv;
2034
- rb_funcall2(Oj, rb_intern("mimic_loaded"), 1, mimic_args);
2035
- } else {
2036
- rb_funcall2(Oj, rb_intern("mimic_loaded"), 0, 0);
2037
- }
2038
- }
2039
- rb_define_module_function(mimic, "parser=", no_op1, 1);
2040
- rb_define_module_function(mimic, "generator=", no_op1, 1);
2041
- rb_define_module_function(mimic, "create_id=", mimic_set_create_id, 1);
2042
- rb_define_module_function(mimic, "create_id", mimic_create_id, 0);
2043
-
2044
- rb_define_module_function(mimic, "dump", mimic_dump, -1);
2045
- rb_define_module_function(mimic, "load", mimic_load, -1);
2046
- rb_define_module_function(mimic, "restore", mimic_load, -1);
2047
- rb_define_module_function(mimic, "recurse_proc", mimic_recurse_proc, 1);
2048
- rb_define_module_function(mimic, "[]", mimic_dump_load, -1);
2049
-
2050
- rb_define_module_function(mimic, "generate", mimic_generate, -1);
2051
- rb_define_module_function(mimic, "fast_generate", mimic_generate, -1);
2052
- rb_define_module_function(mimic, "pretty_generate", mimic_pretty_generate, -1);
2053
- /* for older versions of JSON, the deprecated unparse methods */
2054
- rb_define_module_function(mimic, "unparse", mimic_generate, -1);
2055
- rb_define_module_function(mimic, "fast_unparse", mimic_generate, -1);
2056
- rb_define_module_function(mimic, "pretty_unparse", mimic_pretty_generate, -1);
2057
-
2058
- rb_define_module_function(mimic, "parse", mimic_parse, -1);
2059
- rb_define_module_function(mimic, "parse!", mimic_parse, -1);
2060
-
2061
- rb_define_method(rb_cObject, "to_json", mimic_object_to_json, -1);
2062
-
2063
- rb_gv_set("$VERBOSE", verbose);
2064
-
2065
- create_additions_sym = ID2SYM(rb_intern("create_additions")); rb_gc_register_address(&create_additions_sym);
2066
- symbolize_names_sym = ID2SYM(rb_intern("symbolize_names")); rb_gc_register_address(&symbolize_names_sym);
2067
-
2068
- if (rb_const_defined_at(mimic, rb_intern("JSONError"))) {
2069
- json_error = rb_const_get(mimic, rb_intern("JSONError"));
2070
- } else {
2071
- json_error = rb_define_class_under(mimic, "JSONError", rb_eStandardError);
2072
- }
2073
- if (rb_const_defined_at(mimic, rb_intern("ParserError"))) {
2074
- json_parser_error_class = rb_const_get(mimic, rb_intern("ParserError"));
2075
- } else {
2076
- json_parser_error_class = rb_define_class_under(mimic, "ParserError", json_error);
2077
- }
2078
-
2079
- if (!rb_const_defined_at(mimic, rb_intern("State"))) {
2080
- rb_define_class_under(mimic, "State", rb_cObject);
2081
- }
2082
-
2083
- oj_default_options = mimic_object_to_json_options;
2084
- oj_default_options.to_json = Yes;
2085
-
2086
- return mimic;
2087
- }
2088
-
2089
- /*
2090
- extern void oj_hash_test();
2091
-
2092
- static VALUE
2093
- hash_test(VALUE self) {
2094
- oj_hash_test();
2095
- return Qnil;
2096
- }
2097
- */
2098
-
2099
- #if !HAS_ENCODING_SUPPORT
2100
- static VALUE
2101
- iconv_encoder(VALUE x) {
2102
- VALUE iconv;
1355
+ iconv_encoder(VALUE x) {
1356
+ VALUE iconv;
2103
1357
 
2104
1358
  rb_require("iconv");
2105
1359
  iconv = rb_const_get(rb_cObject, rb_intern("Iconv"));
@@ -2120,36 +1374,43 @@ protect_require(VALUE x) {
2120
1374
  return Qnil;
2121
1375
  }
2122
1376
 
2123
- void Init_oj() {
1377
+ /* Document-module: Oj
1378
+ *
1379
+ * Optimized JSON (Oj), as the name implies was written to provide speed
1380
+ * optimized JSON handling.
1381
+ *
1382
+ * Oj uses modes to control how object are encoded and decoded. In addition
1383
+ * global and options to methods allow additional behavior modifications. The
1384
+ * modes are:
1385
+ *
1386
+ * - *:strict* mode will only allow the 7 basic JSON types to be serialized. Any other Object
1387
+ * will raise an Exception.
1388
+ *
1389
+ * - *:null* mode is similar to the :strict mode except any Object that is not
1390
+ * one of the JSON base types is replaced by a JSON null.
1391
+ *
1392
+ * - *:object* mode will dump any Object as a JSON Object with keys that match
1393
+ * the Ruby Object's variable names without the '@' character. This is the
1394
+ * highest performance mode.
1395
+ *
1396
+ * - *:compat* or *:json* mode is the compatible mode for the json gem. It mimics
1397
+ * the json gem including the options, defaults, and restrictions.
1398
+ *
1399
+ * - *:rails* is the compatibility mode for Rails or Active support.
1400
+ *
1401
+ * - *:custom* is the most configurable mode.
1402
+ */
1403
+ void
1404
+ Init_oj() {
2124
1405
  int err = 0;
2125
1406
 
2126
1407
  Oj = rb_define_module("Oj");
2127
1408
 
2128
1409
  oj_cstack_class = rb_define_class_under(Oj, "CStack", rb_cObject);
2129
1410
 
2130
- oj_string_writer_class = rb_define_class_under(Oj, "StringWriter", rb_cObject);
2131
- rb_define_module_function(oj_string_writer_class, "new", str_writer_new, -1);
2132
- rb_define_method(oj_string_writer_class, "push_key", str_writer_push_key, 1);
2133
- rb_define_method(oj_string_writer_class, "push_object", str_writer_push_object, -1);
2134
- rb_define_method(oj_string_writer_class, "push_array", str_writer_push_array, -1);
2135
- rb_define_method(oj_string_writer_class, "push_value", str_writer_push_value, -1);
2136
- rb_define_method(oj_string_writer_class, "push_json", str_writer_push_json, -1);
2137
- rb_define_method(oj_string_writer_class, "pop", str_writer_pop, 0);
2138
- rb_define_method(oj_string_writer_class, "pop_all", str_writer_pop_all, 0);
2139
- rb_define_method(oj_string_writer_class, "reset", str_writer_reset, 0);
2140
- rb_define_method(oj_string_writer_class, "to_s", str_writer_to_s, 0);
2141
-
2142
- oj_stream_writer_class = rb_define_class_under(Oj, "StreamWriter", rb_cObject);
2143
- rb_define_module_function(oj_stream_writer_class, "new", stream_writer_new, -1);
2144
- rb_define_method(oj_stream_writer_class, "push_key", stream_writer_push_key, 1);
2145
- rb_define_method(oj_stream_writer_class, "push_object", stream_writer_push_object, -1);
2146
- rb_define_method(oj_stream_writer_class, "push_array", stream_writer_push_array, -1);
2147
- rb_define_method(oj_stream_writer_class, "push_value", stream_writer_push_value, -1);
2148
- rb_define_method(oj_stream_writer_class, "push_json", stream_writer_push_json, -1);
2149
- rb_define_method(oj_stream_writer_class, "pop", stream_writer_pop, 0);
2150
- rb_define_method(oj_stream_writer_class, "pop_all", stream_writer_pop_all, 0);
1411
+ oj_string_writer_init();
1412
+ oj_stream_writer_init();
2151
1413
 
2152
- rb_require("time");
2153
1414
  rb_require("date");
2154
1415
  // On Rubinius the require fails but can be done from a ruby file.
2155
1416
  rb_protect(protect_require, Qnil, &err);
@@ -2170,7 +1431,7 @@ void Init_oj() {
2170
1431
  rb_define_module_function(Oj, "default_options", get_def_opts, 0);
2171
1432
  rb_define_module_function(Oj, "default_options=", set_def_opts, 1);
2172
1433
 
2173
- rb_define_module_function(Oj, "mimic_JSON", define_mimic_json, -1);
1434
+ rb_define_module_function(Oj, "mimic_JSON", oj_define_mimic_json, -1);
2174
1435
  rb_define_module_function(Oj, "load", load, -1);
2175
1436
  rb_define_module_function(Oj, "load_file", load_file, -1);
2176
1437
  rb_define_module_function(Oj, "safe_load", safe_load, 1);
@@ -2179,8 +1440,17 @@ void Init_oj() {
2179
1440
  rb_define_module_function(Oj, "object_load", oj_object_parse, -1);
2180
1441
 
2181
1442
  rb_define_module_function(Oj, "dump", dump, -1);
1443
+
2182
1444
  rb_define_module_function(Oj, "to_file", to_file, -1);
2183
1445
  rb_define_module_function(Oj, "to_stream", to_stream, -1);
1446
+ // JSON gem compatibility
1447
+ rb_define_module_function(Oj, "to_json", to_json, -1);
1448
+ rb_define_module_function(Oj, "generate", oj_mimic_generate, -1);
1449
+ rb_define_module_function(Oj, "fast_generate", oj_mimic_generate, -1);
1450
+
1451
+ rb_define_module_function(Oj, "add_to_json", oj_add_to_json, -1);
1452
+ rb_define_module_function(Oj, "remove_to_json", oj_remove_to_json, -1);
1453
+
2184
1454
  rb_define_module_function(Oj, "register_odd", register_odd, -1);
2185
1455
  rb_define_module_function(Oj, "register_odd_raw", register_odd_raw, -1);
2186
1456
 
@@ -2193,6 +1463,9 @@ void Init_oj() {
2193
1463
  oj_array_start_id = rb_intern("array_start");
2194
1464
  oj_as_json_id = rb_intern("as_json");
2195
1465
  oj_error_id = rb_intern("error");
1466
+ oj_begin_id = rb_intern("begin");
1467
+ oj_end_id = rb_intern("end");
1468
+ oj_exclude_end_id = rb_intern("exclude_end?");
2196
1469
  oj_file_id = rb_intern("file?");
2197
1470
  oj_fileno_id = rb_intern("fileno");
2198
1471
  oj_ftype_id = rb_intern("ftype");
@@ -2213,6 +1486,7 @@ void Init_oj() {
2213
1486
  oj_stat_id = rb_intern("stat");
2214
1487
  oj_string_id = rb_intern("string");
2215
1488
  oj_to_hash_id = rb_intern("to_hash");
1489
+ oj_to_h_id = rb_intern("to_h");
2216
1490
  oj_to_json_id = rb_intern("to_json");
2217
1491
  oj_to_s_id = rb_intern("to_s");
2218
1492
  oj_to_sym_id = rb_intern("to_sym");
@@ -2224,7 +1498,7 @@ void Init_oj() {
2224
1498
  oj_utc_offset_id = rb_intern("utc_offset");
2225
1499
  oj_utcq_id = rb_intern("utc?");
2226
1500
  oj_write_id = rb_intern("write");
2227
- has_key_id = rb_intern("has_key?");
1501
+ oj_has_key_id = rb_intern("has_key?");
2228
1502
 
2229
1503
  rb_require("oj/bag");
2230
1504
  rb_require("oj/error");
@@ -2236,64 +1510,78 @@ void Init_oj() {
2236
1510
  oj_bigdecimal_class = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
2237
1511
  oj_date_class = rb_const_get(rb_cObject, rb_intern("Date"));
2238
1512
  oj_datetime_class = rb_const_get(rb_cObject, rb_intern("DateTime"));
1513
+ oj_enumerable_class = rb_const_get(rb_cObject, rb_intern("Enumerable"));
2239
1514
  oj_parse_error_class = rb_const_get_at(Oj, rb_intern("ParseError"));
2240
1515
  oj_stringio_class = rb_const_get(rb_cObject, rb_intern("StringIO"));
2241
1516
  oj_struct_class = rb_const_get(rb_cObject, rb_intern("Struct"));
2242
- json_parser_error_class = Qnil; // replaced if mimic is called
2243
-
2244
- allow_gc_sym = ID2SYM(rb_intern("allow_gc")); rb_gc_register_address(&allow_gc_sym);
2245
- array_nl_sym = ID2SYM(rb_intern("array_nl")); rb_gc_register_address(&array_nl_sym);
2246
- ascii_only_sym = ID2SYM(rb_intern("ascii_only")); rb_gc_register_address(&ascii_only_sym);
2247
- ascii_sym = ID2SYM(rb_intern("ascii")); rb_gc_register_address(&ascii_sym);
2248
- auto_define_sym = ID2SYM(rb_intern("auto_define")); rb_gc_register_address(&auto_define_sym);
2249
- auto_sym = ID2SYM(rb_intern("auto")); rb_gc_register_address(&auto_sym);
2250
- bigdecimal_as_decimal_sym = ID2SYM(rb_intern("bigdecimal_as_decimal"));rb_gc_register_address(&bigdecimal_as_decimal_sym);
2251
- bigdecimal_load_sym = ID2SYM(rb_intern("bigdecimal_load"));rb_gc_register_address(&bigdecimal_load_sym);
2252
- bigdecimal_sym = ID2SYM(rb_intern("bigdecimal")); rb_gc_register_address(&bigdecimal_sym);
2253
- circular_sym = ID2SYM(rb_intern("circular")); rb_gc_register_address(&circular_sym);
2254
- class_cache_sym = ID2SYM(rb_intern("class_cache")); rb_gc_register_address(&class_cache_sym);
2255
- compat_sym = ID2SYM(rb_intern("compat")); rb_gc_register_address(&compat_sym);
2256
- create_id_sym = ID2SYM(rb_intern("create_id")); rb_gc_register_address(&create_id_sym);
2257
- escape_mode_sym = ID2SYM(rb_intern("escape_mode")); rb_gc_register_address(&escape_mode_sym);
2258
- float_prec_sym = ID2SYM(rb_intern("float_precision"));rb_gc_register_address(&float_prec_sym);
2259
- float_sym = ID2SYM(rb_intern("float")); rb_gc_register_address(&float_sym);
2260
- hash_class_sym = ID2SYM(rb_intern("hash_class")); rb_gc_register_address(&hash_class_sym);
2261
- huge_sym = ID2SYM(rb_intern("huge")); rb_gc_register_address(&huge_sym);
2262
- indent_sym = ID2SYM(rb_intern("indent")); rb_gc_register_address(&indent_sym);
2263
- json_sym = ID2SYM(rb_intern("json")); rb_gc_register_address(&json_sym);
2264
- mode_sym = ID2SYM(rb_intern("mode")); rb_gc_register_address(&mode_sym);
2265
- nan_sym = ID2SYM(rb_intern("nan")); rb_gc_register_address(&nan_sym);
2266
- newline_sym = ID2SYM(rb_intern("newline")); rb_gc_register_address(&newline_sym);
2267
- nilnil_sym = ID2SYM(rb_intern("nilnil")); rb_gc_register_address(&nilnil_sym);
2268
- empty_string_sym = ID2SYM(rb_intern("empty_string"));rb_gc_register_address(&empty_string_sym);
2269
- null_sym = ID2SYM(rb_intern("null")); rb_gc_register_address(&null_sym);
2270
- object_nl_sym = ID2SYM(rb_intern("object_nl")); rb_gc_register_address(&object_nl_sym);
2271
- object_sym = ID2SYM(rb_intern("object")); rb_gc_register_address(&object_sym);
2272
- omit_nil_sym = ID2SYM(rb_intern("omit_nil")); rb_gc_register_address(&omit_nil_sym);
2273
- quirks_mode_sym = ID2SYM(rb_intern("quirks_mode")); rb_gc_register_address(&quirks_mode_sym);
1517
+ oj_json_parser_error_class = rb_eEncodingError; // replaced if mimic is called
1518
+ oj_json_generator_error_class = rb_eEncodingError; // replaced if mimic is called
1519
+
1520
+ allow_blank_sym = ID2SYM(rb_intern("allow_blank")); rb_gc_register_address(&allow_blank_sym);
1521
+ allow_gc_sym = ID2SYM(rb_intern("allow_gc")); rb_gc_register_address(&allow_gc_sym);
2274
1522
  allow_invalid_unicode_sym = ID2SYM(rb_intern("allow_invalid_unicode"));rb_gc_register_address(&allow_invalid_unicode_sym);
2275
- raise_sym = ID2SYM(rb_intern("raise")); rb_gc_register_address(&raise_sym);
2276
- ruby_sym = ID2SYM(rb_intern("ruby")); rb_gc_register_address(&ruby_sym);
2277
- sec_prec_sym = ID2SYM(rb_intern("second_precision"));rb_gc_register_address(&sec_prec_sym);
2278
- space_before_sym = ID2SYM(rb_intern("space_before"));rb_gc_register_address(&space_before_sym);
2279
- space_sym = ID2SYM(rb_intern("space")); rb_gc_register_address(&space_sym);
2280
- strict_sym = ID2SYM(rb_intern("strict")); rb_gc_register_address(&strict_sym);
2281
- symbol_keys_sym = ID2SYM(rb_intern("symbol_keys")); rb_gc_register_address(&symbol_keys_sym);
2282
- time_format_sym = ID2SYM(rb_intern("time_format")); rb_gc_register_address(&time_format_sym);
2283
- unix_sym = ID2SYM(rb_intern("unix")); rb_gc_register_address(&unix_sym);
2284
- unix_zone_sym = ID2SYM(rb_intern("unix_zone")); rb_gc_register_address(&unix_zone_sym);
2285
- use_as_json_sym = ID2SYM(rb_intern("use_as_json")); rb_gc_register_address(&use_as_json_sym);
2286
- use_to_json_sym = ID2SYM(rb_intern("use_to_json")); rb_gc_register_address(&use_to_json_sym);
2287
- word_sym = ID2SYM(rb_intern("word")); rb_gc_register_address(&word_sym);
2288
- xmlschema_sym = ID2SYM(rb_intern("xmlschema")); rb_gc_register_address(&xmlschema_sym);
2289
- xss_safe_sym = ID2SYM(rb_intern("xss_safe")); rb_gc_register_address(&xss_safe_sym);
2290
-
2291
- oj_slash_string = rb_str_new2("/"); rb_gc_register_address(&oj_slash_string);
1523
+ ascii_sym = ID2SYM(rb_intern("ascii")); rb_gc_register_address(&ascii_sym);
1524
+ auto_define_sym = ID2SYM(rb_intern("auto_define")); rb_gc_register_address(&auto_define_sym);
1525
+ auto_sym = ID2SYM(rb_intern("auto")); rb_gc_register_address(&auto_sym);
1526
+ bigdecimal_as_decimal_sym = ID2SYM(rb_intern("bigdecimal_as_decimal"));rb_gc_register_address(&bigdecimal_as_decimal_sym);
1527
+ bigdecimal_load_sym = ID2SYM(rb_intern("bigdecimal_load")); rb_gc_register_address(&bigdecimal_load_sym);
1528
+ bigdecimal_sym = ID2SYM(rb_intern("bigdecimal")); rb_gc_register_address(&bigdecimal_sym);
1529
+ circular_sym = ID2SYM(rb_intern("circular")); rb_gc_register_address(&circular_sym);
1530
+ class_cache_sym = ID2SYM(rb_intern("class_cache")); rb_gc_register_address(&class_cache_sym);
1531
+ compat_sym = ID2SYM(rb_intern("compat")); rb_gc_register_address(&compat_sym);
1532
+ create_id_sym = ID2SYM(rb_intern("create_id")); rb_gc_register_address(&create_id_sym);
1533
+ custom_sym = ID2SYM(rb_intern("custom")); rb_gc_register_address(&custom_sym);
1534
+ empty_string_sym = ID2SYM(rb_intern("empty_string")); rb_gc_register_address(&empty_string_sym);
1535
+ escape_mode_sym = ID2SYM(rb_intern("escape_mode")); rb_gc_register_address(&escape_mode_sym);
1536
+ float_prec_sym = ID2SYM(rb_intern("float_precision")); rb_gc_register_address(&float_prec_sym);
1537
+ float_sym = ID2SYM(rb_intern("float")); rb_gc_register_address(&float_sym);
1538
+ huge_sym = ID2SYM(rb_intern("huge")); rb_gc_register_address(&huge_sym);
1539
+ json_sym = ID2SYM(rb_intern("json")); rb_gc_register_address(&json_sym);
1540
+ match_string_sym = ID2SYM(rb_intern("match_string")); rb_gc_register_address(&match_string_sym);
1541
+ mode_sym = ID2SYM(rb_intern("mode")); rb_gc_register_address(&mode_sym);
1542
+ nan_sym = ID2SYM(rb_intern("nan")); rb_gc_register_address(&nan_sym);
1543
+ newline_sym = ID2SYM(rb_intern("newline")); rb_gc_register_address(&newline_sym);
1544
+ nilnil_sym = ID2SYM(rb_intern("nilnil")); rb_gc_register_address(&nilnil_sym);
1545
+ null_sym = ID2SYM(rb_intern("null")); rb_gc_register_address(&null_sym);
1546
+ object_sym = ID2SYM(rb_intern("object")); rb_gc_register_address(&object_sym);
1547
+ oj_allow_nan_sym = ID2SYM(rb_intern("allow_nan")); rb_gc_register_address(&oj_allow_nan_sym);
1548
+ oj_array_class_sym = ID2SYM(rb_intern("array_class")); rb_gc_register_address(&oj_array_class_sym);
1549
+ oj_array_nl_sym = ID2SYM(rb_intern("array_nl")); rb_gc_register_address(&oj_array_nl_sym);
1550
+ oj_ascii_only_sym = ID2SYM(rb_intern("ascii_only")); rb_gc_register_address(&oj_ascii_only_sym);
1551
+ oj_create_additions_sym = ID2SYM(rb_intern("create_additions"));rb_gc_register_address(&oj_create_additions_sym);
1552
+ oj_hash_class_sym = ID2SYM(rb_intern("hash_class")); rb_gc_register_address(&oj_hash_class_sym);
1553
+ oj_indent_sym = ID2SYM(rb_intern("indent")); rb_gc_register_address(&oj_indent_sym);
1554
+ oj_max_nesting_sym = ID2SYM(rb_intern("max_nesting")); rb_gc_register_address(&oj_max_nesting_sym);
1555
+ oj_object_class_sym = ID2SYM(rb_intern("object_class")); rb_gc_register_address(&oj_object_class_sym);
1556
+ oj_object_nl_sym = ID2SYM(rb_intern("object_nl")); rb_gc_register_address(&oj_object_nl_sym);
1557
+ oj_quirks_mode_sym = ID2SYM(rb_intern("quirks_mode")); rb_gc_register_address(&oj_quirks_mode_sym);
1558
+ oj_space_before_sym = ID2SYM(rb_intern("space_before")); rb_gc_register_address(&oj_space_before_sym);
1559
+ oj_space_sym = ID2SYM(rb_intern("space")); rb_gc_register_address(&oj_space_sym);
1560
+ omit_nil_sym = ID2SYM(rb_intern("omit_nil")); rb_gc_register_address(&omit_nil_sym);
1561
+ rails_sym = ID2SYM(rb_intern("rails")); rb_gc_register_address(&rails_sym);
1562
+ raise_sym = ID2SYM(rb_intern("raise")); rb_gc_register_address(&raise_sym);
1563
+ ruby_sym = ID2SYM(rb_intern("ruby")); rb_gc_register_address(&ruby_sym);
1564
+ sec_prec_sym = ID2SYM(rb_intern("second_precision")); rb_gc_register_address(&sec_prec_sym);
1565
+ strict_sym = ID2SYM(rb_intern("strict")); rb_gc_register_address(&strict_sym);
1566
+ symbol_keys_sym = ID2SYM(rb_intern("symbol_keys")); rb_gc_register_address(&symbol_keys_sym);
1567
+ time_format_sym = ID2SYM(rb_intern("time_format")); rb_gc_register_address(&time_format_sym);
1568
+ unicode_xss_sym = ID2SYM(rb_intern("unicode_xss")); rb_gc_register_address(&unicode_xss_sym);
1569
+ unix_sym = ID2SYM(rb_intern("unix")); rb_gc_register_address(&unix_sym);
1570
+ unix_zone_sym = ID2SYM(rb_intern("unix_zone")); rb_gc_register_address(&unix_zone_sym);
1571
+ use_as_json_sym = ID2SYM(rb_intern("use_as_json")); rb_gc_register_address(&use_as_json_sym);
1572
+ use_to_hash_sym = ID2SYM(rb_intern("use_to_hash")); rb_gc_register_address(&use_to_hash_sym);
1573
+ use_to_json_sym = ID2SYM(rb_intern("use_to_json")); rb_gc_register_address(&use_to_json_sym);
1574
+ word_sym = ID2SYM(rb_intern("word")); rb_gc_register_address(&word_sym);
1575
+ xmlschema_sym = ID2SYM(rb_intern("xmlschema")); rb_gc_register_address(&xmlschema_sym);
1576
+ xss_safe_sym = ID2SYM(rb_intern("xss_safe")); rb_gc_register_address(&xss_safe_sym);
1577
+
1578
+ oj_slash_string = rb_str_new2("/"); rb_gc_register_address(&oj_slash_string);
2292
1579
 
2293
1580
  oj_default_options.mode = ObjectMode;
2294
1581
 
2295
1582
  oj_hash_init();
2296
1583
  oj_odd_init();
1584
+ oj_mimic_rails_init();
2297
1585
 
2298
1586
  #if USE_PTHREAD_MUTEX
2299
1587
  pthread_mutex_init(&oj_cache_mutex, 0);
@@ -2304,139 +1592,3 @@ void Init_oj() {
2304
1592
  oj_init_doc();
2305
1593
  }
2306
1594
 
2307
- // mimic JSON documentation
2308
-
2309
- /* Document-module: JSON
2310
- *
2311
- * JSON is a JSON parser. This module when defined by the Oj module is a
2312
- * faster replacement for the original.
2313
- */
2314
- /* Document-module: JSON::Ext
2315
- *
2316
- * The Ext module is a placeholder in the mimic JSON module used for
2317
- * compatibility only.
2318
- */
2319
- /* Document-class: JSON::Ext::Parser
2320
- *
2321
- * The JSON::Ext::Parser is a placeholder in the mimic JSON module used for
2322
- * compatibility only.
2323
- */
2324
- /* Document-class: JSON::Ext::Generator
2325
- *
2326
- * The JSON::Ext::Generator is a placeholder in the mimic JSON module used for
2327
- * compatibility only.
2328
- */
2329
-
2330
- /* Document-method: create_id=
2331
- * call-seq: create_id=(id) -> String
2332
- *
2333
- * Sets the create_id tag to look for in JSON document. That key triggers the
2334
- * creation of a class with the same name.
2335
- *
2336
- * @param [nil|String] id new create_id
2337
- * @return the id
2338
- */
2339
- /* Document-method: parser=
2340
- * call-seq: parser=(parser) -> nil
2341
- *
2342
- * Does nothing other than provide compatibiltiy.
2343
- * @param [Object] parser ignored
2344
- */
2345
- /* Document-method: generator=
2346
- * call-seq: generator=(generator) -> nil
2347
- *
2348
- * Does nothing other than provide compatibiltiy.
2349
- * @param [Object] generator ignored
2350
- */
2351
- /* Document-method: dump
2352
- * call-seq: dump(obj, anIO=nil, limit = nil) -> String
2353
- *
2354
- * Encodes an object as a JSON String.
2355
- *
2356
- * @param [Object] obj object to convert to encode as JSON
2357
- * @param [IO] anIO an IO that allows writing
2358
- * @param [Fixnum] limit ignored
2359
- */
2360
- /* Document-method: load
2361
- * call-seq: load(source, proc=nil) -> Object
2362
- *
2363
- * Loads a Ruby Object from a JSON source that can be either a String or an
2364
- * IO. If Proc is given or a block is providedit is called with each nested
2365
- * element of the loaded Object.
2366
- *
2367
- * @param [String|IO] source JSON source
2368
- * @param [Proc] proc to yield to on each element or nil
2369
- */
2370
- /* Document-method: restore
2371
- * call-seq: restore(source, proc=nil) -> Object
2372
- *
2373
- * Loads a Ruby Object from a JSON source that can be either a String or an
2374
- * IO. If Proc is given or a block is providedit is called with each nested
2375
- * element of the loaded Object.
2376
- *
2377
- * @param [String|IO] source JSON source
2378
- * @param [Proc] proc to yield to on each element or nil
2379
- */
2380
- /* Document-method: recurse_proc
2381
- * call-seq: recurse_proc(obj, &proc) -> nil
2382
- *
2383
- * Yields to the proc for every element in the obj recursivly.
2384
- *
2385
- * @param [Hash|Array] obj object to walk
2386
- * @param [Proc] proc to yield to on each element
2387
- */
2388
- /* Document-method: []
2389
- * call-seq: [](obj, opts={}) -> Object
2390
- *
2391
- * If the obj argument is a String then it is assumed to be a JSON String and
2392
- * parsed otherwise the obj is encoded as a JSON String.
2393
- *
2394
- * @param [String|Hash|Array] obj object to convert
2395
- * @param [Hash] opts same options as either generate or parse
2396
- */
2397
- /* Document-method: generate
2398
- * call-seq: generate(obj, opts=nil) -> String
2399
- *
2400
- * Encode obj as a JSON String. The obj argument must be a Hash, Array, or
2401
- * respond to to_h or to_json. Options other than those listed such as
2402
- * +:allow_nan+ or +:max_nesting+ are ignored.
2403
- *
2404
- * @param [Object|Hash|Array] obj object to convert to a JSON String
2405
- * @param [Hash] opts options
2406
- * @param [String] :indent String to use for indentation
2407
- * @param [String] :space String placed after a , or : delimiter
2408
- * @param [String] :space_before String placed before a : delimiter
2409
- * @param [String] :object_nl String placed after a JSON object
2410
- * @param [String] :array_nl String placed after a JSON array
2411
- * @param [true|false] :ascii_only if not nil or false then use only ascii
2412
- * characters in the output. Note JSON.generate does
2413
- * support this even if it is not documented.
2414
- */
2415
- /* Document-method: fast_generate
2416
- * call-seq: fast_generate(obj, opts=nil) -> String
2417
- * Same as generate().
2418
- * @see generate
2419
- */
2420
- /* Document-method: pretty_generate
2421
- * call-seq: pretty_generate(obj, opts=nil) -> String
2422
- * Same as generate() but with different defaults for the spacing options.
2423
- * @see generate
2424
- */
2425
- /* Document-method: parse
2426
- * call-seq: parse(source, opts=nil) -> Object
2427
- *
2428
- * Parses a JSON String or IO into a Ruby Object. Options other than those
2429
- * listed such as +:allow_nan+ or +:max_nesting+ are ignored. +:object_class+ and
2430
- * +:array_object+ are not supported.
2431
- *
2432
- * @param [String|IO] source source to parse
2433
- * @param [Hash] opts options
2434
- * @param [true|false] :symbolize_names flag indicating JSON object keys should be Symbols instead of Strings
2435
- * @param [true|false] :create_additions flag indicating a key matching +create_id+ in a JSON object should trigger the creation of Ruby Object
2436
- * @see create_id=
2437
- */
2438
- /* Document-method: parse!
2439
- * call-seq: parse!(source, opts=nil) -> Object
2440
- * Same as parse().
2441
- * @see parse
2442
- */