oj 2.18.4 → 2.18.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/oj/dump.c +23 -23
- data/lib/oj/version.rb +1 -1
- data/test/curl/curl_oj.rb +46 -0
- data/test/curl/get_oj.rb +24 -0
- data/test/curl/just_curl.rb +31 -0
- data/test/curl/just_oj.rb +51 -0
- data/test/foo.rb +19 -2
- metadata +63 -66
- data/ext/oj/dump_custom.c +0 -759
- data/test/mem.rb +0 -20
- data/test/omit.rb +0 -20
- data/test/rails_datetime_test.rb +0 -24
- data/test/test_custom.rb +0 -399
- data/test/x_test.rb +0 -185
data/ext/oj/dump_custom.c
DELETED
@@ -1,759 +0,0 @@
|
|
1
|
-
/* dump_object.c
|
2
|
-
* Copyright (c) 2012, 2017, Peter Ohler
|
3
|
-
* All rights reserved.
|
4
|
-
*/
|
5
|
-
|
6
|
-
#include "dump.h"
|
7
|
-
|
8
|
-
static void
|
9
|
-
dump_time(VALUE obj, Out out) {
|
10
|
-
switch (out->opts->time_format) {
|
11
|
-
case RubyTime: oj_dump_obj_to_s(obj, out); break;
|
12
|
-
case XmlTime: oj_dump_xml_time(obj, out); break;
|
13
|
-
case UnixZTime: oj_dump_time(obj, out, 1); break;
|
14
|
-
case UnixTime:
|
15
|
-
default: oj_dump_time(obj, out, 0); break;
|
16
|
-
}
|
17
|
-
}
|
18
|
-
|
19
|
-
static int
|
20
|
-
hash_cb(VALUE key, VALUE value, Out out) {
|
21
|
-
int depth = out->depth;
|
22
|
-
|
23
|
-
if (out->omit_nil && Qnil == value) {
|
24
|
-
return ST_CONTINUE;
|
25
|
-
}
|
26
|
-
if (!out->opts->dump_opts.use) {
|
27
|
-
assure_size(out, depth * out->indent + 1);
|
28
|
-
fill_indent(out, depth);
|
29
|
-
} else {
|
30
|
-
assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
|
31
|
-
if (0 < out->opts->dump_opts.hash_size) {
|
32
|
-
strcpy(out->cur, out->opts->dump_opts.hash_nl);
|
33
|
-
out->cur += out->opts->dump_opts.hash_size;
|
34
|
-
}
|
35
|
-
if (0 < out->opts->dump_opts.indent_size) {
|
36
|
-
int i;
|
37
|
-
for (i = depth; 0 < i; i--) {
|
38
|
-
strcpy(out->cur, out->opts->dump_opts.indent_str);
|
39
|
-
out->cur += out->opts->dump_opts.indent_size;
|
40
|
-
}
|
41
|
-
}
|
42
|
-
}
|
43
|
-
switch (rb_type(key)) {
|
44
|
-
case T_STRING:
|
45
|
-
oj_dump_str(key, 0, out, false);
|
46
|
-
break;
|
47
|
-
case T_SYMBOL:
|
48
|
-
oj_dump_sym(key, 0, out, false);
|
49
|
-
break;
|
50
|
-
default:
|
51
|
-
/*rb_raise(rb_eTypeError, "In :compat mode all Hash keys must be Strings or Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));*/
|
52
|
-
oj_dump_str(rb_funcall(key, oj_to_s_id, 0), 0, out, false);
|
53
|
-
break;
|
54
|
-
}
|
55
|
-
if (!out->opts->dump_opts.use) {
|
56
|
-
*out->cur++ = ':';
|
57
|
-
} else {
|
58
|
-
assure_size(out, out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2);
|
59
|
-
if (0 < out->opts->dump_opts.before_size) {
|
60
|
-
strcpy(out->cur, out->opts->dump_opts.before_sep);
|
61
|
-
out->cur += out->opts->dump_opts.before_size;
|
62
|
-
}
|
63
|
-
*out->cur++ = ':';
|
64
|
-
if (0 < out->opts->dump_opts.after_size) {
|
65
|
-
strcpy(out->cur, out->opts->dump_opts.after_sep);
|
66
|
-
out->cur += out->opts->dump_opts.after_size;
|
67
|
-
}
|
68
|
-
}
|
69
|
-
oj_dump_compat_val(value, depth, out, true);
|
70
|
-
out->depth = depth;
|
71
|
-
*out->cur++ = ',';
|
72
|
-
|
73
|
-
return ST_CONTINUE;
|
74
|
-
}
|
75
|
-
|
76
|
-
static void
|
77
|
-
dump_hash_class(VALUE obj, VALUE clas, int depth, Out out) {
|
78
|
-
int cnt;
|
79
|
-
size_t size;
|
80
|
-
|
81
|
-
cnt = (int)RHASH_SIZE(obj);
|
82
|
-
size = depth * out->indent + 2;
|
83
|
-
assure_size(out, 2);
|
84
|
-
if (0 == cnt) {
|
85
|
-
*out->cur++ = '{';
|
86
|
-
*out->cur++ = '}';
|
87
|
-
} else {
|
88
|
-
long id = oj_check_circular(obj, out);
|
89
|
-
|
90
|
-
if (0 > id) {
|
91
|
-
return;
|
92
|
-
}
|
93
|
-
*out->cur++ = '{';
|
94
|
-
if (0 < id) {
|
95
|
-
assure_size(out, size + 16);
|
96
|
-
fill_indent(out, depth + 1);
|
97
|
-
*out->cur++ = '"';
|
98
|
-
*out->cur++ = '^';
|
99
|
-
*out->cur++ = 'i';
|
100
|
-
*out->cur++ = '"';
|
101
|
-
*out->cur++ = ':';
|
102
|
-
dump_ulong(id, out);
|
103
|
-
*out->cur++ = ',';
|
104
|
-
}
|
105
|
-
out->depth = depth + 1;
|
106
|
-
rb_hash_foreach(obj, hash_cb, (VALUE)out);
|
107
|
-
if (',' == *(out->cur - 1)) {
|
108
|
-
out->cur--; // backup to overwrite last comma
|
109
|
-
}
|
110
|
-
if (!out->opts->dump_opts.use) {
|
111
|
-
assure_size(out, size);
|
112
|
-
fill_indent(out, depth);
|
113
|
-
} else {
|
114
|
-
size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
|
115
|
-
assure_size(out, size);
|
116
|
-
if (0 < out->opts->dump_opts.hash_size) {
|
117
|
-
strcpy(out->cur, out->opts->dump_opts.hash_nl);
|
118
|
-
out->cur += out->opts->dump_opts.hash_size;
|
119
|
-
}
|
120
|
-
if (0 < out->opts->dump_opts.indent_size) {
|
121
|
-
int i;
|
122
|
-
|
123
|
-
for (i = depth; 0 < i; i--) {
|
124
|
-
strcpy(out->cur, out->opts->dump_opts.indent_str);
|
125
|
-
out->cur += out->opts->dump_opts.indent_size;
|
126
|
-
}
|
127
|
-
}
|
128
|
-
}
|
129
|
-
*out->cur++ = '}';
|
130
|
-
}
|
131
|
-
*out->cur = '\0';
|
132
|
-
}
|
133
|
-
|
134
|
-
static void
|
135
|
-
dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
136
|
-
dump_hash_class(obj, rb_obj_class(obj), depth, out);
|
137
|
-
}
|
138
|
-
|
139
|
-
#if HAS_IVAR_HELPERS
|
140
|
-
static int
|
141
|
-
dump_attr_cb(ID key, VALUE value, Out out) {
|
142
|
-
int depth = out->depth;
|
143
|
-
size_t size = depth * out->indent + 1;
|
144
|
-
const char *attr = rb_id2name(key);
|
145
|
-
|
146
|
-
if (out->omit_nil && Qnil == value) {
|
147
|
-
return ST_CONTINUE;
|
148
|
-
}
|
149
|
-
#if HAS_EXCEPTION_MAGIC
|
150
|
-
if (0 == strcmp("bt", attr) || 0 == strcmp("mesg", attr)) {
|
151
|
-
return ST_CONTINUE;
|
152
|
-
}
|
153
|
-
#endif
|
154
|
-
assure_size(out, size);
|
155
|
-
fill_indent(out, depth);
|
156
|
-
if ('@' == *attr) {
|
157
|
-
attr++;
|
158
|
-
oj_dump_cstr(attr, strlen(attr), 0, 0, out);
|
159
|
-
} else {
|
160
|
-
char buf[32];
|
161
|
-
|
162
|
-
*buf = '~';
|
163
|
-
strncpy(buf + 1, attr, sizeof(buf) - 2);
|
164
|
-
buf[sizeof(buf) - 1] = '\0';
|
165
|
-
oj_dump_cstr(buf, strlen(buf), 0, 0, out);
|
166
|
-
}
|
167
|
-
*out->cur++ = ':';
|
168
|
-
oj_dump_comp_val(value, depth, out, 0, 0, true);
|
169
|
-
out->depth = depth;
|
170
|
-
*out->cur++ = ',';
|
171
|
-
|
172
|
-
return ST_CONTINUE;
|
173
|
-
}
|
174
|
-
#endif
|
175
|
-
|
176
|
-
static void
|
177
|
-
dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out) {
|
178
|
-
size_t size = 0;
|
179
|
-
int d2 = depth + 1;
|
180
|
-
int cnt;
|
181
|
-
|
182
|
-
assure_size(out, 2);
|
183
|
-
*out->cur++ = '{';
|
184
|
-
{
|
185
|
-
#if HAS_IVAR_HELPERS
|
186
|
-
cnt = (int)rb_ivar_count(obj);
|
187
|
-
#else
|
188
|
-
volatile VALUE vars = rb_funcall2(obj, oj_instance_variables_id, 0, 0);
|
189
|
-
VALUE *np = RARRAY_PTR(vars);
|
190
|
-
ID vid;
|
191
|
-
const char *attr;
|
192
|
-
int i;
|
193
|
-
int first = 1;
|
194
|
-
|
195
|
-
cnt = (int)RARRAY_LEN(vars);
|
196
|
-
#endif
|
197
|
-
if (Qundef != clas && 0 < cnt) {
|
198
|
-
*out->cur++ = ',';
|
199
|
-
}
|
200
|
-
if (0 == cnt && Qundef == clas) {
|
201
|
-
// Might be something special like an Enumerable.
|
202
|
-
if (Qtrue == rb_obj_is_kind_of(obj, oj_enumerable_class)) {
|
203
|
-
out->cur--;
|
204
|
-
oj_dump_compat_val(rb_funcall(obj, rb_intern("entries"), 0), depth, out, false);
|
205
|
-
return;
|
206
|
-
}
|
207
|
-
}
|
208
|
-
out->depth = depth + 1;
|
209
|
-
#if HAS_IVAR_HELPERS
|
210
|
-
rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
|
211
|
-
if (',' == *(out->cur - 1)) {
|
212
|
-
out->cur--; // backup to overwrite last comma
|
213
|
-
}
|
214
|
-
#else
|
215
|
-
size = d2 * out->indent + 1;
|
216
|
-
for (i = cnt; 0 < i; i--, np++) {
|
217
|
-
VALUE value;
|
218
|
-
|
219
|
-
vid = rb_to_id(*np);
|
220
|
-
attr = rb_id2name(vid);
|
221
|
-
value = rb_ivar_get(obj, vid);
|
222
|
-
if (out->omit_nil && Qnil == value) {
|
223
|
-
continue;
|
224
|
-
}
|
225
|
-
if (first) {
|
226
|
-
first = 0;
|
227
|
-
} else {
|
228
|
-
*out->cur++ = ',';
|
229
|
-
}
|
230
|
-
assure_size(out, size);
|
231
|
-
fill_indent(out, d2);
|
232
|
-
if ('@' == *attr) {
|
233
|
-
attr++;
|
234
|
-
oj_dump_cstr(attr, strlen(attr), 0, 0, out);
|
235
|
-
} else {
|
236
|
-
char buf[32];
|
237
|
-
|
238
|
-
*buf = '~';
|
239
|
-
strncpy(buf + 1, attr, sizeof(buf) - 2);
|
240
|
-
buf[sizeof(buf) - 1] = '\0';
|
241
|
-
oj_dump_cstr(buf, strlen(attr) + 1, 0, 0, out);
|
242
|
-
}
|
243
|
-
*out->cur++ = ':';
|
244
|
-
oj_dump_compat_val(value, d2, out, 0, 0, true);
|
245
|
-
assure_size(out, 2);
|
246
|
-
}
|
247
|
-
#endif
|
248
|
-
#if HAS_EXCEPTION_MAGIC
|
249
|
-
if (rb_obj_is_kind_of(obj, rb_eException)) {
|
250
|
-
volatile VALUE rv;
|
251
|
-
|
252
|
-
if (',' != *(out->cur - 1)) {
|
253
|
-
*out->cur++ = ',';
|
254
|
-
}
|
255
|
-
// message
|
256
|
-
assure_size(out, 2);
|
257
|
-
fill_indent(out, d2);
|
258
|
-
oj_dump_cstr("~mesg", 5, 0, 0, out);
|
259
|
-
*out->cur++ = ':';
|
260
|
-
rv = rb_funcall2(obj, rb_intern("message"), 0, 0);
|
261
|
-
oj_dump_compat_val(rv, d2, out, true);
|
262
|
-
assure_size(out, size + 2);
|
263
|
-
*out->cur++ = ',';
|
264
|
-
// backtrace
|
265
|
-
fill_indent(out, d2);
|
266
|
-
oj_dump_cstr("~bt", 3, 0, 0, out);
|
267
|
-
*out->cur++ = ':';
|
268
|
-
rv = rb_funcall2(obj, rb_intern("backtrace"), 0, 0);
|
269
|
-
oj_dump_compat_val(rv, d2, out, true);
|
270
|
-
assure_size(out, 2);
|
271
|
-
}
|
272
|
-
#endif
|
273
|
-
out->depth = depth;
|
274
|
-
}
|
275
|
-
fill_indent(out, depth);
|
276
|
-
*out->cur++ = '}';
|
277
|
-
*out->cur = '\0';
|
278
|
-
}
|
279
|
-
|
280
|
-
static void
|
281
|
-
dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
282
|
-
if (as_ok && Yes == out->opts->to_json && rb_respond_to(obj, oj_to_hash_id)) {
|
283
|
-
volatile VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
|
284
|
-
|
285
|
-
if (T_HASH != rb_type(h)) {
|
286
|
-
// It seems that ActiveRecord implemented to_hash so that it returns
|
287
|
-
// an Array and not a Hash. To get around that any value returned
|
288
|
-
// will be dumped.
|
289
|
-
|
290
|
-
//rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
|
291
|
-
oj_dump_compat_val(h, depth, out, false);
|
292
|
-
} else {
|
293
|
-
dump_hash_class(h, Qundef, depth, out);
|
294
|
-
}
|
295
|
-
} else if (as_ok && Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
|
296
|
-
volatile VALUE aj;
|
297
|
-
|
298
|
-
#if HAS_METHOD_ARITY
|
299
|
-
// Some classes elect to not take an options argument so check the arity
|
300
|
-
// of as_json.
|
301
|
-
switch (rb_obj_method_arity(obj, oj_as_json_id)) {
|
302
|
-
case 0:
|
303
|
-
aj = rb_funcall2(obj, oj_as_json_id, 0, 0);
|
304
|
-
break;
|
305
|
-
case 1:
|
306
|
-
if (1 <= out->argc) {
|
307
|
-
aj = rb_funcall2(obj, oj_as_json_id, 1, (VALUE*)out->argv);
|
308
|
-
} else {
|
309
|
-
VALUE nothing [1];
|
310
|
-
|
311
|
-
nothing[0] = Qnil;
|
312
|
-
aj = rb_funcall2(obj, oj_as_json_id, 1, nothing);
|
313
|
-
}
|
314
|
-
break;
|
315
|
-
default:
|
316
|
-
aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
|
317
|
-
break;
|
318
|
-
}
|
319
|
-
#else
|
320
|
-
aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
|
321
|
-
#endif
|
322
|
-
// Catch the obvious brain damaged recursive dumping.
|
323
|
-
if (aj == obj) {
|
324
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
325
|
-
|
326
|
-
oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), false, false, out);
|
327
|
-
} else {
|
328
|
-
oj_dump_compat_val(aj, depth, out, false);
|
329
|
-
}
|
330
|
-
} else if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) {
|
331
|
-
volatile VALUE rs;
|
332
|
-
const char *s;
|
333
|
-
int len;
|
334
|
-
|
335
|
-
rs = rb_funcall(obj, oj_to_json_id, 0);
|
336
|
-
s = rb_string_value_ptr((VALUE*)&rs);
|
337
|
-
len = (int)RSTRING_LEN(rs);
|
338
|
-
|
339
|
-
assure_size(out, len + 1);
|
340
|
-
memcpy(out->cur, s, len);
|
341
|
-
out->cur += len;
|
342
|
-
*out->cur = '\0';
|
343
|
-
} else {
|
344
|
-
VALUE clas = rb_obj_class(obj);
|
345
|
-
|
346
|
-
if (oj_bigdecimal_class == clas) {
|
347
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
348
|
-
const char *str = rb_string_value_ptr((VALUE*)&rstr);
|
349
|
-
int len = RSTRING_LEN(rstr);
|
350
|
-
|
351
|
-
if (Yes == out->opts->bigdec_as_num) {
|
352
|
-
oj_dump_raw(str, len, out);
|
353
|
-
} else if (0 == strcasecmp("Infinity", str)) {
|
354
|
-
str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
|
355
|
-
oj_dump_raw(str, len, out);
|
356
|
-
} else if (0 == strcasecmp("-Infinity", str)) {
|
357
|
-
str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
|
358
|
-
oj_dump_raw(str, len, out);
|
359
|
-
} else {
|
360
|
-
oj_dump_cstr(str, len, 0, 0, out);
|
361
|
-
}
|
362
|
-
#if (defined T_RATIONAL && defined RRATIONAL)
|
363
|
-
} else if (oj_datetime_class == clas || oj_date_class == clas || rb_cRational == clas) {
|
364
|
-
#else
|
365
|
-
} else if (oj_datetime_class == clas || oj_date_class == clas) {
|
366
|
-
#endif
|
367
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
368
|
-
|
369
|
-
oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
|
370
|
-
} else {
|
371
|
-
dump_obj_attrs(obj, Qundef, 0, depth, out);
|
372
|
-
}
|
373
|
-
}
|
374
|
-
*out->cur = '\0';
|
375
|
-
}
|
376
|
-
|
377
|
-
static void
|
378
|
-
dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
379
|
-
size_t size;
|
380
|
-
int i, cnt;
|
381
|
-
int d2 = depth + 1;
|
382
|
-
long id = oj_check_circular(a, out);
|
383
|
-
|
384
|
-
if (id < 0) {
|
385
|
-
return;
|
386
|
-
}
|
387
|
-
cnt = (int)RARRAY_LEN(a);
|
388
|
-
*out->cur++ = '[';
|
389
|
-
if (0 < id) {
|
390
|
-
oj_dump_nil(Qnil, 0, out, false);
|
391
|
-
}
|
392
|
-
size = 2;
|
393
|
-
assure_size(out, size);
|
394
|
-
if (0 == cnt) {
|
395
|
-
*out->cur++ = ']';
|
396
|
-
} else {
|
397
|
-
if (0 < id) {
|
398
|
-
*out->cur++ = ',';
|
399
|
-
}
|
400
|
-
if (out->opts->dump_opts.use) {
|
401
|
-
size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
|
402
|
-
} else {
|
403
|
-
size = d2 * out->indent + 2;
|
404
|
-
}
|
405
|
-
cnt--;
|
406
|
-
for (i = 0; i <= cnt; i++) {
|
407
|
-
assure_size(out, size);
|
408
|
-
if (out->opts->dump_opts.use) {
|
409
|
-
if (0 < out->opts->dump_opts.array_size) {
|
410
|
-
strcpy(out->cur, out->opts->dump_opts.array_nl);
|
411
|
-
out->cur += out->opts->dump_opts.array_size;
|
412
|
-
}
|
413
|
-
if (0 < out->opts->dump_opts.indent_size) {
|
414
|
-
int i;
|
415
|
-
for (i = d2; 0 < i; i--) {
|
416
|
-
strcpy(out->cur, out->opts->dump_opts.indent_str);
|
417
|
-
out->cur += out->opts->dump_opts.indent_size;
|
418
|
-
}
|
419
|
-
}
|
420
|
-
} else {
|
421
|
-
fill_indent(out, d2);
|
422
|
-
}
|
423
|
-
oj_dump_comp_val(rb_ary_entry(a, i), d2, out, 0, 0, true);
|
424
|
-
if (i < cnt) {
|
425
|
-
*out->cur++ = ',';
|
426
|
-
}
|
427
|
-
}
|
428
|
-
size = depth * out->indent + 1;
|
429
|
-
assure_size(out, size);
|
430
|
-
if (out->opts->dump_opts.use) {
|
431
|
-
//printf("*** d2: %u indent: %u '%s'\n", d2, out->opts->dump_opts->indent_size, out->opts->dump_opts->indent);
|
432
|
-
if (0 < out->opts->dump_opts.array_size) {
|
433
|
-
strcpy(out->cur, out->opts->dump_opts.array_nl);
|
434
|
-
out->cur += out->opts->dump_opts.array_size;
|
435
|
-
}
|
436
|
-
if (0 < out->opts->dump_opts.indent_size) {
|
437
|
-
int i;
|
438
|
-
|
439
|
-
for (i = depth; 0 < i; i--) {
|
440
|
-
strcpy(out->cur, out->opts->dump_opts.indent_str);
|
441
|
-
out->cur += out->opts->dump_opts.indent_size;
|
442
|
-
}
|
443
|
-
}
|
444
|
-
} else {
|
445
|
-
fill_indent(out, depth);
|
446
|
-
}
|
447
|
-
*out->cur++ = ']';
|
448
|
-
}
|
449
|
-
*out->cur = '\0';
|
450
|
-
}
|
451
|
-
|
452
|
-
static void
|
453
|
-
dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
454
|
-
if (as_ok && Yes == out->opts->to_json && rb_respond_to(obj, oj_to_hash_id)) {
|
455
|
-
volatile VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
|
456
|
-
|
457
|
-
if (T_HASH != rb_type(h)) {
|
458
|
-
// It seems that ActiveRecord implemented to_hash so that it
|
459
|
-
// returns an Array and not a Hash. To get around that any value
|
460
|
-
// returned will be dumped.
|
461
|
-
|
462
|
-
//rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
|
463
|
-
oj_dump_comp_val(h, depth, out, 0, 0, false);
|
464
|
-
}
|
465
|
-
dump_hash_class(h, Qundef, depth, out);
|
466
|
-
} else if (as_ok && Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
|
467
|
-
volatile VALUE aj;
|
468
|
-
|
469
|
-
#if HAS_METHOD_ARITY
|
470
|
-
// Some classes elect to not take an options argument so check the arity
|
471
|
-
// of as_json.
|
472
|
-
switch (rb_obj_method_arity(obj, oj_as_json_id)) {
|
473
|
-
case 0:
|
474
|
-
aj = rb_funcall2(obj, oj_as_json_id, 0, 0);
|
475
|
-
break;
|
476
|
-
case 1:
|
477
|
-
if (1 <= out->argc) {
|
478
|
-
aj = rb_funcall2(obj, oj_as_json_id, 1, out->argv);
|
479
|
-
} else {
|
480
|
-
VALUE nothing [1];
|
481
|
-
|
482
|
-
nothing[0] = Qnil;
|
483
|
-
aj = rb_funcall2(obj, oj_as_json_id, 1, nothing);
|
484
|
-
}
|
485
|
-
break;
|
486
|
-
default:
|
487
|
-
aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
|
488
|
-
break;
|
489
|
-
}
|
490
|
-
#else
|
491
|
-
aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
|
492
|
-
#endif
|
493
|
-
// Catch the obvious brain damaged recursive dumping.
|
494
|
-
if (aj == obj) {
|
495
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
496
|
-
|
497
|
-
oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), false, false, out);
|
498
|
-
} else {
|
499
|
-
oj_dump_compat_val(aj, depth, out, false);
|
500
|
-
}
|
501
|
-
} else if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) {
|
502
|
-
volatile VALUE rs = rb_funcall(obj, oj_to_json_id, 0);
|
503
|
-
const char *s;
|
504
|
-
int len;
|
505
|
-
|
506
|
-
s = rb_string_value_ptr((VALUE*)&rs);
|
507
|
-
len = (int)RSTRING_LEN(rs);
|
508
|
-
assure_size(out, len);
|
509
|
-
memcpy(out->cur, s, len);
|
510
|
-
out->cur += len;
|
511
|
-
} else {
|
512
|
-
VALUE clas = rb_obj_class(obj);
|
513
|
-
VALUE ma = Qnil;
|
514
|
-
VALUE v;
|
515
|
-
char num_id[32];
|
516
|
-
int i;
|
517
|
-
int d2 = depth + 1;
|
518
|
-
int d3 = d2 + 1;
|
519
|
-
size_t size = d2 * out->indent + d3 * out->indent + 3;
|
520
|
-
const char *name;
|
521
|
-
int cnt;
|
522
|
-
size_t len;
|
523
|
-
|
524
|
-
assure_size(out, size);
|
525
|
-
if (clas == rb_cRange) {
|
526
|
-
*out->cur++ = '"';
|
527
|
-
oj_dump_comp_val(rb_funcall(obj, oj_begin_id, 0), d3, out, 0, 0, false);
|
528
|
-
assure_size(out, 3);
|
529
|
-
*out->cur++ = '.';
|
530
|
-
*out->cur++ = '.';
|
531
|
-
if (Qtrue == rb_funcall(obj, oj_exclude_end_id, 0)) {
|
532
|
-
*out->cur++ = '.';
|
533
|
-
}
|
534
|
-
oj_dump_comp_val(rb_funcall(obj, oj_end_id, 0), d3, out, 0, 0, false);
|
535
|
-
*out->cur++ = '"';
|
536
|
-
|
537
|
-
return;
|
538
|
-
}
|
539
|
-
*out->cur++ = '{';
|
540
|
-
fill_indent(out, d2);
|
541
|
-
size = d3 * out->indent + 2;
|
542
|
-
#if HAS_STRUCT_MEMBERS
|
543
|
-
ma = rb_struct_s_members(clas);
|
544
|
-
#endif
|
545
|
-
|
546
|
-
#ifdef RSTRUCT_LEN
|
547
|
-
#if UNIFY_FIXNUM_AND_BIGNUM
|
548
|
-
cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
|
549
|
-
#else // UNIFY_FIXNUM_AND_INTEGER
|
550
|
-
cnt = (int)RSTRUCT_LEN(obj);
|
551
|
-
#endif // UNIFY_FIXNUM_AND_INTEGER
|
552
|
-
#else
|
553
|
-
// This is a bit risky as a struct in C ruby is not the same as a Struct
|
554
|
-
// class in interpreted Ruby so length() may not be defined.
|
555
|
-
cnt = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0));
|
556
|
-
#endif
|
557
|
-
for (i = 0; i < cnt; i++) {
|
558
|
-
#ifdef RSTRUCT_LEN
|
559
|
-
v = RSTRUCT_GET(obj, i);
|
560
|
-
#else
|
561
|
-
v = rb_struct_aref(obj, INT2FIX(i));
|
562
|
-
#endif
|
563
|
-
if (ma != Qnil) {
|
564
|
-
name = rb_id2name(SYM2ID(rb_ary_entry(ma, i)));
|
565
|
-
len = strlen(name);
|
566
|
-
} else {
|
567
|
-
len = snprintf(num_id, sizeof(num_id), "%d", i);
|
568
|
-
name = num_id;
|
569
|
-
}
|
570
|
-
assure_size(out, size + len + 3);
|
571
|
-
fill_indent(out, d3);
|
572
|
-
*out->cur++ = '"';
|
573
|
-
memcpy(out->cur, name, len);
|
574
|
-
out->cur += len;
|
575
|
-
*out->cur++ = '"';
|
576
|
-
*out->cur++ = ':';
|
577
|
-
oj_dump_comp_val(v, d3, out, 0, 0, true);
|
578
|
-
*out->cur++ = ',';
|
579
|
-
}
|
580
|
-
out->cur--;
|
581
|
-
*out->cur++ = '}';
|
582
|
-
*out->cur = '\0';
|
583
|
-
}
|
584
|
-
}
|
585
|
-
|
586
|
-
static void
|
587
|
-
dump_data(VALUE obj, int depth, Out out, bool as_ok) {
|
588
|
-
VALUE clas = rb_obj_class(obj);
|
589
|
-
|
590
|
-
if (as_ok && Yes == out->opts->to_json && rb_respond_to(obj, oj_to_hash_id)) {
|
591
|
-
volatile VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
|
592
|
-
|
593
|
-
if (T_HASH != rb_type(h)) {
|
594
|
-
// It seems that ActiveRecord implemented to_hash so that it returns
|
595
|
-
// an Array and not a Hash. To get around that any value returned
|
596
|
-
// will be dumped.
|
597
|
-
|
598
|
-
//rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
|
599
|
-
oj_dump_compat_val(h, depth, out, false);
|
600
|
-
}
|
601
|
-
dump_hash_class(h, Qundef, depth, out);
|
602
|
-
} else if (Yes == out->opts->bigdec_as_num && oj_bigdecimal_class == clas) {
|
603
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
604
|
-
const char *str = rb_string_value_ptr((VALUE*)&rstr);
|
605
|
-
int len = RSTRING_LEN(rstr);
|
606
|
-
|
607
|
-
if (0 == strcasecmp("Infinity", str)) {
|
608
|
-
str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
|
609
|
-
oj_dump_raw(str, len, out);
|
610
|
-
} else if (0 == strcasecmp("-Infinity", str)) {
|
611
|
-
str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
|
612
|
-
oj_dump_raw(str, len, out);
|
613
|
-
} else {
|
614
|
-
oj_dump_raw(str, len, out);
|
615
|
-
}
|
616
|
-
} else if (as_ok && Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
|
617
|
-
volatile VALUE aj;
|
618
|
-
|
619
|
-
#if HAS_METHOD_ARITY
|
620
|
-
// Some classes elect to not take an options argument so check the arity
|
621
|
-
// of as_json.
|
622
|
-
switch (rb_obj_method_arity(obj, oj_as_json_id)) {
|
623
|
-
case 0:
|
624
|
-
aj = rb_funcall2(obj, oj_as_json_id, 0, 0);
|
625
|
-
break;
|
626
|
-
case 1:
|
627
|
-
if (1 <= out->argc) {
|
628
|
-
aj = rb_funcall2(obj, oj_as_json_id, 1, out->argv);
|
629
|
-
} else {
|
630
|
-
VALUE nothing [1];
|
631
|
-
|
632
|
-
nothing[0] = Qnil;
|
633
|
-
aj = rb_funcall2(obj, oj_as_json_id, 1, nothing);
|
634
|
-
}
|
635
|
-
break;
|
636
|
-
default:
|
637
|
-
aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
|
638
|
-
break;
|
639
|
-
}
|
640
|
-
#else
|
641
|
-
aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
|
642
|
-
#endif
|
643
|
-
// Catch the obvious brain damaged recursive dumping.
|
644
|
-
if (aj == obj) {
|
645
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
646
|
-
|
647
|
-
oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
|
648
|
-
} else {
|
649
|
-
oj_dump_comp_val(aj, depth, out, 0, 0, false);
|
650
|
-
}
|
651
|
-
} else if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) {
|
652
|
-
volatile VALUE rs;
|
653
|
-
const char *s;
|
654
|
-
int len;
|
655
|
-
|
656
|
-
rs = rb_funcall(obj, oj_to_json_id, 0);
|
657
|
-
s = rb_string_value_ptr((VALUE*)&rs);
|
658
|
-
len = (int)RSTRING_LEN(rs);
|
659
|
-
|
660
|
-
assure_size(out, len + 1);
|
661
|
-
memcpy(out->cur, s, len);
|
662
|
-
out->cur += len;
|
663
|
-
*out->cur = '\0';
|
664
|
-
} else {
|
665
|
-
if (rb_cTime == clas) {
|
666
|
-
dump_time(obj, out);
|
667
|
-
} else if (oj_bigdecimal_class == clas) {
|
668
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
669
|
-
const char *str = rb_string_value_ptr((VALUE*)&rstr);
|
670
|
-
int len = RSTRING_LEN(rstr);
|
671
|
-
|
672
|
-
if (0 == strcasecmp("Infinity", str)) {
|
673
|
-
str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
|
674
|
-
oj_dump_raw(str, len, out);
|
675
|
-
} else if (0 == strcasecmp("-Infinity", str)) {
|
676
|
-
str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
|
677
|
-
oj_dump_raw(str, len, out);
|
678
|
-
} else {
|
679
|
-
oj_dump_cstr(str, len, 0, 0, out);
|
680
|
-
}
|
681
|
-
} else if (oj_datetime_class == clas) {
|
682
|
-
volatile VALUE rstr;
|
683
|
-
|
684
|
-
switch (out->opts->time_format) {
|
685
|
-
case XmlTime:
|
686
|
-
rstr = rb_funcall(obj, rb_intern("xmlschema"), 1, INT2FIX(out->opts->sec_prec));
|
687
|
-
break;
|
688
|
-
case UnixZTime:
|
689
|
-
case UnixTime:
|
690
|
-
case RubyTime:
|
691
|
-
default:
|
692
|
-
rstr = rb_funcall(obj, oj_to_s_id, 0);
|
693
|
-
}
|
694
|
-
oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
|
695
|
-
} else {
|
696
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
697
|
-
|
698
|
-
oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
|
699
|
-
}
|
700
|
-
}
|
701
|
-
}
|
702
|
-
|
703
|
-
static void
|
704
|
-
dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
|
705
|
-
oj_dump_obj_to_s(obj, out);
|
706
|
-
}
|
707
|
-
|
708
|
-
static void
|
709
|
-
dump_complex(VALUE obj, int depth, Out out, bool as_ok) {
|
710
|
-
oj_dump_obj_to_s(obj, out);
|
711
|
-
}
|
712
|
-
|
713
|
-
static void
|
714
|
-
dump_rational(VALUE obj, int depth, Out out, bool as_ok) {
|
715
|
-
oj_dump_obj_to_s(obj, out);
|
716
|
-
}
|
717
|
-
|
718
|
-
static DumpFunc custom_funcs[] = {
|
719
|
-
NULL, // RUBY_T_NONE = 0x00,
|
720
|
-
dump_obj, // RUBY_T_OBJECT = 0x01,
|
721
|
-
oj_dump_class, // RUBY_T_CLASS = 0x02,
|
722
|
-
oj_dump_class, // RUBY_T_MODULE = 0x03,
|
723
|
-
oj_dump_float, // RUBY_T_FLOAT = 0x04,
|
724
|
-
oj_dump_str, // RUBY_T_STRING = 0x05,
|
725
|
-
dump_regexp, // RUBY_T_REGEXP = 0x06,
|
726
|
-
dump_array, // RUBY_T_ARRAY = 0x07,
|
727
|
-
dump_hash, // RUBY_T_HASH = 0x08,
|
728
|
-
dump_struct, // RUBY_T_STRUCT = 0x09,
|
729
|
-
oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
|
730
|
-
NULL, // RUBY_T_FILE = 0x0b,
|
731
|
-
dump_data, // RUBY_T_DATA = 0x0c,
|
732
|
-
NULL, // RUBY_T_MATCH = 0x0d,
|
733
|
-
dump_complex, // RUBY_T_COMPLEX = 0x0e,
|
734
|
-
dump_rational, // RUBY_T_RATIONAL = 0x0f,
|
735
|
-
NULL, // 0x10
|
736
|
-
oj_dump_nil, // RUBY_T_NIL = 0x11,
|
737
|
-
oj_dump_true, // RUBY_T_TRUE = 0x12,
|
738
|
-
oj_dump_false, // RUBY_T_FALSE = 0x13,
|
739
|
-
oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
|
740
|
-
oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
|
741
|
-
};
|
742
|
-
|
743
|
-
void
|
744
|
-
oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
|
745
|
-
int type = rb_type(obj);
|
746
|
-
|
747
|
-
if (MAX_DEPTH < depth) {
|
748
|
-
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
749
|
-
}
|
750
|
-
if (0 < type && type <= RUBY_T_FIXNUM) {
|
751
|
-
DumpFunc f = custom_funcs[type];
|
752
|
-
|
753
|
-
if (NULL != f) {
|
754
|
-
f(obj, depth, out, true);
|
755
|
-
return;
|
756
|
-
}
|
757
|
-
}
|
758
|
-
oj_dump_nil(Qnil, depth, out, false);
|
759
|
-
}
|