oj 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of oj might be problematic. Click here for more details.
- data/README.md +146 -86
- data/ext/oj/cache.c +148 -0
- data/ext/oj/cache.h +44 -0
- data/ext/oj/dump.c +308 -154
- data/ext/oj/load.c +262 -19
- data/ext/oj/oj.c +40 -0
- data/ext/oj/oj.h +10 -0
- data/lib/oj/version.rb +1 -1
- data/test/files.rb +29 -0
- data/test/perf.rb +106 -0
- data/test/perf_obj.rb +124 -0
- data/test/perf_strict.rb +131 -0
- data/test/sample.rb +40 -22
- data/test/sample/change.rb +14 -0
- data/test/sample/dir.rb +19 -0
- data/test/sample/doc.rb +36 -0
- data/test/sample/file.rb +48 -0
- data/test/sample/group.rb +16 -0
- data/test/sample/hasprops.rb +16 -0
- data/test/sample/layer.rb +12 -0
- data/test/sample/line.rb +20 -0
- data/test/sample/oval.rb +10 -0
- data/test/sample/rect.rb +10 -0
- data/test/sample/shape.rb +35 -0
- data/test/sample/text.rb +20 -0
- data/test/sample_json.rb +37 -0
- data/test/tests.rb +359 -0
- metadata +23 -3
- data/test/simple.rb +0 -208
data/ext/oj/dump.c
CHANGED
@@ -69,10 +69,11 @@ typedef struct _Out {
|
|
69
69
|
int indent;
|
70
70
|
int depth; // used by dumpHash
|
71
71
|
Options opts;
|
72
|
-
|
72
|
+
uint32_t hash_cnt;
|
73
73
|
} *Out;
|
74
74
|
|
75
75
|
static void dump_obj_to_json(VALUE obj, Options copts, Out out);
|
76
|
+
static void raise_strict(VALUE obj);
|
76
77
|
static void dump_val(VALUE obj, int depth, Out out);
|
77
78
|
static void dump_nil(Out out);
|
78
79
|
static void dump_true(Out out);
|
@@ -80,23 +81,32 @@ static void dump_false(Out out);
|
|
80
81
|
static void dump_fixnum(VALUE obj, Out out);
|
81
82
|
static void dump_bignum(VALUE obj, Out out);
|
82
83
|
static void dump_float(VALUE obj, Out out);
|
83
|
-
static void dump_cstr(const char *str,
|
84
|
+
static void dump_cstr(const char *str, size_t cnt, int is_sym, Out out);
|
84
85
|
static void dump_hex(u_char c, Out out);
|
85
86
|
static void dump_str(VALUE obj, Out out);
|
86
|
-
static void
|
87
|
-
static void
|
87
|
+
static void dump_sym_comp(VALUE obj, Out out);
|
88
|
+
static void dump_sym_obj(VALUE obj, Out out);
|
89
|
+
static void dump_class_comp(VALUE obj, Out out);
|
90
|
+
static void dump_class_obj(VALUE obj, Out out);
|
88
91
|
static void dump_array(VALUE obj, int depth, Out out);
|
89
|
-
static
|
90
|
-
static
|
91
|
-
static void
|
92
|
+
static int hash_cb_strict(VALUE key, VALUE value, Out out);
|
93
|
+
static int hash_cb_object(VALUE key, VALUE value, Out out);
|
94
|
+
static void dump_hash(VALUE obj, int depth, int mode, Out out);
|
95
|
+
static void dump_time(VALUE obj, Out out);
|
96
|
+
static void dump_data_comp(VALUE obj, Out out);
|
97
|
+
static void dump_data_obj(VALUE obj, Out out);
|
98
|
+
static void dump_obj_comp(VALUE obj, int depth, Out out);
|
99
|
+
static void dump_obj_obj(VALUE obj, int depth, Out out);
|
92
100
|
static int dump_attr_cb(ID key, VALUE value, Out out);
|
93
101
|
static void dump_obj_attrs(VALUE obj, int with_class, int depth, Out out);
|
94
102
|
|
95
103
|
static void grow(Out out, size_t len);
|
96
|
-
static int is_json_friendly(const u_char *str,
|
97
|
-
static
|
104
|
+
static int is_json_friendly(const u_char *str, size_t len);
|
105
|
+
static size_t json_friendly_size(const u_char *str, size_t len);
|
98
106
|
|
99
107
|
|
108
|
+
static const char hex_chars[17] = "0123456789abcdef";
|
109
|
+
|
100
110
|
static char json_friendly_chars[256] = "\
|
101
111
|
uuuuuuuuxxxuxxuuuuuuuuuuuuuuuuuu\
|
102
112
|
ooxooooooooooooxoooooooooooooooo\
|
@@ -108,7 +118,7 @@ uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu\
|
|
108
118
|
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu";
|
109
119
|
|
110
120
|
inline static int
|
111
|
-
is_json_friendly(const u_char *str,
|
121
|
+
is_json_friendly(const u_char *str, size_t len) {
|
112
122
|
for (; 0 < len; str++, len--) {
|
113
123
|
if ('o' != json_friendly_chars[*str]) {
|
114
124
|
return 0;
|
@@ -117,8 +127,8 @@ is_json_friendly(const u_char *str, int len) {
|
|
117
127
|
return 1;
|
118
128
|
}
|
119
129
|
|
120
|
-
inline static
|
121
|
-
json_friendly_size(const u_char *str,
|
130
|
+
inline static size_t
|
131
|
+
json_friendly_size(const u_char *str, size_t len) {
|
122
132
|
int cnt = 0;
|
123
133
|
|
124
134
|
for (; 0 < len; str++, len--) {
|
@@ -165,17 +175,9 @@ inline static void
|
|
165
175
|
dump_hex(u_char c, Out out) {
|
166
176
|
u_char d = (c >> 4) & 0x0F;
|
167
177
|
|
168
|
-
|
169
|
-
*out->cur++ = (d - 10) + 'a';
|
170
|
-
} else {
|
171
|
-
*out->cur++ = d + '0';
|
172
|
-
}
|
178
|
+
*out->cur++ = hex_chars[d];
|
173
179
|
d = c & 0x0F;
|
174
|
-
|
175
|
-
*out->cur++ = (d - 10) + 'a';
|
176
|
-
} else {
|
177
|
-
*out->cur++ = d + '0';
|
178
|
-
}
|
180
|
+
*out->cur++ = hex_chars[d];
|
179
181
|
}
|
180
182
|
|
181
183
|
static void
|
@@ -283,15 +285,18 @@ dump_float(VALUE obj, Out out) {
|
|
283
285
|
}
|
284
286
|
|
285
287
|
static void
|
286
|
-
dump_cstr(const char *str,
|
287
|
-
|
288
|
+
dump_cstr(const char *str, size_t cnt, int is_sym, Out out) {
|
289
|
+
size_t size = json_friendly_size((u_char*)str, cnt);
|
288
290
|
|
289
291
|
if (cnt == size) {
|
290
|
-
cnt += 2;
|
292
|
+
cnt += 2 + is_sym;
|
291
293
|
if (out->end - out->cur <= (long)cnt) {
|
292
294
|
grow(out, cnt);
|
293
295
|
}
|
294
296
|
*out->cur++ = '"';
|
297
|
+
if (is_sym) {
|
298
|
+
*out->cur++ = ':';
|
299
|
+
}
|
295
300
|
for (; '\0' != *str; str++) {
|
296
301
|
*out->cur++ = *str;
|
297
302
|
}
|
@@ -302,6 +307,9 @@ dump_cstr(const char *str, int cnt, Out out) {
|
|
302
307
|
grow(out, size);
|
303
308
|
}
|
304
309
|
*out->cur++ = '"';
|
310
|
+
if (is_sym) {
|
311
|
+
*out->cur++ = ':';
|
312
|
+
}
|
305
313
|
for (; 0 < cnt; cnt--, str++) {
|
306
314
|
switch (json_friendly_chars[(u_char)*str]) {
|
307
315
|
case 'o':
|
@@ -343,48 +351,65 @@ dump_cstr(const char *str, int cnt, Out out) {
|
|
343
351
|
|
344
352
|
static void
|
345
353
|
dump_str(VALUE obj, Out out) {
|
346
|
-
dump_cstr(StringValuePtr(obj),
|
354
|
+
dump_cstr(StringValuePtr(obj), RSTRING_LEN(obj), 0, out);
|
347
355
|
}
|
348
356
|
|
349
357
|
static void
|
350
|
-
|
358
|
+
dump_sym_comp(VALUE obj, Out out) {
|
351
359
|
const char *sym = rb_id2name(SYM2ID(obj));
|
352
360
|
|
353
|
-
dump_cstr(sym,
|
361
|
+
dump_cstr(sym, strlen(sym), 0, out);
|
354
362
|
}
|
355
363
|
|
356
364
|
static void
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
break;
|
365
|
-
case ObjectMode:
|
366
|
-
case CompatMode:
|
367
|
-
default:
|
368
|
-
{
|
369
|
-
const char *s = rb_class2name(obj);
|
370
|
-
size_t len = strlen(s);
|
371
|
-
size_t size = len + 20;
|
372
|
-
|
373
|
-
if (out->end - out->cur <= (long)size) {
|
374
|
-
grow(out, size);
|
375
|
-
}
|
376
|
-
memcpy(out->cur, "{\"*\":\"Class\",\"-\":\"", 18);
|
377
|
-
out->cur += 18;
|
378
|
-
memcpy(out->cur, s, len);
|
379
|
-
out->cur += len;
|
380
|
-
*out->cur++ = '"';
|
381
|
-
*out->cur++ = '}';
|
382
|
-
*out->cur = '\0';
|
383
|
-
break;
|
365
|
+
dump_sym_obj(VALUE obj, Out out) {
|
366
|
+
const char *sym = rb_id2name(SYM2ID(obj));
|
367
|
+
size_t len = strlen(sym);
|
368
|
+
|
369
|
+
if (':' == *sym) {
|
370
|
+
if (out->end - out->cur <= 6) {
|
371
|
+
grow(out, 6);
|
384
372
|
}
|
373
|
+
*out->cur++ = '{';
|
374
|
+
*out->cur++ = '"';
|
375
|
+
*out->cur++ = '^';
|
376
|
+
*out->cur++ = 's';
|
377
|
+
*out->cur++ = '"';
|
378
|
+
*out->cur++ = ':';
|
379
|
+
dump_cstr(sym, len, 0, out);
|
380
|
+
*out->cur++ = '}';
|
381
|
+
*out->cur = '\0';
|
382
|
+
} else {
|
383
|
+
dump_cstr(sym, len, 1, out);
|
385
384
|
}
|
386
385
|
}
|
387
386
|
|
387
|
+
static void
|
388
|
+
dump_class_comp(VALUE obj, Out out) {
|
389
|
+
const char *s = rb_class2name(obj);
|
390
|
+
|
391
|
+
dump_cstr(s, strlen(s), 0, out);
|
392
|
+
}
|
393
|
+
|
394
|
+
static void
|
395
|
+
dump_class_obj(VALUE obj, Out out) {
|
396
|
+
const char *s = rb_class2name(obj);
|
397
|
+
size_t len = strlen(s);
|
398
|
+
|
399
|
+
if (out->end - out->cur <= 6) {
|
400
|
+
grow(out, 6);
|
401
|
+
}
|
402
|
+
*out->cur++ = '{';
|
403
|
+
*out->cur++ = '"';
|
404
|
+
*out->cur++ = '^';
|
405
|
+
*out->cur++ = 'c';
|
406
|
+
*out->cur++ = '"';
|
407
|
+
*out->cur++ = ':';
|
408
|
+
dump_cstr(s, len, 0, out);
|
409
|
+
*out->cur++ = '}';
|
410
|
+
*out->cur = '\0';
|
411
|
+
}
|
412
|
+
|
388
413
|
static void
|
389
414
|
dump_array(VALUE a, int depth, Out out) {
|
390
415
|
VALUE *np = RARRAY_PTR(a);
|
@@ -422,17 +447,85 @@ dump_array(VALUE a, int depth, Out out) {
|
|
422
447
|
}
|
423
448
|
|
424
449
|
static int
|
425
|
-
|
450
|
+
hash_cb_strict(VALUE key, VALUE value, Out out) {
|
426
451
|
int depth = out->depth;
|
427
|
-
|
452
|
+
long size = depth * out->indent + 1;
|
428
453
|
|
429
|
-
if (out->end - out->cur <=
|
454
|
+
if (out->end - out->cur <= size) {
|
430
455
|
grow(out, size);
|
431
456
|
}
|
432
457
|
fill_indent(out, depth);
|
433
|
-
|
434
|
-
|
435
|
-
|
458
|
+
if (rb_type(key) == T_STRING) {
|
459
|
+
dump_str(key, out);
|
460
|
+
*out->cur++ = ':';
|
461
|
+
dump_val(value, depth, out);
|
462
|
+
} else {
|
463
|
+
rb_raise(rb_eTypeError, "In :strict mode all Hash keys must be Strings.");
|
464
|
+
}
|
465
|
+
out->depth = depth;
|
466
|
+
*out->cur++ = ',';
|
467
|
+
|
468
|
+
return ST_CONTINUE;
|
469
|
+
}
|
470
|
+
|
471
|
+
static int
|
472
|
+
hash_cb_object(VALUE key, VALUE value, Out out) {
|
473
|
+
int depth = out->depth;
|
474
|
+
long size = depth * out->indent + 1;
|
475
|
+
|
476
|
+
if (out->end - out->cur <= size) {
|
477
|
+
grow(out, size);
|
478
|
+
}
|
479
|
+
fill_indent(out, depth);
|
480
|
+
// TBD if key is a string else dump with unique key for and entry array
|
481
|
+
if (rb_type(key) == T_STRING) {
|
482
|
+
dump_str(key, out);
|
483
|
+
*out->cur++ = ':';
|
484
|
+
dump_val(value, depth, out);
|
485
|
+
} else if (rb_type(key) == T_SYMBOL) {
|
486
|
+
dump_sym_obj(key, out);
|
487
|
+
*out->cur++ = ':';
|
488
|
+
dump_val(value, depth, out);
|
489
|
+
} else {
|
490
|
+
int d2 = depth + 1;
|
491
|
+
long s2 = size + out->indent + 1;
|
492
|
+
int i;
|
493
|
+
int started = 0;
|
494
|
+
u_char b;
|
495
|
+
|
496
|
+
if (out->end - out->cur <= s2 + 15) {
|
497
|
+
grow(out, s2 + 15);
|
498
|
+
}
|
499
|
+
*out->cur++ = '"';
|
500
|
+
*out->cur++ = '^';
|
501
|
+
*out->cur++ = '#';
|
502
|
+
out->hash_cnt++;
|
503
|
+
for (i = 28; 0 <= i; i -= 4) {
|
504
|
+
b = (u_char)((out->hash_cnt >> i) & 0x0000000F);
|
505
|
+
if ('\0' != b) {
|
506
|
+
started = 1;
|
507
|
+
}
|
508
|
+
if (started) {
|
509
|
+
*out->cur++ = hex_chars[b];
|
510
|
+
}
|
511
|
+
}
|
512
|
+
*out->cur++ = '"';
|
513
|
+
*out->cur++ = ':';
|
514
|
+
*out->cur++ = '[';
|
515
|
+
fill_indent(out, d2);
|
516
|
+
dump_val(key, d2, out);
|
517
|
+
if (out->end - out->cur <= (long)s2) {
|
518
|
+
grow(out, s2);
|
519
|
+
}
|
520
|
+
*out->cur++ = ',';
|
521
|
+
fill_indent(out, d2);
|
522
|
+
dump_val(value, d2, out);
|
523
|
+
if (out->end - out->cur <= (long)size) {
|
524
|
+
grow(out, size);
|
525
|
+
}
|
526
|
+
fill_indent(out, depth);
|
527
|
+
*out->cur++ = ']';
|
528
|
+
}
|
436
529
|
out->depth = depth;
|
437
530
|
*out->cur++ = ',';
|
438
531
|
|
@@ -440,7 +533,7 @@ hash_cb(VALUE key, VALUE value, Out out) {
|
|
440
533
|
}
|
441
534
|
|
442
535
|
static void
|
443
|
-
dump_hash(VALUE obj, int depth, Out out) {
|
536
|
+
dump_hash(VALUE obj, int depth, int mode, Out out) {
|
444
537
|
int cnt = (int)RHASH_SIZE(obj);
|
445
538
|
|
446
539
|
if (out->end - out->cur <= 2) {
|
@@ -453,8 +546,14 @@ dump_hash(VALUE obj, int depth, Out out) {
|
|
453
546
|
size_t size = depth * out->indent + 2;
|
454
547
|
|
455
548
|
out->depth = depth + 1;
|
456
|
-
|
457
|
-
|
549
|
+
if (ObjectMode == mode) {
|
550
|
+
rb_hash_foreach(obj, hash_cb_object, (VALUE)out);
|
551
|
+
} else {
|
552
|
+
rb_hash_foreach(obj, hash_cb_strict, (VALUE)out);
|
553
|
+
}
|
554
|
+
if (',' == *(out->cur - 1)) {
|
555
|
+
out->cur--; // backup to overwrite last comma
|
556
|
+
}
|
458
557
|
if (out->end - out->cur <= (long)size) {
|
459
558
|
grow(out, size);
|
460
559
|
}
|
@@ -465,95 +564,95 @@ dump_hash(VALUE obj, int depth, Out out) {
|
|
465
564
|
}
|
466
565
|
|
467
566
|
static void
|
468
|
-
|
567
|
+
dump_time(VALUE obj, Out out) {
|
568
|
+
char buf[64];
|
569
|
+
char *b = buf + sizeof(buf) - 1;
|
570
|
+
time_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
571
|
+
long usec = NUM2LONG(rb_funcall2(obj, oj_tv_usec_id, 0, 0));
|
572
|
+
char *dot = b - 7;
|
573
|
+
long size;
|
574
|
+
|
575
|
+
*b-- = '\0';
|
576
|
+
for (; dot < b; b--, usec /= 10) {
|
577
|
+
*b = '0' + (usec % 10);
|
578
|
+
}
|
579
|
+
*b-- = '.';
|
580
|
+
for (; 0 < sec; b--, sec /= 10) {
|
581
|
+
*b = '0' + (sec % 10);
|
582
|
+
}
|
583
|
+
b++;
|
584
|
+
size = sizeof(buf) - (b - buf) - 1;
|
585
|
+
if (out->end - out->cur <= size) {
|
586
|
+
grow(out, size);
|
587
|
+
}
|
588
|
+
memcpy(out->cur, b, size);
|
589
|
+
out->cur += size;
|
590
|
+
*out->cur = '\0';
|
591
|
+
}
|
592
|
+
|
593
|
+
static void
|
594
|
+
dump_data_comp(VALUE obj, Out out) {
|
469
595
|
VALUE clas = rb_obj_class(obj);
|
470
596
|
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
break;
|
475
|
-
case NullMode:
|
597
|
+
if (rb_cTime == clas) {
|
598
|
+
dump_time(obj, out);
|
599
|
+
} else {
|
476
600
|
dump_nil(out);
|
477
|
-
break;
|
478
|
-
case ObjectMode:
|
479
|
-
case CompatMode:
|
480
|
-
default:
|
481
|
-
if (rb_cTime == clas) {
|
482
|
-
char buf[64];
|
483
|
-
char *b = buf + sizeof(buf) - 1;
|
484
|
-
time_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
485
|
-
long usec = NUM2LONG(rb_funcall2(obj, oj_tv_usec_id, 0, 0));
|
486
|
-
char *dot = b - 7;
|
487
|
-
long size;
|
488
|
-
|
489
|
-
*b-- = '\0';
|
490
|
-
for (; dot < b; b--, usec /= 10) {
|
491
|
-
*b = '0' + (usec % 10);
|
492
|
-
}
|
493
|
-
*b-- = '.';
|
494
|
-
for (; 0 < sec; b--, sec /= 10) {
|
495
|
-
*b = '0' + (sec % 10);
|
496
|
-
}
|
497
|
-
b++;
|
498
|
-
size = sizeof(buf) - (b - buf) - 1;
|
499
|
-
if (out->end - out->cur <= size + 20) {
|
500
|
-
grow(out, size + 20);
|
501
|
-
}
|
502
|
-
memcpy(out->cur, "{\"*\":\"Time\",\"-\":", 16);
|
503
|
-
out->cur += 16;
|
504
|
-
memcpy(out->cur, b, size);
|
505
|
-
out->cur += size;
|
506
|
-
*out->cur++ = '}';
|
507
|
-
*out->cur = '\0';
|
508
|
-
} else {
|
509
|
-
dump_nil(out);
|
510
|
-
}
|
511
601
|
}
|
512
602
|
}
|
513
603
|
|
514
604
|
static void
|
515
|
-
|
516
|
-
|
517
|
-
|
605
|
+
dump_data_obj(VALUE obj, Out out) {
|
606
|
+
VALUE clas = rb_obj_class(obj);
|
607
|
+
|
608
|
+
if (rb_cTime == clas) {
|
609
|
+
if (out->end - out->cur <= 6) {
|
610
|
+
grow(out, 6);
|
611
|
+
}
|
612
|
+
*out->cur++ = '{';
|
613
|
+
*out->cur++ = '"';
|
614
|
+
*out->cur++ = '^';
|
615
|
+
*out->cur++ = 't';
|
616
|
+
*out->cur++ = '"';
|
617
|
+
*out->cur++ = ':';
|
618
|
+
dump_time(obj, out);
|
619
|
+
*out->cur++ = '}';
|
620
|
+
*out->cur = '\0';
|
518
621
|
} else {
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
dump_obj_attrs(obj, 0, depth, out);
|
528
|
-
break;
|
529
|
-
case CompatMode:
|
530
|
-
default:
|
531
|
-
if (rb_respond_to(obj, oj_to_hash_id)) {
|
532
|
-
VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
|
622
|
+
dump_nil(out);
|
623
|
+
}
|
624
|
+
}
|
625
|
+
|
626
|
+
static void
|
627
|
+
dump_obj_comp(VALUE obj, int depth, Out out) {
|
628
|
+
if (rb_respond_to(obj, oj_to_hash_id)) {
|
629
|
+
VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
|
533
630
|
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
}
|
546
|
-
memcpy(out->cur, s, len);
|
547
|
-
out->cur += len;
|
548
|
-
} else {
|
549
|
-
dump_obj_attrs(obj, 0, depth, out);
|
550
|
-
}
|
551
|
-
break;
|
631
|
+
if (T_HASH != rb_type(h)) {
|
632
|
+
rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
|
633
|
+
}
|
634
|
+
dump_hash(h, depth, out->opts->mode, out);
|
635
|
+
} else if (rb_respond_to(obj, oj_to_json_id)) {
|
636
|
+
VALUE rs = rb_funcall(obj, oj_to_json_id, 0);
|
637
|
+
const char *s = StringValuePtr(rs);
|
638
|
+
int len = (int)RSTRING_LEN(rs);
|
639
|
+
|
640
|
+
if (out->end - out->cur <= len) {
|
641
|
+
grow(out, len);
|
552
642
|
}
|
643
|
+
memcpy(out->cur, s, len);
|
644
|
+
out->cur += len;
|
645
|
+
} else {
|
646
|
+
dump_obj_attrs(obj, 0, depth, out);
|
553
647
|
}
|
554
648
|
*out->cur = '\0';
|
555
649
|
}
|
556
650
|
|
651
|
+
inline static void
|
652
|
+
dump_obj_obj(VALUE obj, int depth, Out out) {
|
653
|
+
dump_obj_attrs(obj, 1, depth, out);
|
654
|
+
}
|
655
|
+
|
557
656
|
static int
|
558
657
|
dump_attr_cb(ID key, VALUE value, Out out) {
|
559
658
|
int depth = out->depth;
|
@@ -563,13 +662,18 @@ dump_attr_cb(ID key, VALUE value, Out out) {
|
|
563
662
|
if (out->end - out->cur <= (long)size) {
|
564
663
|
grow(out, size);
|
565
664
|
}
|
665
|
+
fill_indent(out, depth);
|
566
666
|
if ('@' == *attr) {
|
567
667
|
attr++;
|
668
|
+
dump_cstr(attr, strlen(attr), 0, out);
|
568
669
|
} else {
|
569
|
-
|
670
|
+
char buf[32];
|
671
|
+
|
672
|
+
*buf = '~';
|
673
|
+
strncpy(buf + 1, attr, sizeof(buf) - 2);
|
674
|
+
buf[sizeof(buf) - 1] = '\0';
|
675
|
+
dump_cstr(buf, strlen(buf), 0, out);
|
570
676
|
}
|
571
|
-
fill_indent(out, depth);
|
572
|
-
dump_cstr(attr, (int)strlen(attr) - 1, out);
|
573
677
|
*out->cur++ = ':';
|
574
678
|
dump_val(value, depth, out);
|
575
679
|
out->depth = depth;
|
@@ -590,17 +694,18 @@ dump_obj_attrs(VALUE obj, int with_class, int depth, Out out) {
|
|
590
694
|
if (with_class) {
|
591
695
|
const char *class_name = rb_class2name(rb_obj_class(obj));
|
592
696
|
int clen = (int)strlen(class_name);
|
593
|
-
|
594
|
-
size = d2 * out->indent + clen +
|
697
|
+
|
698
|
+
size = d2 * out->indent + clen + 10;
|
595
699
|
if (out->end - out->cur <= (long)size) {
|
596
700
|
grow(out, size);
|
597
701
|
}
|
598
702
|
fill_indent(out, d2);
|
599
703
|
*out->cur++ = '"';
|
600
|
-
*out->cur++ = '
|
704
|
+
*out->cur++ = '^';
|
705
|
+
*out->cur++ = 'o';
|
601
706
|
*out->cur++ = '"';
|
602
707
|
*out->cur++ = ':';
|
603
|
-
dump_cstr(class_name, clen, out);
|
708
|
+
dump_cstr(class_name, clen, 0, out);
|
604
709
|
}
|
605
710
|
{
|
606
711
|
int cnt;
|
@@ -634,10 +739,15 @@ dump_obj_attrs(VALUE obj, int with_class, int depth, Out out) {
|
|
634
739
|
attr = rb_id2name(vid);
|
635
740
|
if ('@' == *attr) {
|
636
741
|
attr++;
|
742
|
+
dump_cstr(attr, strlen(attr), 0, out);
|
637
743
|
} else {
|
638
|
-
|
744
|
+
char buf[32];
|
745
|
+
|
746
|
+
*buf = '~';
|
747
|
+
strncpy(buf + 1, attr, sizeof(buf) - 2);
|
748
|
+
buf[sizeof(buf) - 1] = '\0';
|
749
|
+
dump_cstr(buf, strlen(attr) + 1, 0, out);
|
639
750
|
}
|
640
|
-
dump_cstr(attr, (int)strlen(attr) - 1, out);
|
641
751
|
*out->cur++ = ':';
|
642
752
|
dump_val(rb_ivar_get(obj, vid), d2, out);
|
643
753
|
if (out->end - out->cur <= 2) {
|
@@ -654,6 +764,11 @@ dump_obj_attrs(VALUE obj, int with_class, int depth, Out out) {
|
|
654
764
|
*out->cur = '\0';
|
655
765
|
}
|
656
766
|
|
767
|
+
static void
|
768
|
+
raise_strict(VALUE obj) {
|
769
|
+
rb_raise(rb_eTypeError, "Failed to dump %s Object to JSON in strict mode.\n", rb_class2name(rb_obj_class(obj)));
|
770
|
+
}
|
771
|
+
|
657
772
|
static void
|
658
773
|
dump_val(VALUE obj, int depth, Out out) {
|
659
774
|
switch (rb_type(obj)) {
|
@@ -664,12 +779,51 @@ dump_val(VALUE obj, int depth, Out out) {
|
|
664
779
|
case T_FLOAT: dump_float(obj, out); break;
|
665
780
|
case T_BIGNUM: dump_bignum(obj, out); break;
|
666
781
|
case T_STRING: dump_str(obj, out); break;
|
667
|
-
case T_SYMBOL:
|
782
|
+
case T_SYMBOL:
|
783
|
+
switch (out->opts->mode) {
|
784
|
+
case StrictMode: raise_strict(obj); break;
|
785
|
+
case NullMode: dump_nil(out); break;
|
786
|
+
case CompatMode: dump_sym_comp(obj, out); break;
|
787
|
+
case ObjectMode:
|
788
|
+
default: dump_sym_obj(obj, out); break;
|
789
|
+
}
|
790
|
+
break;
|
668
791
|
case T_ARRAY: dump_array(obj, depth, out); break;
|
669
|
-
case T_HASH: dump_hash(obj, depth, out); break;
|
670
|
-
case T_CLASS:
|
671
|
-
|
672
|
-
|
792
|
+
case T_HASH: dump_hash(obj, depth, out->opts->mode, out); break;
|
793
|
+
case T_CLASS:
|
794
|
+
switch (out->opts->mode) {
|
795
|
+
case StrictMode: raise_strict(obj); break;
|
796
|
+
case NullMode: dump_nil(out); break;
|
797
|
+
case CompatMode: dump_class_comp(obj, out); break;
|
798
|
+
case ObjectMode:
|
799
|
+
default: dump_class_obj(obj, out); break;
|
800
|
+
}
|
801
|
+
break;
|
802
|
+
case T_OBJECT:
|
803
|
+
switch (out->opts->mode) {
|
804
|
+
case StrictMode: raise_strict(obj); break;
|
805
|
+
case NullMode: dump_nil(out); break;
|
806
|
+
case CompatMode: dump_obj_comp(obj, depth, out); break;
|
807
|
+
case ObjectMode:
|
808
|
+
default: dump_obj_obj(obj, depth, out); break;
|
809
|
+
}
|
810
|
+
break;
|
811
|
+
case T_DATA:
|
812
|
+
switch (out->opts->mode) {
|
813
|
+
case StrictMode: raise_strict(obj); break;
|
814
|
+
case NullMode: dump_nil(out); break;
|
815
|
+
case CompatMode: dump_data_comp(obj, out); break;
|
816
|
+
case ObjectMode:
|
817
|
+
default: dump_data_obj(obj, out); break;
|
818
|
+
}
|
819
|
+
break;
|
820
|
+
case T_STRUCT: // for Range
|
821
|
+
#if (defined T_COMPLEX && defined RCOMPLEX)
|
822
|
+
case T_COMPLEX:
|
823
|
+
#endif
|
824
|
+
#if (defined T_RATIONAL && defined RRATIONAL)
|
825
|
+
case T_RATIONAL:
|
826
|
+
#endif
|
673
827
|
case T_REGEXP:
|
674
828
|
// TBD
|
675
829
|
rb_raise(rb_eNotImpError, "Failed to dump '%s' Object (%02x)\n",
|
@@ -690,7 +844,7 @@ dump_obj_to_json(VALUE obj, Options copts, Out out) {
|
|
690
844
|
// out->circ_cache = 0;
|
691
845
|
// out->circ_cnt = 0;
|
692
846
|
out->opts = copts;
|
693
|
-
out->
|
847
|
+
out->hash_cnt = 0;
|
694
848
|
/* if (Yes == copts->circular) {
|
695
849
|
ox_cache8_new(&out->circ_cache);
|
696
850
|
}*/
|