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