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
@@ -0,0 +1,936 @@
1
+ // Copyright (c) 2012, 2017 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #include "code.h"
5
+ #include "dump.h"
6
+ #include "rails.h"
7
+ #include "trace.h"
8
+
9
+ // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
10
+ #define OJ_INFINITY (1.0/0.0)
11
+
12
+ bool oj_use_hash_alt = false;
13
+ bool oj_use_array_alt = false;
14
+
15
+ static bool use_struct_alt = false;
16
+ static bool use_exception_alt = false;
17
+ static bool use_bignum_alt = false;
18
+
19
+ static void
20
+ raise_json_err(const char *msg, const char *err_classname) {
21
+ rb_raise(oj_get_json_err_class(err_classname), "%s", msg);
22
+ }
23
+
24
+ static void
25
+ dump_obj_classname(const char *classname, int depth, Out out) {
26
+ int d2 = depth + 1;
27
+ size_t len = strlen(classname);
28
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
29
+ size_t size = d2 * out->indent + 10 + len + out->opts->create_id_len + sep_len;
30
+
31
+ assure_size(out, size);
32
+ *out->cur++ = '{';
33
+ fill_indent(out, d2);
34
+ *out->cur++ = '"';
35
+ APPEND_CHARS(out->cur, out->opts->create_id, out->opts->create_id_len);
36
+ *out->cur++ = '"';
37
+ if (0 < out->opts->dump_opts.before_size) {
38
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
39
+ }
40
+ *out->cur++ = ':';
41
+ if (0 < out->opts->dump_opts.after_size) {
42
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
43
+ }
44
+ *out->cur++ = '"';
45
+ APPEND_CHARS(out->cur, classname, len);
46
+ *out->cur++ = '"';
47
+ }
48
+
49
+ static void
50
+ dump_values_array(VALUE *values, int depth, Out out) {
51
+ size_t size;
52
+ int d2 = depth + 1;
53
+
54
+ assure_size(out, d2 * out->indent + 3);
55
+ *out->cur++ = '[';
56
+ if (Qundef == *values) {
57
+ *out->cur++ = ']';
58
+ } else {
59
+ if (out->opts->dump_opts.use) {
60
+ size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 2;
61
+ size += out->opts->dump_opts.array_size;
62
+ size += out->opts->dump_opts.indent_size;
63
+ } else {
64
+ size = d2 * out->indent + 3;
65
+ }
66
+ for (; Qundef != *values; values++) {
67
+ assure_size(out, size);
68
+ if (out->opts->dump_opts.use) {
69
+ if (0 < out->opts->dump_opts.array_size) {
70
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
71
+ }
72
+ if (0 < out->opts->dump_opts.indent_size) {
73
+ int i;
74
+
75
+ for (i = d2; 0 < i; i--) {
76
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
77
+ }
78
+ }
79
+ } else {
80
+ fill_indent(out, d2);
81
+ }
82
+ oj_dump_compat_val(*values, d2, out, true);
83
+ if (Qundef != *(values + 1)) {
84
+ *out->cur++ = ',';
85
+ }
86
+ }
87
+ assure_size(out, size);
88
+ if (out->opts->dump_opts.use) {
89
+ if (0 < out->opts->dump_opts.array_size) {
90
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
91
+ }
92
+ if (0 < out->opts->dump_opts.indent_size) {
93
+ int i;
94
+
95
+ for (i = depth; 0 < i; i--) {
96
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
97
+ }
98
+ }
99
+ } else {
100
+ fill_indent(out, depth);
101
+ }
102
+ *out->cur++ = ']';
103
+ }
104
+ }
105
+
106
+ static void
107
+ dump_to_json(VALUE obj, Out out) {
108
+ volatile VALUE rs;
109
+ const char *s;
110
+ int len;
111
+
112
+ if (Yes == out->opts->trace) {
113
+ oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyIn);
114
+ }
115
+ if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
116
+ rs = rb_funcall(obj, oj_to_json_id, 0);
117
+ } else {
118
+ rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
119
+ }
120
+ if (Yes == out->opts->trace) {
121
+ oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyOut);
122
+ }
123
+
124
+ s = RSTRING_PTR(rs);
125
+ len = (int)RSTRING_LEN(rs);
126
+
127
+ assure_size(out, len + 1);
128
+ APPEND_CHARS(out->cur, s, len);
129
+ *out->cur = '\0';
130
+ }
131
+
132
+ static void
133
+ dump_array(VALUE a, int depth, Out out, bool as_ok) {
134
+ size_t size;
135
+ int i, cnt;
136
+ int d2 = depth + 1;
137
+ long id = oj_check_circular(a, out);
138
+
139
+ if (0 > id) {
140
+ raise_json_err("Too deeply nested", "NestingError");
141
+ return;
142
+ }
143
+ if (as_ok && !oj_use_hash_alt && rb_obj_class(a) != rb_cArray && rb_respond_to(a, oj_to_json_id)) {
144
+ dump_to_json(a, out);
145
+ return;
146
+ }
147
+ cnt = (int)RARRAY_LEN(a);
148
+ *out->cur++ = '[';
149
+ assure_size(out, 2);
150
+ if (0 == cnt) {
151
+ *out->cur++ = ']';
152
+ } else {
153
+ if (out->opts->dump_opts.use) {
154
+ size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
155
+ } else {
156
+ size = d2 * out->indent + 2;
157
+ }
158
+ assure_size(out, size * cnt);
159
+ cnt--;
160
+ for (i = 0; i <= cnt; i++) {
161
+ if (out->opts->dump_opts.use) {
162
+ if (0 < out->opts->dump_opts.array_size) {
163
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
164
+ }
165
+ if (0 < out->opts->dump_opts.indent_size) {
166
+ int i;
167
+ for (i = d2; 0 < i; i--) {
168
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
169
+ }
170
+ }
171
+ } else {
172
+ fill_indent(out, d2);
173
+ }
174
+ oj_dump_compat_val(RARRAY_AREF(a, i), d2, out, true);
175
+ if (i < cnt) {
176
+ *out->cur++ = ',';
177
+ }
178
+ }
179
+ if (out->opts->dump_opts.use) {
180
+ size = out->opts->dump_opts.array_size + out->opts->dump_opts.indent_size * depth + 1;
181
+ assure_size(out, size);
182
+ if (0 < out->opts->dump_opts.array_size) {
183
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
184
+ }
185
+ if (0 < out->opts->dump_opts.indent_size) {
186
+ int i;
187
+
188
+ for (i = depth; 0 < i; i--) {
189
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
190
+ }
191
+ }
192
+ } else {
193
+ size = depth * out->indent + 1;
194
+ assure_size(out, size);
195
+ fill_indent(out, depth);
196
+ }
197
+ *out->cur++ = ']';
198
+ }
199
+ *out->cur = '\0';
200
+ }
201
+
202
+ static ID _dump_id = 0;
203
+
204
+ static void
205
+ bigdecimal_alt(VALUE obj, int depth, Out out) {
206
+ struct _attr attrs[] = {
207
+ { "b", 1, Qnil },
208
+ { NULL, 0, Qnil },
209
+ };
210
+
211
+ if (0 == _dump_id) {
212
+ _dump_id = rb_intern("_dump");
213
+ }
214
+ attrs[0].value = rb_funcall(obj, _dump_id, 0);
215
+
216
+ oj_code_attrs(obj, attrs, depth, out, true);
217
+ }
218
+
219
+ static ID real_id = 0;
220
+ static ID imag_id = 0;
221
+
222
+ static void
223
+ complex_alt(VALUE obj, int depth, Out out) {
224
+ struct _attr attrs[] = {
225
+ { "r", 1, Qnil },
226
+ { "i", 1, Qnil },
227
+ { NULL, 0, Qnil },
228
+ };
229
+
230
+ if (0 == real_id) {
231
+ real_id = rb_intern("real");
232
+ imag_id = rb_intern("imag");
233
+ }
234
+ attrs[0].value = rb_funcall(obj, real_id, 0);
235
+ attrs[1].value = rb_funcall(obj, imag_id, 0);
236
+
237
+ oj_code_attrs(obj, attrs, depth, out, true);
238
+ }
239
+
240
+ static ID year_id = 0;
241
+ static ID month_id = 0;
242
+ static ID day_id = 0;
243
+ static ID start_id = 0;
244
+
245
+ static void
246
+ date_alt(VALUE obj, int depth, Out out) {
247
+ struct _attr attrs[] = {
248
+ { "y", 1, Qnil },
249
+ { "m", 1, Qnil },
250
+ { "d", 1, Qnil },
251
+ { "sg", 2, Qnil },
252
+ { NULL, 0, Qnil },
253
+ };
254
+ if (0 == year_id) {
255
+ year_id = rb_intern("year");
256
+ month_id = rb_intern("month");
257
+ day_id = rb_intern("day");
258
+ start_id = rb_intern("start");
259
+ }
260
+ attrs[0].value = rb_funcall(obj, year_id, 0);
261
+ attrs[1].value = rb_funcall(obj, month_id, 0);
262
+ attrs[2].value = rb_funcall(obj, day_id, 0);
263
+ attrs[3].value = rb_funcall(obj, start_id, 0);
264
+
265
+ oj_code_attrs(obj, attrs, depth, out, true);
266
+ }
267
+
268
+ static ID hour_id = 0;
269
+ static ID min_id = 0;
270
+ static ID sec_id = 0;
271
+ static ID offset_id = 0;
272
+
273
+ static void
274
+ datetime_alt(VALUE obj, int depth, Out out) {
275
+ struct _attr attrs[] = {
276
+ { "y", 1, Qnil },
277
+ { "m", 1, Qnil },
278
+ { "d", 1, Qnil },
279
+ { "H", 1, Qnil },
280
+ { "M", 1, Qnil },
281
+ { "S", 1, Qnil },
282
+ { "of", 2, Qnil },
283
+ { "sg", 2, Qnil },
284
+ { NULL, 0, Qnil },
285
+ };
286
+ if (0 == hour_id) {
287
+ year_id = rb_intern("year");
288
+ month_id = rb_intern("month");
289
+ day_id = rb_intern("day");
290
+ hour_id = rb_intern("hour");
291
+ min_id = rb_intern("min");
292
+ sec_id = rb_intern("sec");
293
+ offset_id = rb_intern("offset");
294
+ start_id = rb_intern("start");
295
+ }
296
+ attrs[0].value = rb_funcall(obj, year_id, 0);
297
+ attrs[1].value = rb_funcall(obj, month_id, 0);
298
+ attrs[2].value = rb_funcall(obj, day_id, 0);
299
+ attrs[3].value = rb_funcall(obj, hour_id, 0);
300
+ attrs[4].value = rb_funcall(obj, min_id, 0);
301
+ attrs[5].value = rb_funcall(obj, sec_id, 0);
302
+ attrs[6].value = rb_funcall(rb_funcall(obj, offset_id, 0), oj_to_s_id, 0);
303
+ attrs[7].value = rb_funcall(obj, start_id, 0);
304
+
305
+ oj_code_attrs(obj, attrs, depth, out, true);
306
+ }
307
+
308
+ static ID message_id = 0;
309
+ static ID backtrace_id = 0;
310
+
311
+ static void
312
+ exception_alt(VALUE obj, int depth, Out out) {
313
+ int d3 = depth + 2;
314
+ size_t size = d3 * out->indent + 2;
315
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
316
+
317
+ if (0 == message_id) {
318
+ message_id = rb_intern("message");
319
+ backtrace_id = rb_intern("backtrace");
320
+ }
321
+ dump_obj_classname(rb_class2name(rb_obj_class(obj)), depth, out);
322
+
323
+ assure_size(out, size + sep_len + 6);
324
+ *out->cur++ = ',';
325
+ fill_indent(out, d3);
326
+ APPEND_CHARS(out->cur, "\"m\"", 3);
327
+ if (0 < out->opts->dump_opts.before_size) {
328
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
329
+ }
330
+ *out->cur++ = ':';
331
+ if (0 < out->opts->dump_opts.after_size) {
332
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
333
+ }
334
+ oj_dump_str(rb_funcall(obj, message_id, 0), 0, out, false);
335
+ assure_size(out, size + sep_len + 6);
336
+ *out->cur++ = ',';
337
+ fill_indent(out, d3);
338
+ APPEND_CHARS(out->cur, "\"b\"", 3);
339
+ if (0 < out->opts->dump_opts.before_size) {
340
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
341
+ }
342
+ *out->cur++ = ':';
343
+ if (0 < out->opts->dump_opts.after_size) {
344
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
345
+ }
346
+ dump_array(rb_funcall(obj, backtrace_id, 0), depth, out, false);
347
+ fill_indent(out, depth);
348
+ *out->cur++ = '}';
349
+ *out->cur = '\0';
350
+ }
351
+
352
+ static ID table_id = 0;
353
+
354
+ static void
355
+ openstruct_alt(VALUE obj, int depth, Out out) {
356
+ struct _attr attrs[] = {
357
+ { "t", 1, Qnil },
358
+ { NULL, 0, Qnil },
359
+ };
360
+ if (0 == table_id) {
361
+ table_id = rb_intern("table");
362
+ }
363
+ attrs[0].value = rb_funcall(obj, table_id, 0);
364
+
365
+ oj_code_attrs(obj, attrs, depth, out, true);
366
+ }
367
+
368
+ static void
369
+ range_alt(VALUE obj, int depth, Out out) {
370
+ int d3 = depth + 2;
371
+ size_t size = d3 * out->indent + 2;
372
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
373
+ VALUE args[] = { Qundef, Qundef, Qundef, Qundef };
374
+
375
+ dump_obj_classname(rb_class2name(rb_obj_class(obj)), depth, out);
376
+
377
+ assure_size(out, size + sep_len + 6);
378
+ *out->cur++ = ',';
379
+ fill_indent(out, d3);
380
+ APPEND_CHARS(out->cur, "\"a\"", 3);
381
+ if (0 < out->opts->dump_opts.before_size) {
382
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
383
+ }
384
+ *out->cur++ = ':';
385
+ if (0 < out->opts->dump_opts.after_size) {
386
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
387
+ }
388
+ args[0] = rb_funcall(obj, oj_begin_id, 0);
389
+ args[1] = rb_funcall(obj, oj_end_id, 0);
390
+ args[2] = rb_funcall(obj, oj_exclude_end_id, 0);
391
+ dump_values_array(args, depth, out);
392
+ fill_indent(out, depth);
393
+ *out->cur++ = '}';
394
+ *out->cur = '\0';
395
+ }
396
+
397
+ static ID numerator_id = 0;
398
+ static ID denominator_id = 0;
399
+
400
+ static void
401
+ rational_alt(VALUE obj, int depth, Out out) {
402
+ struct _attr attrs[] = {
403
+ { "n", 1, Qnil },
404
+ { "d", 1, Qnil },
405
+ { NULL, 0, Qnil },
406
+ };
407
+ if (0 == numerator_id) {
408
+ numerator_id = rb_intern("numerator");
409
+ denominator_id = rb_intern("denominator");
410
+ }
411
+ attrs[0].value = rb_funcall(obj, numerator_id, 0);
412
+ attrs[1].value = rb_funcall(obj, denominator_id, 0);
413
+
414
+ oj_code_attrs(obj, attrs, depth, out, true);
415
+ }
416
+
417
+ static ID options_id = 0;
418
+ static ID source_id = 0;
419
+
420
+ static void
421
+ regexp_alt(VALUE obj, int depth, Out out) {
422
+ struct _attr attrs[] = {
423
+ { "o", 1, Qnil },
424
+ { "s", 1, Qnil },
425
+ { NULL, 0, Qnil },
426
+ };
427
+ if (0 == options_id) {
428
+ options_id = rb_intern("options");
429
+ source_id = rb_intern("source");
430
+ }
431
+ attrs[0].value = rb_funcall(obj, options_id, 0);
432
+ attrs[1].value = rb_funcall(obj, source_id, 0);
433
+
434
+ oj_code_attrs(obj, attrs, depth, out, true);
435
+ }
436
+
437
+ static void
438
+ time_alt(VALUE obj, int depth, Out out) {
439
+ struct _attr attrs[] = {
440
+ { "s", 1, Qundef, 0, Qundef },
441
+ { "n", 1, Qundef, 0, Qundef },
442
+ { NULL, 0, Qnil },
443
+ };
444
+ time_t sec;
445
+ long long nsec;
446
+
447
+ #ifdef HAVE_RB_TIME_TIMESPEC
448
+ if (16 <= sizeof(struct timespec)) {
449
+ struct timespec ts = rb_time_timespec(obj);
450
+
451
+ sec = (long long)ts.tv_sec;
452
+ nsec = ts.tv_nsec;
453
+ } else {
454
+ sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
455
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
456
+ }
457
+ #else
458
+ sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
459
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
460
+ #endif
461
+
462
+ attrs[0].num = sec;
463
+ attrs[1].num = nsec;
464
+
465
+ oj_code_attrs(obj, attrs, depth, out, true);
466
+ }
467
+
468
+ struct _code oj_compat_codes[] = {
469
+ { "BigDecimal", Qnil, bigdecimal_alt, NULL, false },
470
+ { "Complex", Qnil, complex_alt, NULL, false },
471
+ { "Date", Qnil, date_alt, false },
472
+ { "DateTime", Qnil, datetime_alt, NULL, false },
473
+ { "OpenStruct", Qnil, openstruct_alt, NULL, false },
474
+ { "Range", Qnil, range_alt, NULL, false },
475
+ { "Rational", Qnil, rational_alt, NULL, false },
476
+ { "Regexp", Qnil, regexp_alt, NULL, false },
477
+ { "Time", Qnil, time_alt, NULL, false },
478
+ // TBD the rest of the library classes
479
+ { NULL, Qundef, NULL, NULL, false },
480
+ };
481
+
482
+ VALUE
483
+ oj_add_to_json(int argc, VALUE *argv, VALUE self) {
484
+ Code a;
485
+
486
+ if (0 == argc) {
487
+ for (a = oj_compat_codes; NULL != a->name; a++) {
488
+ if (Qnil == a->clas || Qundef == a->clas) {
489
+ a->clas = rb_const_get_at(rb_cObject, rb_intern(a->name));
490
+ }
491
+ a->active = true;
492
+ }
493
+ use_struct_alt = true;
494
+ use_exception_alt = true;
495
+ use_bignum_alt = true;
496
+ oj_use_hash_alt = true;
497
+ oj_use_array_alt = true;
498
+ } else {
499
+ for (; 0 < argc; argc--, argv++) {
500
+ if (rb_cStruct == *argv) {
501
+ use_struct_alt = true;
502
+ continue;
503
+ }
504
+ if (rb_eException == *argv) {
505
+ use_exception_alt = true;
506
+ continue;
507
+ }
508
+ if (rb_cInteger == *argv) {
509
+ use_bignum_alt = true;
510
+ continue;
511
+ }
512
+ if (rb_cHash == *argv) {
513
+ oj_use_hash_alt = true;
514
+ continue;
515
+ }
516
+ if (rb_cArray == *argv) {
517
+ oj_use_array_alt = true;
518
+ continue;
519
+ }
520
+ for (a = oj_compat_codes; NULL != a->name; a++) {
521
+ if (Qnil == a->clas || Qundef == a->clas) {
522
+ a->clas = rb_const_get_at(rb_cObject, rb_intern(a->name));
523
+ }
524
+ if (*argv == a->clas) {
525
+ a->active = true;
526
+ break;
527
+ }
528
+ }
529
+ }
530
+ }
531
+ return Qnil;
532
+ }
533
+
534
+ VALUE
535
+ oj_remove_to_json(int argc, VALUE *argv, VALUE self) {
536
+ if (0 == argc) {
537
+ oj_code_set_active(oj_compat_codes, Qnil, false);
538
+ use_struct_alt = false;
539
+ use_exception_alt = false;
540
+ use_bignum_alt = false;
541
+ oj_use_hash_alt = false;
542
+ oj_use_array_alt = false;
543
+ } else {
544
+ for (; 0 < argc; argc--, argv++) {
545
+ if (rb_cStruct == *argv) {
546
+ use_struct_alt = false;
547
+ continue;
548
+ }
549
+ if (rb_eException == *argv) {
550
+ use_exception_alt = false;
551
+ continue;
552
+ }
553
+ if (rb_cInteger == *argv) {
554
+ use_bignum_alt = false;
555
+ continue;
556
+ }
557
+ if (rb_cHash == *argv) {
558
+ oj_use_hash_alt = false;
559
+ continue;
560
+ }
561
+ if (rb_cArray == *argv) {
562
+ oj_use_array_alt = false;
563
+ continue;
564
+ }
565
+ oj_code_set_active(oj_compat_codes, *argv, false);
566
+ }
567
+ }
568
+ return Qnil;
569
+ }
570
+
571
+ // The JSON gem is inconsistent with handling of infinity. Using
572
+ // JSON.dump(0.1/0) returns the string Infinity but (0.1/0).to_json raise and
573
+ // exception. Worse, for BigDecimals a quoted "Infinity" is returned.
574
+ static void
575
+ dump_float(VALUE obj, int depth, Out out, bool as_ok) {
576
+ char buf[64];
577
+ char *b;
578
+ double d = rb_num2dbl(obj);
579
+ int cnt = 0;
580
+
581
+ if (0.0 == d) {
582
+ b = buf;
583
+ *b++ = '0';
584
+ *b++ = '.';
585
+ *b++ = '0';
586
+ *b++ = '\0';
587
+ cnt = 3;
588
+ } else if (OJ_INFINITY == d) {
589
+ if (WordNan == out->opts->dump_opts.nan_dump) {
590
+ strcpy(buf, "Infinity");
591
+ cnt = 8;
592
+ } else {
593
+ raise_json_err("Infinity not allowed in JSON.", "GeneratorError");
594
+ }
595
+ } else if (-OJ_INFINITY == d) {
596
+ if (WordNan == out->opts->dump_opts.nan_dump) {
597
+ strcpy(buf, "-Infinity");
598
+ cnt = 9;
599
+ } else {
600
+ raise_json_err("-Infinity not allowed in JSON.", "GeneratorError");
601
+ }
602
+ } else if (isnan(d)) {
603
+ if (WordNan == out->opts->dump_opts.nan_dump) {
604
+ strcpy(buf, "NaN");
605
+ cnt = 3;
606
+ } else {
607
+ raise_json_err("NaN not allowed in JSON.", "GeneratorError");
608
+ }
609
+ } else if (d == (double)(long long int)d) {
610
+ cnt = snprintf(buf, sizeof(buf), "%.1f", d);
611
+ } else if (oj_rails_float_opt) {
612
+ cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, "%0.16g");
613
+ } else {
614
+ volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
615
+
616
+ strcpy(buf, RSTRING_PTR(rstr));
617
+ cnt = (int)RSTRING_LEN(rstr);
618
+ }
619
+ assure_size(out, cnt);
620
+ APPEND_CHARS(out->cur, buf, cnt);
621
+ *out->cur = '\0';
622
+ }
623
+
624
+ static int
625
+ hash_cb(VALUE key, VALUE value, VALUE ov) {
626
+ Out out = (Out)ov;
627
+ int depth = out->depth;
628
+
629
+ if (out->omit_nil && Qnil == value) {
630
+ return ST_CONTINUE;
631
+ }
632
+ if (!out->opts->dump_opts.use) {
633
+ assure_size(out, depth * out->indent + 1);
634
+ fill_indent(out, depth);
635
+ } else {
636
+ assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
637
+ if (0 < out->opts->dump_opts.hash_size) {
638
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
639
+ }
640
+ if (0 < out->opts->dump_opts.indent_size) {
641
+ int i;
642
+ for (i = depth; 0 < i; i--) {
643
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
644
+ }
645
+ }
646
+ }
647
+ switch (rb_type(key)) {
648
+ case T_STRING:
649
+ oj_dump_str(key, 0, out, false);
650
+ break;
651
+ case T_SYMBOL:
652
+ oj_dump_sym(key, 0, out, false);
653
+ break;
654
+ default:
655
+ /*rb_raise(rb_eTypeError, "In :compat mode all Hash keys must be Strings or Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));*/
656
+ oj_dump_str(rb_funcall(key, oj_to_s_id, 0), 0, out, false);
657
+ break;
658
+ }
659
+ if (!out->opts->dump_opts.use) {
660
+ *out->cur++ = ':';
661
+ } else {
662
+ assure_size(out, out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2);
663
+ if (0 < out->opts->dump_opts.before_size) {
664
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
665
+ }
666
+ *out->cur++ = ':';
667
+ if (0 < out->opts->dump_opts.after_size) {
668
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
669
+ }
670
+ }
671
+ oj_dump_compat_val(value, depth, out, true);
672
+ out->depth = depth;
673
+ *out->cur++ = ',';
674
+
675
+ return ST_CONTINUE;
676
+ }
677
+
678
+ static void
679
+ dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
680
+ int cnt;
681
+ long id = oj_check_circular(obj, out);
682
+
683
+ if (0 > id) {
684
+ raise_json_err("Too deeply nested", "NestingError");
685
+ return;
686
+ }
687
+ if (as_ok && !oj_use_hash_alt && rb_obj_class(obj) != rb_cHash && rb_respond_to(obj, oj_to_json_id)) {
688
+ dump_to_json(obj, out);
689
+ return;
690
+ }
691
+ cnt = (int)RHASH_SIZE(obj);
692
+ assure_size(out, 2);
693
+ if (0 == cnt) {
694
+ APPEND_CHARS(out->cur, "{}", 2);
695
+ } else {
696
+ *out->cur++ = '{';
697
+ out->depth = depth + 1;
698
+ rb_hash_foreach(obj, hash_cb, (VALUE)out);
699
+ if (',' == *(out->cur - 1)) {
700
+ out->cur--; // backup to overwrite last comma
701
+ }
702
+ if (!out->opts->dump_opts.use) {
703
+ assure_size(out, depth * out->indent + 2);
704
+ fill_indent(out, depth);
705
+ } else {
706
+ assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
707
+ if (0 < out->opts->dump_opts.hash_size) {
708
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
709
+ }
710
+ if (0 < out->opts->dump_opts.indent_size) {
711
+ int i;
712
+
713
+ for (i = depth; 0 < i; i--) {
714
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
715
+ }
716
+ }
717
+ }
718
+ *out->cur++ = '}';
719
+ }
720
+ *out->cur = '\0';
721
+ }
722
+
723
+ // In compat mode only the first call check for to_json. After that to_s is
724
+ // called.
725
+ static void
726
+ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
727
+ if (oj_code_dump(oj_compat_codes, obj, depth, out)) {
728
+ return;
729
+ }
730
+ if (use_exception_alt && rb_obj_is_kind_of(obj, rb_eException)) {
731
+ exception_alt(obj, depth, out);
732
+ return;
733
+ }
734
+ if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
735
+ oj_dump_raw_json(obj, depth, out);
736
+ return;
737
+ }
738
+ if (as_ok && rb_respond_to(obj, oj_to_json_id)) {
739
+ dump_to_json(obj, out);
740
+ return;
741
+ }
742
+ // Nothing else matched so encode as a JSON object with Ruby obj members
743
+ // as JSON object members.
744
+ oj_dump_obj_to_s(obj, out);
745
+ }
746
+
747
+ static void
748
+ dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
749
+ VALUE clas = rb_obj_class(obj);
750
+
751
+ if (oj_code_dump(oj_compat_codes, obj, depth, out)) {
752
+ return;
753
+ }
754
+ if (rb_cRange == clas) {
755
+ *out->cur++ = '"';
756
+ oj_dump_compat_val(rb_funcall(obj, oj_begin_id, 0), 0, out, false);
757
+ assure_size(out, 3);
758
+ APPEND_CHARS(out->cur, "..", 2);
759
+ if (Qtrue == rb_funcall(obj, oj_exclude_end_id, 0)) {
760
+ *out->cur++ = '.';
761
+ }
762
+ oj_dump_compat_val(rb_funcall(obj, oj_end_id, 0), 0, out, false);
763
+ *out->cur++ = '"';
764
+
765
+ return;
766
+ }
767
+ if (as_ok && rb_respond_to(obj, oj_to_json_id)) {
768
+ dump_to_json(obj, out);
769
+
770
+ return;
771
+ }
772
+ if (use_struct_alt) {
773
+ int d3 = depth + 2;
774
+ size_t size = d3 * out->indent + 2;
775
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
776
+ const char *classname = rb_class2name(rb_obj_class(obj));
777
+ VALUE args[100];
778
+ int cnt;
779
+ int i;
780
+
781
+ if (NULL == classname || '#' == *classname) {
782
+ raise_json_err("Only named structs are supported.", "JSONError");
783
+ }
784
+ #ifdef RSTRUCT_LEN
785
+ #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
786
+ cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
787
+ #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
788
+ cnt = (int)RSTRUCT_LEN(obj);
789
+ #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
790
+ #else
791
+ // This is a bit risky as a struct in C ruby is not the same as a Struct
792
+ // class in interpreted Ruby so length() may not be defined.
793
+ cnt = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0));
794
+ #endif
795
+ if (sizeof(args) / sizeof(*args) <= (size_t)cnt) {
796
+ // TBD allocate and try again
797
+ cnt = 99;
798
+ }
799
+ dump_obj_classname(rb_class2name(rb_obj_class(obj)), depth, out);
800
+
801
+ assure_size(out, size + sep_len + 6);
802
+ *out->cur++ = ',';
803
+ fill_indent(out, d3);
804
+ APPEND_CHARS(out->cur, "\"v\"", 3);
805
+ if (0 < out->opts->dump_opts.before_size) {
806
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
807
+ }
808
+ *out->cur++ = ':';
809
+ if (0 < out->opts->dump_opts.after_size) {
810
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
811
+ }
812
+ for (i = 0; i < cnt; i++) {
813
+ #ifdef RSTRUCT_LEN
814
+ args[i] = RSTRUCT_GET(obj, i);
815
+ #else
816
+ args[i] = rb_struct_aref(obj, INT2FIX(i));
817
+ #endif
818
+ }
819
+ args[cnt] = Qundef;
820
+ dump_values_array(args, depth, out);
821
+ fill_indent(out, depth);
822
+ *out->cur++ = '}';
823
+ *out->cur = '\0';
824
+ } else {
825
+ oj_dump_obj_to_s(obj, out);
826
+ }
827
+ }
828
+
829
+ static void
830
+ dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
831
+ // The json gem uses to_s explicitly. to_s can be overridden while
832
+ // rb_big2str can not so unless overridden by using add_to_json(Integer)
833
+ // this must use to_s to pass the json gem unit tests.
834
+ volatile VALUE rs;
835
+ int cnt;
836
+ bool dump_as_string = false;
837
+
838
+ if (use_bignum_alt) {
839
+ rs = rb_big2str(obj, 10);
840
+ } else {
841
+ rs = rb_funcall(obj, oj_to_s_id, 0);
842
+ }
843
+ rb_check_type(rs, T_STRING);
844
+ cnt = (int)RSTRING_LEN(rs);
845
+
846
+ if (out->opts->int_range_min != 0 || out->opts->int_range_max != 0) {
847
+ dump_as_string = true; // Bignum cannot be inside of Fixnum range
848
+ assure_size(out, cnt + 2);
849
+ *out->cur++ = '"';
850
+ } else {
851
+ assure_size(out, cnt);
852
+ }
853
+ APPEND_CHARS(out->cur, RSTRING_PTR(rs), cnt);
854
+ if (dump_as_string) {
855
+ *out->cur++ = '"';
856
+ }
857
+ *out->cur = '\0';
858
+ }
859
+
860
+ static DumpFunc compat_funcs[] = {
861
+ NULL, // RUBY_T_NONE = 0x00,
862
+ dump_obj, // RUBY_T_OBJECT = 0x01,
863
+ oj_dump_class, // RUBY_T_CLASS = 0x02,
864
+ oj_dump_class, // RUBY_T_MODULE = 0x03,
865
+ dump_float, // RUBY_T_FLOAT = 0x04,
866
+ oj_dump_str, // RUBY_T_STRING = 0x05,
867
+ dump_obj, // RUBY_T_REGEXP = 0x06,
868
+ dump_array, // RUBY_T_ARRAY = 0x07,
869
+ dump_hash, // RUBY_T_HASH = 0x08,
870
+ dump_struct, // RUBY_T_STRUCT = 0x09,
871
+ dump_bignum, // RUBY_T_BIGNUM = 0x0a,
872
+ NULL, // RUBY_T_FILE = 0x0b,
873
+ dump_obj, // RUBY_T_DATA = 0x0c,
874
+ NULL, // RUBY_T_MATCH = 0x0d,
875
+ dump_obj, // RUBY_T_COMPLEX = 0x0e,
876
+ dump_obj, // RUBY_T_RATIONAL = 0x0f,
877
+ NULL, // 0x10
878
+ oj_dump_nil, // RUBY_T_NIL = 0x11,
879
+ oj_dump_true, // RUBY_T_TRUE = 0x12,
880
+ oj_dump_false, // RUBY_T_FALSE = 0x13,
881
+ oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
882
+ oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
883
+ };
884
+
885
+ static void
886
+ set_state_depth(VALUE state, int depth) {
887
+ VALUE json_module = rb_const_get_at(rb_cObject, rb_intern("JSON"));
888
+ VALUE ext = rb_const_get(json_module, rb_intern("Ext"));
889
+ VALUE generator = rb_const_get(ext, rb_intern("Generator"));
890
+ VALUE state_class = rb_const_get(generator, rb_intern("State"));
891
+
892
+ if (state_class == rb_obj_class(state)) {
893
+ rb_funcall(state, rb_intern("depth="), 1, INT2NUM(depth));
894
+ }
895
+ }
896
+
897
+ void
898
+ oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
899
+ int type = rb_type(obj);
900
+
901
+ if (Yes == out->opts->trace) {
902
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
903
+ }
904
+ if (out->opts->dump_opts.max_depth <= depth) {
905
+ // When JSON.dump is called then an ArgumentError is expected and the
906
+ // limit is the depth inclusive. If JSON.generate is called then a
907
+ // NestingError is expected and the limit is inclusive. Worse than
908
+ // that there are unit tests for both.
909
+ if (CALLER_DUMP == out->caller) {
910
+ if (0 < out->argc) {
911
+ set_state_depth(*out->argv, depth);
912
+ }
913
+ rb_raise(rb_eArgError, "Too deeply nested.");
914
+ } else if (out->opts->dump_opts.max_depth < depth) {
915
+ if (0 < out->argc) {
916
+ set_state_depth(*out->argv, depth - 1);
917
+ }
918
+ raise_json_err("Too deeply nested", "NestingError");
919
+ }
920
+ }
921
+ if (0 < type && type <= RUBY_T_FIXNUM) {
922
+ DumpFunc f = compat_funcs[type];
923
+
924
+ if (NULL != f) {
925
+ f(obj, depth, out, as_ok);
926
+ if (Yes == out->opts->trace) {
927
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
928
+ }
929
+ return;
930
+ }
931
+ }
932
+ oj_dump_nil(Qnil, depth, out, false);
933
+ if (Yes == out->opts->trace) {
934
+ oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
935
+ }
936
+ }