oj 2.12.1 → 2.12.2
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.
- checksums.yaml +7 -0
- data/README.md +9 -2
- data/ext/oj/dump.c +2 -2
- data/ext/oj/fast.c +89 -119
- data/ext/oj/oj.h +6 -5
- data/lib/oj/version.rb +1 -1
- data/test/bug.rb +40 -51
- data/test/bug2.rb +10 -0
- data/test/example.rb +11 -0
- data/test/io.rb +48 -0
- data/test/{test_range.rb → mod.rb} +6 -9
- data/test/struct.rb +29 -0
- data/test/test_fast.rb +30 -2
- data/test/test_scp.rb +12 -2
- data/test/test_serializer.rb +59 -0
- data/test/test_various.rb +3 -9
- data/test/write_timebars.rb +31 -0
- data/test/zip.rb +34 -0
- metadata +47 -51
- data/test/perf1.rb +0 -64
- data/test/perf2.rb +0 -76
- data/test/perf_obj_old.rb +0 -213
- data/test/test_bigd.rb +0 -63
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2a621ea1cf610e5b78949d860fc54f2c6fe43e0c
|
4
|
+
data.tar.gz: 11cd52b0f0747e95007d678b291560b6271b9235
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 76bdb63802a6f728259dd9cb7351d64f38862cf8a522bdb56c208cdc5803cb52a4625493c4c0d7d103d5e6a7a2522bfd847a1942ccb56ce2a59a3b22ae9d969e
|
7
|
+
data.tar.gz: 5a215c6a81a876ee0f1a777ff90f1d55b1ad5eb809da6b431eb21b79f7bcaab7a552febdcc090f12e17aa0acf0ea885c78d70940b13e298d8524db1c227c0500
|
data/README.md
CHANGED
@@ -26,9 +26,11 @@ Follow [@peterohler on Twitter](http://twitter.com/#!/peterohler) for announceme
|
|
26
26
|
|
27
27
|
[![Build Status](https://secure.travis-ci.org/ohler55/oj.png?branch=master)](http://travis-ci.org/ohler55/oj)
|
28
28
|
|
29
|
-
## Current Release 2.12.
|
29
|
+
## Current Release 2.12.2
|
30
30
|
|
31
|
-
-
|
31
|
+
- Fixed Oj::Doc bug that causes a crash on local name lookups.
|
32
|
+
|
33
|
+
- Fixed Oj::Doc unicode parsing.
|
32
34
|
|
33
35
|
[Older release notes](http://www.ohler.com/dev/oj_misc/release_notes.html).
|
34
36
|
|
@@ -80,6 +82,11 @@ Rails 3.2 and 4.0. As of the Oj 2.6.0 release the default behavior is to not use
|
|
80
82
|
the `to_json()` method unless the `:use_to_json` option is set. This provides
|
81
83
|
another work around to the rails older and newer behavior.
|
82
84
|
|
85
|
+
The latest ActiveRecord is able to work with Oj by simply using the line:
|
86
|
+
```
|
87
|
+
serialize :my_attr, Oj
|
88
|
+
```
|
89
|
+
|
83
90
|
In version Rails 4.1, multi_json has been removed, and this patch is unnecessary and will no longer work.
|
84
91
|
Instead, use the `oj_mimic_json` [gem](https://github.com/ohler55/oj_mimic_json) along with `oj` in your `Gemfile` to have Oj mimic the JSON gem and be used in its place by `ActiveSupport` JSON handling:
|
85
92
|
```
|
data/ext/oj/dump.c
CHANGED
@@ -2228,7 +2228,7 @@ dump_leaf_hash(Leaf leaf, int depth, Out out) {
|
|
2228
2228
|
|
2229
2229
|
static void
|
2230
2230
|
dump_leaf(Leaf leaf, int depth, Out out) {
|
2231
|
-
switch (leaf->
|
2231
|
+
switch (leaf->rtype) {
|
2232
2232
|
case T_NIL:
|
2233
2233
|
dump_nil(out);
|
2234
2234
|
break;
|
@@ -2254,7 +2254,7 @@ dump_leaf(Leaf leaf, int depth, Out out) {
|
|
2254
2254
|
dump_leaf_hash(leaf, depth, out);
|
2255
2255
|
break;
|
2256
2256
|
default:
|
2257
|
-
rb_raise(rb_eTypeError, "Unexpected type %02x.\n", leaf->
|
2257
|
+
rb_raise(rb_eTypeError, "Unexpected type %02x.\n", leaf->rtype);
|
2258
2258
|
break;
|
2259
2259
|
}
|
2260
2260
|
}
|
data/ext/oj/fast.c
CHANGED
@@ -170,7 +170,7 @@ ulong_fill(char *s, size_t num) {
|
|
170
170
|
inline static void
|
171
171
|
leaf_init(Leaf leaf, int type) {
|
172
172
|
leaf->next = 0;
|
173
|
-
leaf->
|
173
|
+
leaf->rtype = type;
|
174
174
|
leaf->parent_type = T_NONE;
|
175
175
|
switch (type) {
|
176
176
|
case T_ARRAY:
|
@@ -206,6 +206,8 @@ leaf_new(Doc doc, int type) {
|
|
206
206
|
if (0 == doc->batches || BATCH_SIZE == doc->batches->next_avail) {
|
207
207
|
Batch b = ALLOC(struct _Batch);
|
208
208
|
|
209
|
+
// Initializes all leaves with a NO_VAL value_type
|
210
|
+
memset(b, 0, sizeof(struct _Batch));
|
209
211
|
b->next = doc->batches;
|
210
212
|
doc->batches = b;
|
211
213
|
b->next_avail = 0;
|
@@ -232,7 +234,7 @@ leaf_append_element(Leaf parent, Leaf element) {
|
|
232
234
|
static VALUE
|
233
235
|
leaf_value(Doc doc, Leaf leaf) {
|
234
236
|
if (RUBY_VAL != leaf->value_type) {
|
235
|
-
switch (leaf->
|
237
|
+
switch (leaf->rtype) {
|
236
238
|
case T_NIL:
|
237
239
|
leaf->value = Qnil;
|
238
240
|
break;
|
@@ -260,7 +262,7 @@ leaf_value(Doc doc, Leaf leaf) {
|
|
260
262
|
return leaf_hash_value(doc, leaf);
|
261
263
|
break;
|
262
264
|
default:
|
263
|
-
rb_raise(rb_const_get_at(Oj, rb_intern("Error")), "Unexpected type %02x.", leaf->
|
265
|
+
rb_raise(rb_const_get_at(Oj, rb_intern("Error")), "Unexpected type %02x.", leaf->rtype);
|
264
266
|
break;
|
265
267
|
}
|
266
268
|
}
|
@@ -348,79 +350,11 @@ leaf_fixnum_value(Leaf leaf) {
|
|
348
350
|
leaf->value_type = RUBY_VAL;
|
349
351
|
}
|
350
352
|
|
351
|
-
#ifdef JRUBY_RUBY
|
352
|
-
static void
|
353
|
-
leaf_float_value(Leaf leaf) {
|
354
|
-
char *s = leaf->str;
|
355
|
-
int64_t n = 0;
|
356
|
-
long a = 0;
|
357
|
-
long div = 1;
|
358
|
-
long e = 0;
|
359
|
-
int neg = 0;
|
360
|
-
int eneg = 0;
|
361
|
-
int big = 0;
|
362
|
-
|
363
|
-
if ('-' == *s) {
|
364
|
-
s++;
|
365
|
-
neg = 1;
|
366
|
-
} else if ('+' == *s) {
|
367
|
-
s++;
|
368
|
-
}
|
369
|
-
for (; '0' <= *s && *s <= '9'; s++) {
|
370
|
-
n = n * 10 + (*s - '0');
|
371
|
-
if (NUM_MAX <= n) {
|
372
|
-
big = 1;
|
373
|
-
}
|
374
|
-
}
|
375
|
-
if (big) {
|
376
|
-
char c = *s;
|
377
|
-
|
378
|
-
*s = '\0';
|
379
|
-
leaf->value = rb_cstr_to_inum(leaf->str, 10, 0);
|
380
|
-
*s = c;
|
381
|
-
} else {
|
382
|
-
double d;
|
383
|
-
|
384
|
-
if ('.' == *s) {
|
385
|
-
s++;
|
386
|
-
for (; '0' <= *s && *s <= '9'; s++) {
|
387
|
-
a = a * 10 + (*s - '0');
|
388
|
-
div *= 10;
|
389
|
-
}
|
390
|
-
}
|
391
|
-
if ('e' == *s || 'E' == *s) {
|
392
|
-
s++;
|
393
|
-
if ('-' == *s) {
|
394
|
-
s++;
|
395
|
-
eneg = 1;
|
396
|
-
} else if ('+' == *s) {
|
397
|
-
s++;
|
398
|
-
}
|
399
|
-
for (; '0' <= *s && *s <= '9'; s++) {
|
400
|
-
e = e * 10 + (*s - '0');
|
401
|
-
}
|
402
|
-
}
|
403
|
-
d = (double)n + (double)a / (double)div;
|
404
|
-
if (neg) {
|
405
|
-
d = -d;
|
406
|
-
}
|
407
|
-
if (0 != e) {
|
408
|
-
if (eneg) {
|
409
|
-
e = -e;
|
410
|
-
}
|
411
|
-
d *= pow(10.0, e);
|
412
|
-
}
|
413
|
-
leaf->value = rb_float_new(d);
|
414
|
-
}
|
415
|
-
leaf->value_type = RUBY_VAL;
|
416
|
-
}
|
417
|
-
#else
|
418
353
|
static void
|
419
354
|
leaf_float_value(Leaf leaf) {
|
420
355
|
leaf->value = rb_float_new(rb_cstr_to_dbl(leaf->str, 1));
|
421
356
|
leaf->value_type = RUBY_VAL;
|
422
357
|
}
|
423
|
-
#endif
|
424
358
|
|
425
359
|
static VALUE
|
426
360
|
leaf_array_value(Doc doc, Leaf leaf) {
|
@@ -675,33 +609,59 @@ read_nil(ParseInfo pi) {
|
|
675
609
|
return leaf;
|
676
610
|
}
|
677
611
|
|
678
|
-
static
|
679
|
-
|
680
|
-
|
612
|
+
static uint32_t
|
613
|
+
read_4hex(ParseInfo pi, const char *h) {
|
614
|
+
uint32_t b = 0;
|
615
|
+
int i;
|
616
|
+
|
617
|
+
for (i = 0; i < 4; i++, h++) {
|
618
|
+
b = b << 4;
|
619
|
+
if ('0' <= *h && *h <= '9') {
|
620
|
+
b += *h - '0';
|
621
|
+
} else if ('A' <= *h && *h <= 'F') {
|
622
|
+
b += *h - 'A' + 10;
|
623
|
+
} else if ('a' <= *h && *h <= 'f') {
|
624
|
+
b += *h - 'a' + 10;
|
625
|
+
} else {
|
626
|
+
raise_error("invalid hex character", pi->str, pi->s);
|
627
|
+
}
|
628
|
+
}
|
629
|
+
return b;
|
630
|
+
}
|
681
631
|
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
} else if (
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
} else if (
|
699
|
-
|
632
|
+
static char*
|
633
|
+
unicode_to_chars(ParseInfo pi, char *t, uint32_t code) {
|
634
|
+
if (0x0000007F >= code) {
|
635
|
+
*t++ = (char)code;
|
636
|
+
} else if (0x000007FF >= code) {
|
637
|
+
*t++ = 0xC0 | (code >> 6);
|
638
|
+
*t++ = 0x80 | (0x3F & code);
|
639
|
+
} else if (0x0000FFFF >= code) {
|
640
|
+
*t++ = 0xE0 | (code >> 12);
|
641
|
+
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
642
|
+
*t++ = 0x80 | (0x3F & code);
|
643
|
+
} else if (0x001FFFFF >= code) {
|
644
|
+
*t++ = 0xF0 | (code >> 18);
|
645
|
+
*t++ = 0x80 | ((code >> 12) & 0x3F);
|
646
|
+
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
647
|
+
*t++ = 0x80 | (0x3F & code);
|
648
|
+
} else if (0x03FFFFFF >= code) {
|
649
|
+
*t++ = 0xF8 | (code >> 24);
|
650
|
+
*t++ = 0x80 | ((code >> 18) & 0x3F);
|
651
|
+
*t++ = 0x80 | ((code >> 12) & 0x3F);
|
652
|
+
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
653
|
+
*t++ = 0x80 | (0x3F & code);
|
654
|
+
} else if (0x7FFFFFFF >= code) {
|
655
|
+
*t++ = 0xFC | (code >> 30);
|
656
|
+
*t++ = 0x80 | ((code >> 24) & 0x3F);
|
657
|
+
*t++ = 0x80 | ((code >> 18) & 0x3F);
|
658
|
+
*t++ = 0x80 | ((code >> 12) & 0x3F);
|
659
|
+
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
660
|
+
*t++ = 0x80 | (0x3F & code);
|
700
661
|
} else {
|
701
|
-
pi->s
|
702
|
-
raise_error("invalid hex character", pi->str, pi->s);
|
662
|
+
raise_error("invalid Unicode character", pi->str, pi->s);
|
703
663
|
}
|
704
|
-
return
|
664
|
+
return t;
|
705
665
|
}
|
706
666
|
|
707
667
|
/* Assume the value starts immediately and goes until the quote character is
|
@@ -731,16 +691,31 @@ read_quoted_value(ParseInfo pi) {
|
|
731
691
|
case '"': *t = '"'; break;
|
732
692
|
case '/': *t = '/'; break;
|
733
693
|
case '\\': *t = '\\'; break;
|
734
|
-
case 'u':
|
694
|
+
case 'u': {
|
695
|
+
uint32_t code;
|
696
|
+
|
735
697
|
h++;
|
736
|
-
|
737
|
-
h +=
|
738
|
-
if (
|
739
|
-
|
698
|
+
code = read_4hex(pi, h);
|
699
|
+
h += 3;
|
700
|
+
if (0x0000D800 <= code && code <= 0x0000DFFF) {
|
701
|
+
uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
|
702
|
+
uint32_t c2;
|
703
|
+
|
704
|
+
h++;
|
705
|
+
if ('\\' != *h || 'u' != *(h + 1)) {
|
706
|
+
pi->s = h;
|
707
|
+
raise_error("invalid escaped character", pi->str, pi->s);
|
708
|
+
}
|
709
|
+
h += 2;
|
710
|
+
c2 = read_4hex(pi, h);
|
711
|
+
h += 3;
|
712
|
+
c2 = (c2 - 0x0000DC00) & 0x000003FF;
|
713
|
+
code = ((c1 << 10) | c2) + 0x00010000;
|
740
714
|
}
|
741
|
-
|
742
|
-
|
715
|
+
t = unicode_to_chars(pi, t, code);
|
716
|
+
t--;
|
743
717
|
break;
|
718
|
+
}
|
744
719
|
default:
|
745
720
|
pi->s = h;
|
746
721
|
raise_error("invalid escaped character", pi->str, pi->s);
|
@@ -759,15 +734,10 @@ read_quoted_value(ParseInfo pi) {
|
|
759
734
|
// doc support functions
|
760
735
|
inline static void
|
761
736
|
doc_init(Doc doc) {
|
737
|
+
memset(doc, 0, sizeof(struct _Doc));
|
762
738
|
doc->where = doc->where_path;
|
763
|
-
*doc->where = 0;
|
764
|
-
doc->data = 0;
|
765
739
|
doc->self = Qundef;
|
766
|
-
doc->size = 0;
|
767
|
-
doc->json = 0;
|
768
740
|
doc->batches = &doc->batch0;
|
769
|
-
doc->batch0.next = 0;
|
770
|
-
doc->batch0.next_avail = 0;
|
771
741
|
}
|
772
742
|
|
773
743
|
static void
|
@@ -885,7 +855,7 @@ get_doc_leaf(Doc doc, const char *path) {
|
|
885
855
|
if (MAX_STACK <= cnt) {
|
886
856
|
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
887
857
|
}
|
888
|
-
memcpy(stack, doc->where_path, sizeof(Leaf) * cnt);
|
858
|
+
memcpy(stack, doc->where_path, sizeof(Leaf) * (cnt + 1));
|
889
859
|
lp = stack + cnt;
|
890
860
|
}
|
891
861
|
return get_leaf(stack, lp, path);
|
@@ -914,7 +884,7 @@ get_leaf(Leaf *stack, Leaf *lp, const char *path) {
|
|
914
884
|
} else if (COL_VAL == leaf->value_type && 0 != leaf->elements) {
|
915
885
|
Leaf first = leaf->elements->next;
|
916
886
|
Leaf e = first;
|
917
|
-
int type = leaf->
|
887
|
+
int type = leaf->rtype;
|
918
888
|
|
919
889
|
leaf = 0;
|
920
890
|
if (T_ARRAY == type) {
|
@@ -1021,7 +991,7 @@ move_step(Doc doc, const char *path, int loc) {
|
|
1021
991
|
Leaf first = leaf->elements->next;
|
1022
992
|
Leaf e = first;
|
1023
993
|
|
1024
|
-
if (T_ARRAY == leaf->
|
994
|
+
if (T_ARRAY == leaf->rtype) {
|
1025
995
|
int cnt = 0;
|
1026
996
|
|
1027
997
|
for (; '0' <= *path && *path <= '9'; path++) {
|
@@ -1046,7 +1016,7 @@ move_step(Doc doc, const char *path, int loc) {
|
|
1046
1016
|
cnt--;
|
1047
1017
|
e = e->next;
|
1048
1018
|
} while (e != first);
|
1049
|
-
} else if (T_HASH == leaf->
|
1019
|
+
} else if (T_HASH == leaf->rtype) {
|
1050
1020
|
const char *key = path;
|
1051
1021
|
const char *slash = strchr(path, '/');
|
1052
1022
|
int klen;
|
@@ -1302,7 +1272,7 @@ doc_type(int argc, VALUE *argv, VALUE self) {
|
|
1302
1272
|
path = StringValuePtr(*argv);
|
1303
1273
|
}
|
1304
1274
|
if (0 != (leaf = get_doc_leaf(doc, path))) {
|
1305
|
-
switch (leaf->
|
1275
|
+
switch (leaf->rtype) {
|
1306
1276
|
case T_NIL: type = rb_cNilClass; break;
|
1307
1277
|
case T_TRUE: type = rb_cTrueClass; break;
|
1308
1278
|
case T_FALSE: type = rb_cFalseClass; break;
|
@@ -1375,7 +1345,7 @@ doc_each_leaf(int argc, VALUE *argv, VALUE self) {
|
|
1375
1345
|
|
1376
1346
|
wlen = doc->where - doc->where_path;
|
1377
1347
|
if (0 < wlen) {
|
1378
|
-
memcpy(save_path, doc->where_path, sizeof(Leaf) * wlen);
|
1348
|
+
memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
|
1379
1349
|
}
|
1380
1350
|
if (1 <= argc) {
|
1381
1351
|
Check_Type(*argv, T_STRING);
|
@@ -1386,14 +1356,14 @@ doc_each_leaf(int argc, VALUE *argv, VALUE self) {
|
|
1386
1356
|
}
|
1387
1357
|
if (0 != move_step(doc, path, 1)) {
|
1388
1358
|
if (0 < wlen) {
|
1389
|
-
memcpy(doc->where_path, save_path, sizeof(Leaf) * wlen);
|
1359
|
+
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
1390
1360
|
}
|
1391
1361
|
return Qnil;
|
1392
1362
|
}
|
1393
1363
|
}
|
1394
1364
|
each_leaf(doc, self);
|
1395
1365
|
if (0 < wlen) {
|
1396
|
-
memcpy(doc->where_path, save_path, sizeof(Leaf) * wlen);
|
1366
|
+
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
1397
1367
|
}
|
1398
1368
|
}
|
1399
1369
|
return Qnil;
|
@@ -1451,7 +1421,7 @@ doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
1451
1421
|
|
1452
1422
|
wlen = doc->where - doc->where_path;
|
1453
1423
|
if (0 < wlen) {
|
1454
|
-
memcpy(save_path, doc->where_path, sizeof(Leaf) * wlen);
|
1424
|
+
memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
|
1455
1425
|
}
|
1456
1426
|
if (1 <= argc) {
|
1457
1427
|
Check_Type(*argv, T_STRING);
|
@@ -1462,7 +1432,7 @@ doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
1462
1432
|
}
|
1463
1433
|
if (0 != move_step(doc, path, 1)) {
|
1464
1434
|
if (0 < wlen) {
|
1465
|
-
memcpy(doc->where_path, save_path, sizeof(Leaf) * wlen);
|
1435
|
+
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
1466
1436
|
}
|
1467
1437
|
return Qnil;
|
1468
1438
|
}
|
@@ -1479,7 +1449,7 @@ doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
1479
1449
|
} while (e != first);
|
1480
1450
|
}
|
1481
1451
|
if (0 < wlen) {
|
1482
|
-
memcpy(doc->where_path, save_path, sizeof(Leaf) * wlen);
|
1452
|
+
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
1483
1453
|
}
|
1484
1454
|
}
|
1485
1455
|
return Qnil;
|
data/ext/oj/oj.h
CHANGED
@@ -179,9 +179,10 @@ typedef struct _StreamWriter {
|
|
179
179
|
} *StreamWriter;
|
180
180
|
|
181
181
|
enum {
|
182
|
-
|
183
|
-
|
184
|
-
|
182
|
+
NO_VAL = 0x00,
|
183
|
+
STR_VAL = 0x01,
|
184
|
+
COL_VAL = 0x02,
|
185
|
+
RUBY_VAL = 0x03
|
185
186
|
};
|
186
187
|
|
187
188
|
typedef struct _Leaf {
|
@@ -191,11 +192,11 @@ typedef struct _Leaf {
|
|
191
192
|
size_t index; // array index, 0 is not set
|
192
193
|
};
|
193
194
|
union {
|
194
|
-
char *str; // pointer to location in json string
|
195
|
+
char *str; // pointer to location in json string or allocated
|
195
196
|
struct _Leaf *elements; // array and hash elements
|
196
197
|
VALUE value;
|
197
198
|
};
|
198
|
-
uint8_t
|
199
|
+
uint8_t rtype;
|
199
200
|
uint8_t parent_type;
|
200
201
|
uint8_t value_type;
|
201
202
|
} *Leaf;
|
data/lib/oj/version.rb
CHANGED
data/test/bug.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
1
3
|
#!/usr/bin/env ruby
|
2
4
|
# encoding: UTF-8
|
3
5
|
|
@@ -5,60 +7,47 @@ $: << File.dirname(__FILE__)
|
|
5
7
|
|
6
8
|
require 'helper'
|
7
9
|
|
8
|
-
require 'oj'
|
9
|
-
require 'securerandom'
|
10
|
-
|
11
10
|
class Handler
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
def
|
17
|
-
|
11
|
+
def initialize
|
12
|
+
@state = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def hash_start
|
16
|
+
@state << {}
|
17
|
+
@state.last
|
18
|
+
end
|
19
|
+
|
20
|
+
def hash_end
|
21
|
+
@state.pop
|
22
|
+
end
|
23
|
+
|
24
|
+
def hash_set(h,k,v)
|
25
|
+
h.store(k,v)
|
18
26
|
end
|
19
|
-
end
|
20
27
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
name = "/tmp/#{SecureRandom.uuid}"
|
25
|
-
`mkfifo #{name}`
|
26
|
-
if fork
|
27
|
-
open(name, 'r+') do |read_io|
|
28
|
-
p "start reading #{read_io.stat.ftype}"
|
29
|
-
Oj.sc_parse(Handler.new, read_io) {|v| p v}
|
30
|
-
p "stop reading"
|
31
|
-
end
|
32
|
-
else
|
33
|
-
open(name, 'w+') do |write_io|
|
34
|
-
p "start writing #{write_io.stat.ftype} autoclose: #{write_io.autoclose?}"
|
35
|
-
write_io.write json
|
36
|
-
write_io.write json
|
37
|
-
p "stop writing"
|
38
|
-
end
|
39
|
-
sleep(1) # make it obvious that there are two threads
|
40
|
-
open(name, 'w+') do |write_io|
|
41
|
-
p "start writing #{write_io.stat.ftype}"
|
42
|
-
write_io.write json
|
43
|
-
write_io.write json
|
44
|
-
p "stop writing"
|
45
|
-
end
|
28
|
+
def array_start
|
29
|
+
@state << []
|
30
|
+
@state.last
|
46
31
|
end
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
write_io.write json
|
60
|
-
p "stop writing"
|
61
|
-
write_io.close
|
62
|
-
end
|
32
|
+
|
33
|
+
|
34
|
+
def array_end
|
35
|
+
@state.pop
|
36
|
+
end
|
37
|
+
|
38
|
+
def array_append(a,v)
|
39
|
+
a << v
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_value(v)
|
43
|
+
p v
|
63
44
|
end
|
45
|
+
|
46
|
+
def error(message, line, column); p "ERROR: #{message}" end
|
64
47
|
end
|
48
|
+
|
49
|
+
$handler = Handler.new
|
50
|
+
|
51
|
+
IO.popen("cat tst") { |p| puts Oj.sc_parse($handler, p) }
|
52
|
+
|
53
|
+
#File.open('tst', 'r') { |file| Oj.sc_parse($handler, file) }
|