oj 2.18.5 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
- */