oj 2.18.3 → 3.13.14

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