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