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