oj 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +17 -23
- data/README.md +74 -425
- data/ext/oj/buf.h +103 -0
- data/ext/oj/cache8.c +4 -0
- data/ext/oj/circarray.c +68 -0
- data/ext/oj/circarray.h +23 -0
- data/ext/oj/code.c +227 -0
- data/ext/oj/code.h +40 -0
- data/ext/oj/compat.c +243 -0
- data/ext/oj/custom.c +1097 -0
- data/ext/oj/dump.c +766 -1534
- data/ext/oj/dump.h +92 -0
- data/ext/oj/dump_compat.c +937 -0
- data/ext/oj/dump_leaf.c +254 -0
- data/ext/oj/dump_object.c +810 -0
- data/ext/oj/dump_rails.c +329 -0
- data/ext/oj/dump_strict.c +416 -0
- data/ext/oj/encode.h +51 -0
- data/ext/oj/err.c +57 -0
- data/ext/oj/err.h +70 -0
- data/ext/oj/extconf.rb +17 -7
- data/ext/oj/fast.c +213 -180
- data/ext/oj/hash.c +163 -0
- data/ext/oj/hash.h +46 -0
- data/ext/oj/hash_test.c +512 -0
- data/ext/oj/mimic_json.c +817 -0
- data/ext/oj/mimic_rails.c +806 -0
- data/ext/oj/mimic_rails.h +17 -0
- data/ext/oj/object.c +752 -0
- data/ext/oj/odd.c +230 -0
- data/ext/oj/odd.h +44 -0
- data/ext/oj/oj.c +1288 -929
- data/ext/oj/oj.h +240 -69
- data/ext/oj/parse.c +1014 -0
- data/ext/oj/parse.h +92 -0
- data/ext/oj/reader.c +223 -0
- data/ext/oj/reader.h +151 -0
- data/ext/oj/resolve.c +127 -0
- data/ext/oj/{cache.h → resolve.h} +6 -13
- data/ext/oj/rxclass.c +133 -0
- data/ext/oj/rxclass.h +27 -0
- data/ext/oj/saj.c +77 -175
- data/ext/oj/scp.c +224 -0
- data/ext/oj/sparse.c +911 -0
- data/ext/oj/stream_writer.c +301 -0
- data/ext/oj/strict.c +162 -0
- data/ext/oj/string_writer.c +480 -0
- data/ext/oj/val_stack.c +98 -0
- data/ext/oj/val_stack.h +188 -0
- data/lib/oj/active_support_helper.rb +41 -0
- data/lib/oj/bag.rb +6 -10
- data/lib/oj/easy_hash.rb +52 -0
- data/lib/oj/json.rb +172 -0
- data/lib/oj/mimic.rb +260 -5
- data/lib/oj/saj.rb +13 -10
- data/lib/oj/schandler.rb +142 -0
- data/lib/oj/state.rb +131 -0
- data/lib/oj/version.rb +1 -1
- data/lib/oj.rb +11 -23
- data/pages/Advanced.md +22 -0
- data/pages/Compatibility.md +25 -0
- data/pages/Custom.md +23 -0
- data/pages/Encoding.md +65 -0
- data/pages/JsonGem.md +79 -0
- data/pages/Modes.md +140 -0
- data/pages/Options.md +250 -0
- data/pages/Rails.md +60 -0
- data/pages/Security.md +20 -0
- data/test/_test_active.rb +76 -0
- data/test/_test_active_mimic.rb +96 -0
- data/test/_test_mimic_rails.rb +126 -0
- data/test/activesupport4/decoding_test.rb +105 -0
- data/test/activesupport4/encoding_test.rb +531 -0
- data/test/activesupport4/test_helper.rb +41 -0
- data/test/activesupport5/decoding_test.rb +125 -0
- data/test/activesupport5/encoding_test.rb +483 -0
- data/test/activesupport5/encoding_test_cases.rb +90 -0
- data/test/activesupport5/test_helper.rb +50 -0
- data/test/activesupport5/time_zone_test_helpers.rb +24 -0
- data/test/helper.rb +27 -0
- data/test/isolated/shared.rb +310 -0
- data/test/isolated/test_mimic_after.rb +13 -0
- data/test/isolated/test_mimic_alone.rb +12 -0
- data/test/isolated/test_mimic_as_json.rb +45 -0
- data/test/isolated/test_mimic_before.rb +13 -0
- data/test/isolated/test_mimic_define.rb +28 -0
- data/test/isolated/test_mimic_rails_after.rb +22 -0
- data/test/isolated/test_mimic_rails_before.rb +21 -0
- data/test/isolated/test_mimic_redefine.rb +15 -0
- data/test/json_gem/json_addition_test.rb +216 -0
- data/test/json_gem/json_common_interface_test.rb +143 -0
- data/test/json_gem/json_encoding_test.rb +109 -0
- data/test/json_gem/json_ext_parser_test.rb +20 -0
- data/test/json_gem/json_fixtures_test.rb +35 -0
- data/test/json_gem/json_generator_test.rb +383 -0
- data/test/json_gem/json_generic_object_test.rb +90 -0
- data/test/json_gem/json_parser_test.rb +470 -0
- data/test/json_gem/json_string_matching_test.rb +42 -0
- data/test/json_gem/test_helper.rb +18 -0
- data/test/perf_compat.rb +130 -0
- data/test/perf_fast.rb +9 -9
- data/test/perf_file.rb +64 -0
- data/test/{perf_obj.rb → perf_object.rb} +24 -10
- data/test/perf_scp.rb +151 -0
- data/test/perf_strict.rb +32 -113
- data/test/sample.rb +2 -3
- data/test/test_compat.rb +474 -0
- data/test/test_custom.rb +355 -0
- data/test/test_debian.rb +53 -0
- data/test/test_fast.rb +66 -16
- data/test/test_file.rb +237 -0
- data/test/test_gc.rb +49 -0
- data/test/test_hash.rb +29 -0
- data/test/test_null.rb +376 -0
- data/test/test_object.rb +1010 -0
- data/test/test_saj.rb +16 -16
- data/test/test_scp.rb +417 -0
- data/test/test_strict.rb +410 -0
- data/test/test_various.rb +815 -0
- data/test/test_writer.rb +308 -0
- data/test/tests.rb +9 -902
- data/test/tests_mimic.rb +14 -0
- data/test/tests_mimic_addition.rb +7 -0
- metadata +253 -38
- data/ext/oj/cache.c +0 -148
- data/ext/oj/foo.rb +0 -6
- data/ext/oj/load.c +0 -1049
- data/test/a.rb +0 -38
- data/test/perf1.rb +0 -64
- data/test/perf2.rb +0 -76
- data/test/perf_obj_old.rb +0 -213
- data/test/test_mimic.rb +0 -208
data/ext/oj/fast.c
CHANGED
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
#include <errno.h>
|
|
39
39
|
|
|
40
40
|
#include "oj.h"
|
|
41
|
+
#include "encode.h"
|
|
41
42
|
|
|
42
43
|
// maximum to allocate on the stack, arbitrary limit
|
|
43
44
|
#define SMALL_XML 65536
|
|
@@ -146,23 +147,6 @@ next_non_white(ParseInfo pi) {
|
|
|
146
147
|
}
|
|
147
148
|
}
|
|
148
149
|
|
|
149
|
-
inline static void
|
|
150
|
-
next_white(ParseInfo pi) {
|
|
151
|
-
for (; 1; pi->s++) {
|
|
152
|
-
switch(*pi->s) {
|
|
153
|
-
case ' ':
|
|
154
|
-
case '\t':
|
|
155
|
-
case '\f':
|
|
156
|
-
case '\n':
|
|
157
|
-
case '\r':
|
|
158
|
-
case '\0':
|
|
159
|
-
return;
|
|
160
|
-
default:
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
150
|
inline static char*
|
|
167
151
|
ulong_fill(char *s, size_t num) {
|
|
168
152
|
char buf[32];
|
|
@@ -186,7 +170,7 @@ ulong_fill(char *s, size_t num) {
|
|
|
186
170
|
inline static void
|
|
187
171
|
leaf_init(Leaf leaf, int type) {
|
|
188
172
|
leaf->next = 0;
|
|
189
|
-
leaf->
|
|
173
|
+
leaf->rtype = type;
|
|
190
174
|
leaf->parent_type = T_NONE;
|
|
191
175
|
switch (type) {
|
|
192
176
|
case T_ARRAY:
|
|
@@ -222,6 +206,8 @@ leaf_new(Doc doc, int type) {
|
|
|
222
206
|
if (0 == doc->batches || BATCH_SIZE == doc->batches->next_avail) {
|
|
223
207
|
Batch b = ALLOC(struct _Batch);
|
|
224
208
|
|
|
209
|
+
// Initializes all leaves with a NO_VAL value_type
|
|
210
|
+
memset(b, 0, sizeof(struct _Batch));
|
|
225
211
|
b->next = doc->batches;
|
|
226
212
|
doc->batches = b;
|
|
227
213
|
b->next_avail = 0;
|
|
@@ -248,7 +234,7 @@ leaf_append_element(Leaf parent, Leaf element) {
|
|
|
248
234
|
static VALUE
|
|
249
235
|
leaf_value(Doc doc, Leaf leaf) {
|
|
250
236
|
if (RUBY_VAL != leaf->value_type) {
|
|
251
|
-
switch (leaf->
|
|
237
|
+
switch (leaf->rtype) {
|
|
252
238
|
case T_NIL:
|
|
253
239
|
leaf->value = Qnil;
|
|
254
240
|
break;
|
|
@@ -266,9 +252,7 @@ leaf_value(Doc doc, Leaf leaf) {
|
|
|
266
252
|
break;
|
|
267
253
|
case T_STRING:
|
|
268
254
|
leaf->value = rb_str_new2(leaf->str);
|
|
269
|
-
|
|
270
|
-
rb_enc_associate(leaf->value, oj_utf8_encoding);
|
|
271
|
-
#endif
|
|
255
|
+
leaf->value = oj_encode(leaf->value);
|
|
272
256
|
leaf->value_type = RUBY_VAL;
|
|
273
257
|
break;
|
|
274
258
|
case T_ARRAY:
|
|
@@ -278,7 +262,7 @@ leaf_value(Doc doc, Leaf leaf) {
|
|
|
278
262
|
return leaf_hash_value(doc, leaf);
|
|
279
263
|
break;
|
|
280
264
|
default:
|
|
281
|
-
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);
|
|
282
266
|
break;
|
|
283
267
|
}
|
|
284
268
|
}
|
|
@@ -361,84 +345,16 @@ leaf_fixnum_value(Leaf leaf) {
|
|
|
361
345
|
if (neg) {
|
|
362
346
|
n = -n;
|
|
363
347
|
}
|
|
364
|
-
leaf->value =
|
|
348
|
+
leaf->value = rb_ll2inum(n);
|
|
365
349
|
}
|
|
366
350
|
leaf->value_type = RUBY_VAL;
|
|
367
351
|
}
|
|
368
352
|
|
|
369
|
-
#ifdef JRUBY_RUBY
|
|
370
|
-
static void
|
|
371
|
-
leaf_float_value(Leaf leaf) {
|
|
372
|
-
char *s = leaf->str;
|
|
373
|
-
int64_t n = 0;
|
|
374
|
-
long a = 0;
|
|
375
|
-
long div = 1;
|
|
376
|
-
long e = 0;
|
|
377
|
-
int neg = 0;
|
|
378
|
-
int eneg = 0;
|
|
379
|
-
int big = 0;
|
|
380
|
-
|
|
381
|
-
if ('-' == *s) {
|
|
382
|
-
s++;
|
|
383
|
-
neg = 1;
|
|
384
|
-
} else if ('+' == *s) {
|
|
385
|
-
s++;
|
|
386
|
-
}
|
|
387
|
-
for (; '0' <= *s && *s <= '9'; s++) {
|
|
388
|
-
n = n * 10 + (*s - '0');
|
|
389
|
-
if (NUM_MAX <= n) {
|
|
390
|
-
big = 1;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
if (big) {
|
|
394
|
-
char c = *s;
|
|
395
|
-
|
|
396
|
-
*s = '\0';
|
|
397
|
-
leaf->value = rb_cstr_to_inum(leaf->str, 10, 0);
|
|
398
|
-
*s = c;
|
|
399
|
-
} else {
|
|
400
|
-
double d;
|
|
401
|
-
|
|
402
|
-
if ('.' == *s) {
|
|
403
|
-
s++;
|
|
404
|
-
for (; '0' <= *s && *s <= '9'; s++) {
|
|
405
|
-
a = a * 10 + (*s - '0');
|
|
406
|
-
div *= 10;
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
if ('e' == *s || 'E' == *s) {
|
|
410
|
-
s++;
|
|
411
|
-
if ('-' == *s) {
|
|
412
|
-
s++;
|
|
413
|
-
eneg = 1;
|
|
414
|
-
} else if ('+' == *s) {
|
|
415
|
-
s++;
|
|
416
|
-
}
|
|
417
|
-
for (; '0' <= *s && *s <= '9'; s++) {
|
|
418
|
-
e = e * 10 + (*s - '0');
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
d = (double)n + (double)a / (double)div;
|
|
422
|
-
if (neg) {
|
|
423
|
-
d = -d;
|
|
424
|
-
}
|
|
425
|
-
if (0 != e) {
|
|
426
|
-
if (eneg) {
|
|
427
|
-
e = -e;
|
|
428
|
-
}
|
|
429
|
-
d *= pow(10.0, e);
|
|
430
|
-
}
|
|
431
|
-
leaf->value = rb_float_new(d);
|
|
432
|
-
}
|
|
433
|
-
leaf->value_type = RUBY_VAL;
|
|
434
|
-
}
|
|
435
|
-
#else
|
|
436
353
|
static void
|
|
437
354
|
leaf_float_value(Leaf leaf) {
|
|
438
355
|
leaf->value = rb_float_new(rb_cstr_to_dbl(leaf->str, 1));
|
|
439
356
|
leaf->value_type = RUBY_VAL;
|
|
440
357
|
}
|
|
441
|
-
#endif
|
|
442
358
|
|
|
443
359
|
static VALUE
|
|
444
360
|
leaf_array_value(Doc doc, Leaf leaf) {
|
|
@@ -467,9 +383,7 @@ leaf_hash_value(Doc doc, Leaf leaf) {
|
|
|
467
383
|
|
|
468
384
|
do {
|
|
469
385
|
key = rb_str_new2(e->key);
|
|
470
|
-
|
|
471
|
-
rb_enc_associate(key, oj_utf8_encoding);
|
|
472
|
-
#endif
|
|
386
|
+
key = oj_encode(key);
|
|
473
387
|
rb_hash_aset(h, key, leaf_value(doc, e));
|
|
474
388
|
e = e->next;
|
|
475
389
|
} while (e != first);
|
|
@@ -695,33 +609,59 @@ read_nil(ParseInfo pi) {
|
|
|
695
609
|
return leaf;
|
|
696
610
|
}
|
|
697
611
|
|
|
698
|
-
static
|
|
699
|
-
|
|
700
|
-
|
|
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
|
+
}
|
|
701
631
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
} else if (
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
} else if (
|
|
719
|
-
|
|
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);
|
|
720
661
|
} else {
|
|
721
|
-
pi->s
|
|
722
|
-
raise_error("invalid hex character", pi->str, pi->s);
|
|
662
|
+
raise_error("invalid Unicode character", pi->str, pi->s);
|
|
723
663
|
}
|
|
724
|
-
return
|
|
664
|
+
return t;
|
|
725
665
|
}
|
|
726
666
|
|
|
727
667
|
/* Assume the value starts immediately and goes until the quote character is
|
|
@@ -751,16 +691,31 @@ read_quoted_value(ParseInfo pi) {
|
|
|
751
691
|
case '"': *t = '"'; break;
|
|
752
692
|
case '/': *t = '/'; break;
|
|
753
693
|
case '\\': *t = '\\'; break;
|
|
754
|
-
case 'u':
|
|
694
|
+
case 'u': {
|
|
695
|
+
uint32_t code;
|
|
696
|
+
|
|
755
697
|
h++;
|
|
756
|
-
|
|
757
|
-
h +=
|
|
758
|
-
if (
|
|
759
|
-
|
|
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;
|
|
760
714
|
}
|
|
761
|
-
|
|
762
|
-
|
|
715
|
+
t = unicode_to_chars(pi, t, code);
|
|
716
|
+
t--;
|
|
763
717
|
break;
|
|
718
|
+
}
|
|
764
719
|
default:
|
|
765
720
|
pi->s = h;
|
|
766
721
|
raise_error("invalid escaped character", pi->str, pi->s);
|
|
@@ -779,15 +734,10 @@ read_quoted_value(ParseInfo pi) {
|
|
|
779
734
|
// doc support functions
|
|
780
735
|
inline static void
|
|
781
736
|
doc_init(Doc doc) {
|
|
737
|
+
memset(doc, 0, sizeof(struct _Doc));
|
|
782
738
|
doc->where = doc->where_path;
|
|
783
|
-
*doc->where = 0;
|
|
784
|
-
doc->data = 0;
|
|
785
739
|
doc->self = Qundef;
|
|
786
|
-
doc->size = 0;
|
|
787
|
-
doc->json = 0;
|
|
788
740
|
doc->batches = &doc->batch0;
|
|
789
|
-
doc->batch0.next = 0;
|
|
790
|
-
doc->batch0.next_avail = 0;
|
|
791
741
|
}
|
|
792
742
|
|
|
793
743
|
static void
|
|
@@ -863,7 +813,11 @@ parse_json(VALUE clas, char *json, int given, int allocated) {
|
|
|
863
813
|
}
|
|
864
814
|
#endif
|
|
865
815
|
// last arg is free func void* func(void*)
|
|
816
|
+
#if HAS_DATA_OBJECT_WRAP
|
|
817
|
+
doc->self = rb_data_object_wrap(clas, doc, 0, free_doc_cb);
|
|
818
|
+
#else
|
|
866
819
|
doc->self = rb_data_object_alloc(clas, doc, 0, free_doc_cb);
|
|
820
|
+
#endif
|
|
867
821
|
rb_gc_register_address(&doc->self);
|
|
868
822
|
doc->json = json;
|
|
869
823
|
DATA_PTR(doc->self) = doc;
|
|
@@ -902,7 +856,10 @@ get_doc_leaf(Doc doc, const char *path) {
|
|
|
902
856
|
} else {
|
|
903
857
|
size_t cnt = doc->where - doc->where_path;
|
|
904
858
|
|
|
905
|
-
|
|
859
|
+
if (MAX_STACK <= cnt) {
|
|
860
|
+
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
|
861
|
+
}
|
|
862
|
+
memcpy(stack, doc->where_path, sizeof(Leaf) * (cnt + 1));
|
|
906
863
|
lp = stack + cnt;
|
|
907
864
|
}
|
|
908
865
|
return get_leaf(stack, lp, path);
|
|
@@ -910,6 +867,35 @@ get_doc_leaf(Doc doc, const char *path) {
|
|
|
910
867
|
return leaf;
|
|
911
868
|
}
|
|
912
869
|
|
|
870
|
+
static const char*
|
|
871
|
+
next_slash(const char *s) {
|
|
872
|
+
for (; '\0' != *s; s++) {
|
|
873
|
+
if ('\\' == *s) {
|
|
874
|
+
s++;
|
|
875
|
+
if ('\0' == *s) {
|
|
876
|
+
break;
|
|
877
|
+
}
|
|
878
|
+
} else if ('/' == *s) {
|
|
879
|
+
return s;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
return NULL;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
static bool
|
|
886
|
+
key_match(const char *pat, const char *key, int plen) {
|
|
887
|
+
for (; 0 < plen; plen--, pat++, key++) {
|
|
888
|
+
if ('\\' == *pat) {
|
|
889
|
+
plen--;
|
|
890
|
+
pat++;
|
|
891
|
+
}
|
|
892
|
+
if (*pat != *key) {
|
|
893
|
+
return false;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
return '\0' == *key;
|
|
897
|
+
}
|
|
898
|
+
|
|
913
899
|
static Leaf
|
|
914
900
|
get_leaf(Leaf *stack, Leaf *lp, const char *path) {
|
|
915
901
|
Leaf leaf = *lp;
|
|
@@ -931,7 +917,7 @@ get_leaf(Leaf *stack, Leaf *lp, const char *path) {
|
|
|
931
917
|
} else if (COL_VAL == leaf->value_type && 0 != leaf->elements) {
|
|
932
918
|
Leaf first = leaf->elements->next;
|
|
933
919
|
Leaf e = first;
|
|
934
|
-
int type = leaf->
|
|
920
|
+
int type = leaf->rtype;
|
|
935
921
|
|
|
936
922
|
leaf = 0;
|
|
937
923
|
if (T_ARRAY == type) {
|
|
@@ -955,7 +941,7 @@ get_leaf(Leaf *stack, Leaf *lp, const char *path) {
|
|
|
955
941
|
} while (e != first);
|
|
956
942
|
} else if (T_HASH == type) {
|
|
957
943
|
const char *key = path;
|
|
958
|
-
const char *slash =
|
|
944
|
+
const char *slash = next_slash(path);
|
|
959
945
|
int klen;
|
|
960
946
|
|
|
961
947
|
if (0 == slash) {
|
|
@@ -966,7 +952,7 @@ get_leaf(Leaf *stack, Leaf *lp, const char *path) {
|
|
|
966
952
|
path += klen + 1;
|
|
967
953
|
}
|
|
968
954
|
do {
|
|
969
|
-
if (
|
|
955
|
+
if (key_match(key, e->key, klen)) {
|
|
970
956
|
lp++;
|
|
971
957
|
*lp = e;
|
|
972
958
|
leaf = get_leaf(stack, lp, path);
|
|
@@ -988,11 +974,15 @@ each_leaf(Doc doc, VALUE self) {
|
|
|
988
974
|
Leaf e = first;
|
|
989
975
|
|
|
990
976
|
doc->where++;
|
|
977
|
+
if (MAX_STACK <= doc->where - doc->where_path) {
|
|
978
|
+
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
|
979
|
+
}
|
|
991
980
|
do {
|
|
992
981
|
*doc->where = e;
|
|
993
982
|
each_leaf(doc, self);
|
|
994
983
|
e = e->next;
|
|
995
984
|
} while (e != first);
|
|
985
|
+
doc->where--;
|
|
996
986
|
}
|
|
997
987
|
} else {
|
|
998
988
|
rb_yield(self);
|
|
@@ -1034,7 +1024,7 @@ move_step(Doc doc, const char *path, int loc) {
|
|
|
1034
1024
|
Leaf first = leaf->elements->next;
|
|
1035
1025
|
Leaf e = first;
|
|
1036
1026
|
|
|
1037
|
-
if (T_ARRAY == leaf->
|
|
1027
|
+
if (T_ARRAY == leaf->rtype) {
|
|
1038
1028
|
int cnt = 0;
|
|
1039
1029
|
|
|
1040
1030
|
for (; '0' <= *path && *path <= '9'; path++) {
|
|
@@ -1059,9 +1049,9 @@ move_step(Doc doc, const char *path, int loc) {
|
|
|
1059
1049
|
cnt--;
|
|
1060
1050
|
e = e->next;
|
|
1061
1051
|
} while (e != first);
|
|
1062
|
-
} else if (T_HASH == leaf->
|
|
1052
|
+
} else if (T_HASH == leaf->rtype) {
|
|
1063
1053
|
const char *key = path;
|
|
1064
|
-
const char *slash =
|
|
1054
|
+
const char *slash = next_slash(path);
|
|
1065
1055
|
int klen;
|
|
1066
1056
|
|
|
1067
1057
|
if (0 == slash) {
|
|
@@ -1072,7 +1062,7 @@ move_step(Doc doc, const char *path, int loc) {
|
|
|
1072
1062
|
path += klen + 1;
|
|
1073
1063
|
}
|
|
1074
1064
|
do {
|
|
1075
|
-
if (
|
|
1065
|
+
if (key_match(key, e->key, klen)) {
|
|
1076
1066
|
doc->where++;
|
|
1077
1067
|
*doc->where = e;
|
|
1078
1068
|
loc = move_step(doc, path, loc + 1);
|
|
@@ -1109,14 +1099,14 @@ each_value(Doc doc, Leaf leaf) {
|
|
|
1109
1099
|
|
|
1110
1100
|
// doc functions
|
|
1111
1101
|
|
|
1112
|
-
/*
|
|
1102
|
+
/* @overload open(json) { |doc| ... } => Object
|
|
1113
1103
|
*
|
|
1114
1104
|
* Parses a JSON document String and then yields to the provided block if one
|
|
1115
1105
|
* is given with an instance of the Oj::Doc as the single yield parameter. If
|
|
1116
1106
|
* a block is not given then an Oj::Doc instance is returned and must be
|
|
1117
1107
|
* closed with a call to the #close() method when no longer needed.
|
|
1118
1108
|
*
|
|
1119
|
-
*
|
|
1109
|
+
* @param [String] json JSON document string
|
|
1120
1110
|
* @yieldparam [Oj::Doc] doc parsed JSON document
|
|
1121
1111
|
* @yieldreturn [Object] returns the result of the yield as the result of the method call
|
|
1122
1112
|
* @example
|
|
@@ -1150,14 +1140,14 @@ doc_open(VALUE clas, VALUE str) {
|
|
|
1150
1140
|
return obj;
|
|
1151
1141
|
}
|
|
1152
1142
|
|
|
1153
|
-
/*
|
|
1143
|
+
/* @overload open_file(filename) { |doc| ... } => Object
|
|
1154
1144
|
*
|
|
1155
1145
|
* Parses a JSON document from a file and then yields to the provided block if
|
|
1156
1146
|
* one is given with an instance of the Oj::Doc as the single yield
|
|
1157
1147
|
* parameter. If a block is not given then an Oj::Doc instance is returned and
|
|
1158
1148
|
* must be closed with a call to the #close() method when no longer needed.
|
|
1159
1149
|
*
|
|
1160
|
-
*
|
|
1150
|
+
* @param [String] filename name of file that contains a JSON document
|
|
1161
1151
|
* @yieldparam [Oj::Doc] doc parsed JSON document
|
|
1162
1152
|
* @yieldreturn [Object] returns the result of the yield as the result of the method call
|
|
1163
1153
|
* @example
|
|
@@ -1206,11 +1196,34 @@ doc_open_file(VALUE clas, VALUE filename) {
|
|
|
1206
1196
|
return obj;
|
|
1207
1197
|
}
|
|
1208
1198
|
|
|
1199
|
+
static int
|
|
1200
|
+
esc_strlen(const char *s) {
|
|
1201
|
+
int cnt = 0;
|
|
1202
|
+
|
|
1203
|
+
for (; '\0' != *s; s++, cnt++) {
|
|
1204
|
+
if ('/' == *s) {
|
|
1205
|
+
cnt++;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
return cnt;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
static char*
|
|
1212
|
+
append_key(char *p, const char *key) {
|
|
1213
|
+
for (; '\0' != *key; p++, key++) {
|
|
1214
|
+
if ('/' == *key) {
|
|
1215
|
+
*p++ = '\\';
|
|
1216
|
+
}
|
|
1217
|
+
*p = *key;
|
|
1218
|
+
}
|
|
1219
|
+
return p;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1209
1222
|
/* Document-method: parse
|
|
1210
1223
|
* @see Oj::Doc.open
|
|
1211
1224
|
*/
|
|
1212
1225
|
|
|
1213
|
-
/*
|
|
1226
|
+
/* @overload where?() => String
|
|
1214
1227
|
*
|
|
1215
1228
|
* Returns a String that describes the absolute path to the current location
|
|
1216
1229
|
* in the JSON document.
|
|
@@ -1231,7 +1244,7 @@ doc_where(VALUE self) {
|
|
|
1231
1244
|
for (lp = doc->where_path; lp <= doc->where; lp++) {
|
|
1232
1245
|
leaf = *lp;
|
|
1233
1246
|
if (T_HASH == leaf->parent_type) {
|
|
1234
|
-
size +=
|
|
1247
|
+
size += esc_strlen((*lp)->key) + 1;
|
|
1235
1248
|
} else if (T_ARRAY == leaf->parent_type) {
|
|
1236
1249
|
size += ((*lp)->index < 100) ? 3 : 11;
|
|
1237
1250
|
}
|
|
@@ -1241,7 +1254,7 @@ doc_where(VALUE self) {
|
|
|
1241
1254
|
for (lp = doc->where_path; lp <= doc->where; lp++) {
|
|
1242
1255
|
leaf = *lp;
|
|
1243
1256
|
if (T_HASH == leaf->parent_type) {
|
|
1244
|
-
p =
|
|
1257
|
+
p = append_key(p, (*lp)->key);
|
|
1245
1258
|
} else if (T_ARRAY == leaf->parent_type) {
|
|
1246
1259
|
p = ulong_fill(p, (*lp)->index);
|
|
1247
1260
|
}
|
|
@@ -1252,7 +1265,7 @@ doc_where(VALUE self) {
|
|
|
1252
1265
|
}
|
|
1253
1266
|
}
|
|
1254
1267
|
|
|
1255
|
-
/*
|
|
1268
|
+
/* @overload local_key() => String, Fixnum, nil
|
|
1256
1269
|
*
|
|
1257
1270
|
* Returns the final key to the current location.
|
|
1258
1271
|
* @example
|
|
@@ -1268,16 +1281,14 @@ doc_local_key(VALUE self) {
|
|
|
1268
1281
|
|
|
1269
1282
|
if (T_HASH == leaf->parent_type) {
|
|
1270
1283
|
key = rb_str_new2(leaf->key);
|
|
1271
|
-
|
|
1272
|
-
rb_enc_associate(key, oj_utf8_encoding);
|
|
1273
|
-
#endif
|
|
1284
|
+
key = oj_encode(key);
|
|
1274
1285
|
} else if (T_ARRAY == leaf->parent_type) {
|
|
1275
1286
|
key = LONG2NUM(leaf->index);
|
|
1276
1287
|
}
|
|
1277
1288
|
return key;
|
|
1278
1289
|
}
|
|
1279
1290
|
|
|
1280
|
-
/*
|
|
1291
|
+
/* @overload home() => nil
|
|
1281
1292
|
*
|
|
1282
1293
|
* Moves the document marker or location to the hoot or home position. The
|
|
1283
1294
|
* same operation can be performed with a Oj::Doc.move('/').
|
|
@@ -1294,13 +1305,13 @@ doc_home(VALUE self) {
|
|
|
1294
1305
|
return oj_slash_string;
|
|
1295
1306
|
}
|
|
1296
1307
|
|
|
1297
|
-
/*
|
|
1308
|
+
/* @overload type(path=nil) => Class
|
|
1298
1309
|
*
|
|
1299
1310
|
* Returns the Class of the data value at the location identified by the path
|
|
1300
1311
|
* or the current location if the path is nil or not provided. This method
|
|
1301
1312
|
* does not create the Ruby Object at the location specified so the overhead
|
|
1302
1313
|
* is low.
|
|
1303
|
-
*
|
|
1314
|
+
* @param [String] path path to the location to get the type of if provided
|
|
1304
1315
|
* @example
|
|
1305
1316
|
* Oj::Doc.open('[1,2]') { |doc| doc.type() } #=> Array
|
|
1306
1317
|
* Oj::Doc.open('[1,2]') { |doc| doc.type('/1') } #=> Fixnum
|
|
@@ -1317,12 +1328,16 @@ doc_type(int argc, VALUE *argv, VALUE self) {
|
|
|
1317
1328
|
path = StringValuePtr(*argv);
|
|
1318
1329
|
}
|
|
1319
1330
|
if (0 != (leaf = get_doc_leaf(doc, path))) {
|
|
1320
|
-
switch (leaf->
|
|
1331
|
+
switch (leaf->rtype) {
|
|
1321
1332
|
case T_NIL: type = rb_cNilClass; break;
|
|
1322
1333
|
case T_TRUE: type = rb_cTrueClass; break;
|
|
1323
1334
|
case T_FALSE: type = rb_cFalseClass; break;
|
|
1324
1335
|
case T_STRING: type = rb_cString; break;
|
|
1336
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
|
1337
|
+
case T_FIXNUM: type = rb_cInteger; break;
|
|
1338
|
+
#else
|
|
1325
1339
|
case T_FIXNUM: type = rb_cFixnum; break;
|
|
1340
|
+
#endif
|
|
1326
1341
|
case T_FLOAT: type = rb_cFloat; break;
|
|
1327
1342
|
case T_ARRAY: type = rb_cArray; break;
|
|
1328
1343
|
case T_HASH: type = rb_cHash; break;
|
|
@@ -1332,14 +1347,14 @@ doc_type(int argc, VALUE *argv, VALUE self) {
|
|
|
1332
1347
|
return type;
|
|
1333
1348
|
}
|
|
1334
1349
|
|
|
1335
|
-
/*
|
|
1350
|
+
/* @overload fetch(path=nil) => nil, true, false, Fixnum, Float, String, Array, Hash
|
|
1336
1351
|
*
|
|
1337
1352
|
* Returns the value at the location identified by the path or the current
|
|
1338
1353
|
* location if the path is nil or not provided. This method will create and
|
|
1339
1354
|
* return an Array or Hash if that is the type of Object at the location
|
|
1340
1355
|
* specified. This is more expensive than navigating to the leaves of the JSON
|
|
1341
1356
|
* document.
|
|
1342
|
-
*
|
|
1357
|
+
* @param [String] path path to the location to get the type of if provided
|
|
1343
1358
|
* @example
|
|
1344
1359
|
* Oj::Doc.open('[1,2]') { |doc| doc.fetch() } #=> [1, 2]
|
|
1345
1360
|
* Oj::Doc.open('[1,2]') { |doc| doc.fetch('/1') } #=> 1
|
|
@@ -1365,12 +1380,12 @@ doc_fetch(int argc, VALUE *argv, VALUE self) {
|
|
|
1365
1380
|
return val;
|
|
1366
1381
|
}
|
|
1367
1382
|
|
|
1368
|
-
/*
|
|
1383
|
+
/* @overload each_leaf(path=nil) => nil
|
|
1369
1384
|
*
|
|
1370
1385
|
* Yields to the provided block for each leaf node with the identified
|
|
1371
1386
|
* location of the JSON document as the root. The parameter passed to the
|
|
1372
1387
|
* block on yield is the Doc instance after moving to the child location.
|
|
1373
|
-
*
|
|
1388
|
+
* @param [String] path if provided it identified the top of the branch to process the leaves of
|
|
1374
1389
|
* @yieldparam [Doc] Doc at the child location
|
|
1375
1390
|
* @example
|
|
1376
1391
|
* Oj::Doc.open('[3,[2,1]]') { |doc|
|
|
@@ -1390,7 +1405,7 @@ doc_each_leaf(int argc, VALUE *argv, VALUE self) {
|
|
|
1390
1405
|
|
|
1391
1406
|
wlen = doc->where - doc->where_path;
|
|
1392
1407
|
if (0 < wlen) {
|
|
1393
|
-
memcpy(save_path, doc->where_path, sizeof(Leaf) * wlen);
|
|
1408
|
+
memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
|
|
1394
1409
|
}
|
|
1395
1410
|
if (1 <= argc) {
|
|
1396
1411
|
Check_Type(*argv, T_STRING);
|
|
@@ -1401,24 +1416,24 @@ doc_each_leaf(int argc, VALUE *argv, VALUE self) {
|
|
|
1401
1416
|
}
|
|
1402
1417
|
if (0 != move_step(doc, path, 1)) {
|
|
1403
1418
|
if (0 < wlen) {
|
|
1404
|
-
memcpy(doc->where_path, save_path, sizeof(Leaf) * wlen);
|
|
1419
|
+
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
|
1405
1420
|
}
|
|
1406
1421
|
return Qnil;
|
|
1407
1422
|
}
|
|
1408
1423
|
}
|
|
1409
1424
|
each_leaf(doc, self);
|
|
1410
1425
|
if (0 < wlen) {
|
|
1411
|
-
memcpy(doc->where_path, save_path, sizeof(Leaf) * wlen);
|
|
1426
|
+
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
|
1412
1427
|
}
|
|
1413
1428
|
}
|
|
1414
1429
|
return Qnil;
|
|
1415
1430
|
}
|
|
1416
1431
|
|
|
1417
|
-
/*
|
|
1432
|
+
/* @overload move(path) => nil
|
|
1418
1433
|
*
|
|
1419
1434
|
* Moves the document marker to the path specified. The path can an absolute
|
|
1420
1435
|
* path or a relative path.
|
|
1421
|
-
*
|
|
1436
|
+
* @param [String] path path to the location to move to
|
|
1422
1437
|
* @example
|
|
1423
1438
|
* Oj::Doc.open('{"one":[1,2]') { |doc| doc.move('/one/2'); doc.where? } #=> "/one/2"
|
|
1424
1439
|
*/
|
|
@@ -1440,13 +1455,13 @@ doc_move(VALUE self, VALUE str) {
|
|
|
1440
1455
|
return Qnil;
|
|
1441
1456
|
}
|
|
1442
1457
|
|
|
1443
|
-
/*
|
|
1458
|
+
/* @overload each_child(path=nil) { |doc| ... } => nil
|
|
1444
1459
|
*
|
|
1445
1460
|
* Yields to the provided block for each immediate child node with the
|
|
1446
1461
|
* identified location of the JSON document as the root. The parameter passed
|
|
1447
1462
|
* to the block on yield is the Doc instance after moving to the child
|
|
1448
1463
|
* location.
|
|
1449
|
-
*
|
|
1464
|
+
* @param [String] path if provided it identified the top of the branch to process the chilren of
|
|
1450
1465
|
* @yieldparam [Doc] Doc at the child location
|
|
1451
1466
|
* @example
|
|
1452
1467
|
* Oj::Doc.open('[3,[2,1]]') { |doc|
|
|
@@ -1466,7 +1481,7 @@ doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
|
1466
1481
|
|
|
1467
1482
|
wlen = doc->where - doc->where_path;
|
|
1468
1483
|
if (0 < wlen) {
|
|
1469
|
-
memcpy(save_path, doc->where_path, sizeof(Leaf) * wlen);
|
|
1484
|
+
memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
|
|
1470
1485
|
}
|
|
1471
1486
|
if (1 <= argc) {
|
|
1472
1487
|
Check_Type(*argv, T_STRING);
|
|
@@ -1477,7 +1492,7 @@ doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
|
1477
1492
|
}
|
|
1478
1493
|
if (0 != move_step(doc, path, 1)) {
|
|
1479
1494
|
if (0 < wlen) {
|
|
1480
|
-
memcpy(doc->where_path, save_path, sizeof(Leaf) * wlen);
|
|
1495
|
+
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
|
1481
1496
|
}
|
|
1482
1497
|
return Qnil;
|
|
1483
1498
|
}
|
|
@@ -1494,19 +1509,19 @@ doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
|
1494
1509
|
} while (e != first);
|
|
1495
1510
|
}
|
|
1496
1511
|
if (0 < wlen) {
|
|
1497
|
-
memcpy(doc->where_path, save_path, sizeof(Leaf) * wlen);
|
|
1512
|
+
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
|
1498
1513
|
}
|
|
1499
1514
|
}
|
|
1500
1515
|
return Qnil;
|
|
1501
1516
|
}
|
|
1502
1517
|
|
|
1503
|
-
/*
|
|
1518
|
+
/* @overload each_value(path=nil) { |val| ... } => nil
|
|
1504
1519
|
*
|
|
1505
1520
|
* Yields to the provided block for each leaf value in the identified location
|
|
1506
1521
|
* of the JSON document. The parameter passed to the block on yield is the
|
|
1507
1522
|
* value of the leaf. Only those leaves below the element specified by the
|
|
1508
1523
|
* path parameter are processed.
|
|
1509
|
-
*
|
|
1524
|
+
* @param [String] path if provided it identified the top of the branch to process the leaf values of
|
|
1510
1525
|
* @yieldparam [Object] val each leaf value
|
|
1511
1526
|
* @example
|
|
1512
1527
|
* Oj::Doc.open('[3,[2,1]]') { |doc|
|
|
@@ -1541,12 +1556,12 @@ doc_each_value(int argc, VALUE *argv, VALUE self) {
|
|
|
1541
1556
|
return Qnil;
|
|
1542
1557
|
}
|
|
1543
1558
|
|
|
1544
|
-
/*
|
|
1559
|
+
/* @overload dump(path, filename)
|
|
1545
1560
|
*
|
|
1546
1561
|
* Dumps the document or nodes to a new JSON document. It uses the default
|
|
1547
1562
|
* options for generating the JSON.
|
|
1548
|
-
*
|
|
1549
|
-
*
|
|
1563
|
+
* @param path [String] if provided it identified the top of the branch to dump to JSON
|
|
1564
|
+
* @param filename [String] if provided it is the filename to write the output to
|
|
1550
1565
|
* @example
|
|
1551
1566
|
* Oj::Doc.open('[3,[2,1]]') { |doc|
|
|
1552
1567
|
* doc.dump('/2')
|
|
@@ -1571,13 +1586,21 @@ doc_dump(int argc, VALUE *argv, VALUE self) {
|
|
|
1571
1586
|
}
|
|
1572
1587
|
}
|
|
1573
1588
|
if (0 != (leaf = get_doc_leaf(doc, path))) {
|
|
1574
|
-
char *json;
|
|
1575
1589
|
VALUE rjson;
|
|
1576
1590
|
|
|
1577
1591
|
if (0 == filename) {
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1592
|
+
char buf[4096];
|
|
1593
|
+
struct _Out out;
|
|
1594
|
+
|
|
1595
|
+
out.buf = buf;
|
|
1596
|
+
out.end = buf + sizeof(buf) - 10;
|
|
1597
|
+
out.allocated = 0;
|
|
1598
|
+
out.omit_nil = oj_default_options.dump_opts.omit_nil;
|
|
1599
|
+
oj_dump_leaf_to_json(leaf, &oj_default_options, &out);
|
|
1600
|
+
rjson = rb_str_new2(out.buf);
|
|
1601
|
+
if (out.allocated) {
|
|
1602
|
+
xfree(out.buf);
|
|
1603
|
+
}
|
|
1581
1604
|
} else {
|
|
1582
1605
|
oj_write_leaf_to_file(leaf, filename, &oj_default_options);
|
|
1583
1606
|
rjson = Qnil;
|
|
@@ -1587,7 +1610,7 @@ doc_dump(int argc, VALUE *argv, VALUE self) {
|
|
|
1587
1610
|
return Qnil;
|
|
1588
1611
|
}
|
|
1589
1612
|
|
|
1590
|
-
/*
|
|
1613
|
+
/* @overload size() => Fixnum
|
|
1591
1614
|
*
|
|
1592
1615
|
* Returns the number of nodes in the JSON document where a node is any one of
|
|
1593
1616
|
* the basic JSON components.
|
|
@@ -1600,7 +1623,7 @@ doc_size(VALUE self) {
|
|
|
1600
1623
|
return ULONG2NUM(((Doc)DATA_PTR(self))->size);
|
|
1601
1624
|
}
|
|
1602
1625
|
|
|
1603
|
-
/*
|
|
1626
|
+
/* @overload close() => nil
|
|
1604
1627
|
*
|
|
1605
1628
|
* Closes an open document. No further calls to the document will be valid
|
|
1606
1629
|
* after closing.
|
|
@@ -1618,6 +1641,7 @@ doc_close(VALUE self) {
|
|
|
1618
1641
|
if (0 != doc) {
|
|
1619
1642
|
xfree(doc->json);
|
|
1620
1643
|
doc_free(doc);
|
|
1644
|
+
xfree(doc);
|
|
1621
1645
|
}
|
|
1622
1646
|
return Qnil;
|
|
1623
1647
|
}
|
|
@@ -1626,6 +1650,12 @@ doc_close(VALUE self) {
|
|
|
1626
1650
|
Oj = rb_define_module("Oj");
|
|
1627
1651
|
#endif
|
|
1628
1652
|
|
|
1653
|
+
static VALUE
|
|
1654
|
+
doc_not_implemented(VALUE self) {
|
|
1655
|
+
rb_raise(rb_eNotImpError, "Not implemented.");
|
|
1656
|
+
return Qnil;
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1629
1659
|
/* Document-class: Oj::Doc
|
|
1630
1660
|
*
|
|
1631
1661
|
* The Doc class is used to parse and navigate a JSON document. The model it
|
|
@@ -1690,4 +1720,7 @@ oj_init_doc() {
|
|
|
1690
1720
|
rb_define_method(oj_doc_class, "dump", doc_dump, -1);
|
|
1691
1721
|
rb_define_method(oj_doc_class, "size", doc_size, 0);
|
|
1692
1722
|
rb_define_method(oj_doc_class, "close", doc_close, 0);
|
|
1723
|
+
|
|
1724
|
+
rb_define_method(oj_doc_class, "clone", doc_not_implemented, 0);
|
|
1725
|
+
rb_define_method(oj_doc_class, "dup", doc_not_implemented, 0);
|
|
1693
1726
|
}
|