oj 2.3.0 → 2.4.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.
- checksums.yaml +4 -4
- data/README.md +8 -0
- data/ext/oj/compat.c +4 -4
- data/ext/oj/dump.c +19 -24
- data/ext/oj/hash.c +20 -17
- data/ext/oj/hash_test.c +8 -8
- data/ext/oj/object.c +3 -3
- data/ext/oj/oj.c +258 -27
- data/ext/oj/oj.h +16 -3
- data/ext/oj/parse.c +6 -1
- data/ext/oj/parse.h +2 -1
- data/ext/oj/strict.c +3 -3
- data/lib/oj/version.rb +1 -1
- data/test/debian_test.rb +90 -0
- data/test/test_writer.rb +51 -13
- data/test/tests.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 873b6fade9db8e2c3e82c5a6329c4ceb09215d6d
|
4
|
+
data.tar.gz: 4f8074a9a5ac20d567c58d002323949fc08828ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f82b5aedde38474ca0ddd6826f11ed4fa02bf17fbcf6a56ba14dca772c9e3000119d15d81c092f4dae9000a7dec6ca2c1a7c971a2b854a54d68a50586ab8f2d4
|
7
|
+
data.tar.gz: 8935ab29251ca82de0c9b770df24a0015bc6e46dc0f1cdfba6868ddc23b685306b8c4c4a1d182559ada38f654a8f9dbd199d4b68f9670a18d65fc7c45370eecf
|
data/README.md
CHANGED
@@ -21,6 +21,14 @@ Follow [@peterohler on Twitter](http://twitter.com/#!/peterohler) for announceme
|
|
21
21
|
[![Build Status](https://secure.travis-ci.org/ohler55/oj.png?branch=master)](http://travis-ci.org/ohler55/oj)
|
22
22
|
|
23
23
|
|
24
|
+
### Current Release 2.4.0
|
25
|
+
|
26
|
+
- Merged in a PR to again allow strings with embedded nulls.
|
27
|
+
|
28
|
+
- Implemented StreamWriter to compliment the StringWriter.
|
29
|
+
|
30
|
+
- Fixed bug in the class cache hash function that showed up with the sparc compiler.
|
31
|
+
|
24
32
|
### Current Release 2.3.0
|
25
33
|
|
26
34
|
- JRuby is no longer supported.
|
data/ext/oj/compat.c
CHANGED
@@ -75,7 +75,7 @@ end_hash(struct _ParseInfo *pi) {
|
|
75
75
|
if (Qundef != clas) { // else an error
|
76
76
|
parent->val = rb_funcall(clas, oj_json_create_id, 1, parent->val);
|
77
77
|
}
|
78
|
-
if (parent->classname < pi->json || pi->
|
78
|
+
if (parent->classname < pi->json || pi->end < parent->classname) {
|
79
79
|
xfree((char*)parent->classname);
|
80
80
|
parent->classname = 0;
|
81
81
|
}
|
@@ -96,11 +96,11 @@ oj_compat_parse(int argc, VALUE *argv, VALUE self) {
|
|
96
96
|
pi.options = oj_default_options;
|
97
97
|
oj_set_compat_callbacks(&pi);
|
98
98
|
|
99
|
-
return oj_pi_parse(argc, argv, &pi, 0);
|
99
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0);
|
100
100
|
}
|
101
101
|
|
102
102
|
VALUE
|
103
|
-
oj_compat_parse_cstr(int argc, VALUE *argv, char *json) {
|
103
|
+
oj_compat_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
104
104
|
struct _ParseInfo pi;
|
105
105
|
|
106
106
|
pi.options = oj_default_options;
|
@@ -108,5 +108,5 @@ oj_compat_parse_cstr(int argc, VALUE *argv, char *json) {
|
|
108
108
|
pi.end_hash = end_hash;
|
109
109
|
pi.hash_set_cstr = hash_set_cstr;
|
110
110
|
|
111
|
-
return oj_pi_parse(argc, argv, &pi, json);
|
111
|
+
return oj_pi_parse(argc, argv, &pi, json, len);
|
112
112
|
}
|
data/ext/oj/dump.c
CHANGED
@@ -426,7 +426,7 @@ dump_bignum(VALUE obj, Out out) {
|
|
426
426
|
if (out->end - out->cur <= (long)cnt) {
|
427
427
|
grow(out, cnt);
|
428
428
|
}
|
429
|
-
memcpy(out->cur,
|
429
|
+
memcpy(out->cur, rb_string_value_ptr((VALUE*)&rs), cnt);
|
430
430
|
out->cur += cnt;
|
431
431
|
*out->cur = '\0';
|
432
432
|
}
|
@@ -554,12 +554,12 @@ dump_cstr(const char *str, size_t cnt, int is_sym, int escape1, Out out) {
|
|
554
554
|
|
555
555
|
static void
|
556
556
|
dump_str_comp(VALUE obj, Out out) {
|
557
|
-
dump_cstr(
|
557
|
+
dump_cstr(rb_string_value_ptr((VALUE*)&obj), RSTRING_LEN(obj), 0, 0, out);
|
558
558
|
}
|
559
559
|
|
560
560
|
static void
|
561
561
|
dump_str_obj(VALUE obj, Out out) {
|
562
|
-
const char *s =
|
562
|
+
const char *s = rb_string_value_ptr((VALUE*)&obj);
|
563
563
|
size_t len = RSTRING_LEN(obj);
|
564
564
|
char s1 = s[1];
|
565
565
|
|
@@ -1023,7 +1023,7 @@ static void
|
|
1023
1023
|
dump_ruby_time(VALUE obj, Out out) {
|
1024
1024
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1025
1025
|
|
1026
|
-
dump_cstr(
|
1026
|
+
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
|
1027
1027
|
}
|
1028
1028
|
|
1029
1029
|
static void
|
@@ -1121,7 +1121,7 @@ dump_data_strict(VALUE obj, Out out) {
|
|
1121
1121
|
if (oj_bigdecimal_class == clas) {
|
1122
1122
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1123
1123
|
|
1124
|
-
dump_raw(
|
1124
|
+
dump_raw(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), out);
|
1125
1125
|
} else {
|
1126
1126
|
raise_strict(obj);
|
1127
1127
|
}
|
@@ -1134,7 +1134,7 @@ dump_data_null(VALUE obj, Out out) {
|
|
1134
1134
|
if (oj_bigdecimal_class == clas) {
|
1135
1135
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1136
1136
|
|
1137
|
-
dump_raw(
|
1137
|
+
dump_raw(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), out);
|
1138
1138
|
} else {
|
1139
1139
|
dump_nil(out);
|
1140
1140
|
}
|
@@ -1161,7 +1161,7 @@ dump_data_comp(VALUE obj, int depth, Out out) {
|
|
1161
1161
|
last_obj = obj;
|
1162
1162
|
rs = rb_funcall(obj, oj_to_json_id, 0);
|
1163
1163
|
last_obj = Qundef;
|
1164
|
-
s =
|
1164
|
+
s = rb_string_value_ptr((VALUE*)&rs);
|
1165
1165
|
len = (int)RSTRING_LEN(rs);
|
1166
1166
|
|
1167
1167
|
if (out->end - out->cur <= len + 1) {
|
@@ -1184,14 +1184,14 @@ dump_data_comp(VALUE obj, int depth, Out out) {
|
|
1184
1184
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1185
1185
|
|
1186
1186
|
if (Yes == out->opts->bigdec_as_num) {
|
1187
|
-
dump_raw(
|
1187
|
+
dump_raw(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), out);
|
1188
1188
|
} else {
|
1189
|
-
dump_cstr(
|
1189
|
+
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
|
1190
1190
|
}
|
1191
1191
|
} else {
|
1192
1192
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1193
1193
|
|
1194
|
-
dump_cstr(
|
1194
|
+
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
|
1195
1195
|
}
|
1196
1196
|
}
|
1197
1197
|
}
|
@@ -1221,9 +1221,9 @@ dump_data_obj(VALUE obj, int depth, Out out) {
|
|
1221
1221
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1222
1222
|
|
1223
1223
|
if (Yes == out->opts->bigdec_as_num) {
|
1224
|
-
dump_raw(
|
1224
|
+
dump_raw(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), out);
|
1225
1225
|
} else {
|
1226
|
-
dump_cstr(
|
1226
|
+
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
|
1227
1227
|
}
|
1228
1228
|
} else {
|
1229
1229
|
dump_nil(out);
|
@@ -1244,9 +1244,7 @@ dump_obj_comp(VALUE obj, int depth, Out out) {
|
|
1244
1244
|
}
|
1245
1245
|
dump_hash(h, depth, out->opts->mode, out);
|
1246
1246
|
} else if (rb_respond_to(obj, oj_as_json_id)) {
|
1247
|
-
|
1248
|
-
|
1249
|
-
dump_val(js, depth, out);
|
1247
|
+
dump_val(rb_funcall(obj, oj_as_json_id, 0), depth, out);
|
1250
1248
|
} else if (rb_respond_to(obj, oj_to_json_id) && (!oj_rails_hack || last_obj != obj)) {
|
1251
1249
|
volatile VALUE rs;
|
1252
1250
|
const char *s;
|
@@ -1255,7 +1253,7 @@ dump_obj_comp(VALUE obj, int depth, Out out) {
|
|
1255
1253
|
last_obj = obj;
|
1256
1254
|
rs = rb_funcall(obj, oj_to_json_id, 0);
|
1257
1255
|
last_obj = Qundef;
|
1258
|
-
s =
|
1256
|
+
s = rb_string_value_ptr((VALUE*)&rs);
|
1259
1257
|
len = (int)RSTRING_LEN(rs);
|
1260
1258
|
|
1261
1259
|
if (out->end - out->cur <= len + 1) {
|
@@ -1271,14 +1269,14 @@ dump_obj_comp(VALUE obj, int depth, Out out) {
|
|
1271
1269
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1272
1270
|
|
1273
1271
|
if (Yes == out->opts->bigdec_as_num) {
|
1274
|
-
dump_raw(
|
1272
|
+
dump_raw(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), out);
|
1275
1273
|
} else {
|
1276
|
-
dump_cstr(
|
1274
|
+
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
|
1277
1275
|
}
|
1278
1276
|
} else if (oj_datetime_class == clas || oj_date_class == clas) {
|
1279
1277
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1280
1278
|
|
1281
|
-
dump_cstr(
|
1279
|
+
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
|
1282
1280
|
} else {
|
1283
1281
|
Odd odd = oj_get_odd(clas);
|
1284
1282
|
|
@@ -1304,7 +1302,7 @@ dump_obj_obj(VALUE obj, int depth, Out out) {
|
|
1304
1302
|
if (oj_bigdecimal_class == clas) {
|
1305
1303
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1306
1304
|
|
1307
|
-
dump_raw(
|
1305
|
+
dump_raw(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), out);
|
1308
1306
|
} else {
|
1309
1307
|
dump_obj_attrs(obj, clas, id, depth, out);
|
1310
1308
|
}
|
@@ -1496,7 +1494,7 @@ dump_struct_comp(VALUE obj, int depth, Out out) {
|
|
1496
1494
|
const char *s;
|
1497
1495
|
int len;
|
1498
1496
|
|
1499
|
-
s =
|
1497
|
+
s = rb_string_value_ptr((VALUE*)&rs);
|
1500
1498
|
len = (int)RSTRING_LEN(rs);
|
1501
1499
|
if (out->end - out->cur <= len) {
|
1502
1500
|
grow(out, len);
|
@@ -2035,8 +2033,6 @@ key_check(StrWriter sw, const char *key) {
|
|
2035
2033
|
|
2036
2034
|
if (0 == key && (ObjectNew == type || ObjectType == type)) {
|
2037
2035
|
rb_raise(rb_eStandardError, "Can not push onto an Object without a key.");
|
2038
|
-
} else if (0 != key && (ArrayNew == type || ArrayType == type)) {
|
2039
|
-
rb_raise(rb_eStandardError, "No key is needed to push into an array.");
|
2040
2036
|
}
|
2041
2037
|
}
|
2042
2038
|
|
@@ -2155,4 +2151,3 @@ oj_str_writer_pop_all(StrWriter sw) {
|
|
2155
2151
|
oj_str_writer_pop(sw);
|
2156
2152
|
}
|
2157
2153
|
}
|
2158
|
-
|
data/ext/oj/hash.c
CHANGED
@@ -56,27 +56,30 @@ struct _Hash intern_hash;
|
|
56
56
|
|
57
57
|
static uint32_t
|
58
58
|
hash_calc(const uint8_t *key, size_t len) {
|
59
|
-
|
60
|
-
|
61
|
-
uint32_t
|
62
|
-
uint32_t
|
63
|
-
|
64
|
-
|
65
|
-
|
59
|
+
const uint8_t *end = key + len;
|
60
|
+
const uint8_t *endless = key + (len / 4 * 4);
|
61
|
+
uint32_t h = (uint32_t)len;
|
62
|
+
uint32_t k;
|
63
|
+
|
64
|
+
while (key < endless) {
|
65
|
+
k = (uint32_t)*key++;
|
66
|
+
k |= (uint32_t)*key++ << 8;
|
67
|
+
k |= (uint32_t)*key++ << 16;
|
68
|
+
k |= (uint32_t)*key++ << 24;
|
69
|
+
|
70
|
+
k *= M;
|
66
71
|
k ^= k >> 24;
|
67
72
|
h *= M;
|
68
73
|
h ^= k * M;
|
69
74
|
}
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
} else {
|
76
|
-
key = (uint8_t*)kp;
|
75
|
+
if (1 < end - key) {
|
76
|
+
uint16_t k16 = (uint16_t)*key++;
|
77
|
+
|
78
|
+
k16 |= (uint16_t)*key++ << 8;
|
79
|
+
h ^= k16 << 8;
|
77
80
|
}
|
78
|
-
if (
|
79
|
-
h ^= key
|
81
|
+
if (key < end) {
|
82
|
+
h ^= *key;
|
80
83
|
}
|
81
84
|
h *= M;
|
82
85
|
h ^= h >> 13;
|
@@ -115,7 +118,7 @@ hash_get(Hash hash, const char *key, size_t len, VALUE **slotp, VALUE def_value)
|
|
115
118
|
|
116
119
|
b->next = 0;
|
117
120
|
bucket->next = b;
|
118
|
-
|
121
|
+
bucket = b;
|
119
122
|
}
|
120
123
|
bucket->key = oj_strndup(key, len);
|
121
124
|
bucket->len = len;
|
data/ext/oj/hash_test.c
CHANGED
@@ -224,7 +224,6 @@ static struct _StrLen data[] = {
|
|
224
224
|
{ "StandardError", 13 },
|
225
225
|
{ "Interrupt", 9 },
|
226
226
|
{ "SignalException", 15 },
|
227
|
-
{ "#<Class:0x007fb0510c8790>", 25 },
|
228
227
|
{ "SystemExit", 10 },
|
229
228
|
{ "Exception", 9 },
|
230
229
|
{ "Symbol", 6 },
|
@@ -460,6 +459,7 @@ perf() {
|
|
460
459
|
VALUE *slot = 0;
|
461
460
|
uint64_t dt, start;
|
462
461
|
int i, iter = 1000000;
|
462
|
+
int dataCnt = sizeof(data) / sizeof(*data);
|
463
463
|
|
464
464
|
oj_hash_init();
|
465
465
|
start = micro_time();
|
@@ -476,9 +476,9 @@ perf() {
|
|
476
476
|
}
|
477
477
|
dt = micro_time() - start;
|
478
478
|
#if IS_WINDOWS
|
479
|
-
printf("%d iterations took %ld msecs\n", iter, (long)(dt / 1000));
|
479
|
+
printf("%d iterations took %ld msecs, %ld gets/msec\n", iter, (long)(dt / 1000), (long)(iter * dataCnt / (dt / 1000)));
|
480
480
|
#else
|
481
|
-
printf("%d iterations took %"PRIu64" msecs\n", iter, dt / 1000);
|
481
|
+
printf("%d iterations took %"PRIu64" msecs, %ld gets/msec\n", iter, dt / 1000, (long)(iter * dataCnt / (dt / 1000)));
|
482
482
|
#endif
|
483
483
|
}
|
484
484
|
|
@@ -490,23 +490,23 @@ oj_hash_test() {
|
|
490
490
|
|
491
491
|
oj_hash_init();
|
492
492
|
for (d = data; 0 != d->str; d++) {
|
493
|
-
|
493
|
+
char *s = oj_strndup(d->str, d->len);
|
494
494
|
v = oj_class_hash_get(d->str, d->len, &slot);
|
495
|
-
if (
|
495
|
+
if (Qnil == v) {
|
496
496
|
if (0 == slot) {
|
497
|
-
|
497
|
+
printf("*** failed to get a slot for %s\n", s);
|
498
498
|
} else {
|
499
|
-
/*printf("*** added '%s' to hash\n", *d); */
|
500
499
|
v = ID2SYM(rb_intern(d->str));
|
501
500
|
*slot = v;
|
502
501
|
}
|
503
502
|
} else {
|
504
503
|
VALUE rs = rb_funcall2(v, rb_intern("to_s"), 0, 0);
|
505
504
|
|
506
|
-
printf("*** get on '%s' returned '%s' (%s)\n",
|
505
|
+
printf("*** get on '%s' returned '%s' (%s)\n", s, StringValuePtr(rs), rb_class2name(rb_obj_class(v)));
|
507
506
|
}
|
508
507
|
/*oj_hash_print(c);*/
|
509
508
|
}
|
509
|
+
printf("*** ---------- hash table ------------\n");
|
510
510
|
oj_hash_print();
|
511
511
|
perf();
|
512
512
|
}
|
data/ext/oj/object.c
CHANGED
@@ -511,11 +511,11 @@ oj_object_parse(int argc, VALUE *argv, VALUE self) {
|
|
511
511
|
pi.add_cstr = add_cstr;
|
512
512
|
pi.array_append_cstr = array_append_cstr;
|
513
513
|
|
514
|
-
return oj_pi_parse(argc, argv, &pi, 0);
|
514
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0);
|
515
515
|
}
|
516
516
|
|
517
517
|
VALUE
|
518
|
-
oj_object_parse_cstr(int argc, VALUE *argv, char *json) {
|
518
|
+
oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
519
519
|
struct _ParseInfo pi;
|
520
520
|
|
521
521
|
pi.options = oj_default_options;
|
@@ -528,5 +528,5 @@ oj_object_parse_cstr(int argc, VALUE *argv, char *json) {
|
|
528
528
|
pi.add_cstr = add_cstr;
|
529
529
|
pi.array_append_cstr = array_append_cstr;
|
530
530
|
|
531
|
-
return oj_pi_parse(argc, argv, &pi, json);
|
531
|
+
return oj_pi_parse(argc, argv, &pi, json, len);
|
532
532
|
}
|
data/ext/oj/oj.c
CHANGED
@@ -693,15 +693,15 @@ load_file(int argc, VALUE *argv, VALUE self) {
|
|
693
693
|
// The json string is freed in the parser when it is finished with it.
|
694
694
|
switch (mode) {
|
695
695
|
case StrictMode:
|
696
|
-
return oj_strict_parse_cstr(argc, argv, json);
|
696
|
+
return oj_strict_parse_cstr(argc, argv, json, len);
|
697
697
|
case NullMode:
|
698
698
|
case CompatMode:
|
699
|
-
return oj_compat_parse_cstr(argc, argv, json);
|
699
|
+
return oj_compat_parse_cstr(argc, argv, json, len);
|
700
700
|
case ObjectMode:
|
701
701
|
default:
|
702
702
|
break;
|
703
703
|
}
|
704
|
-
return oj_object_parse_cstr(argc, argv, json);
|
704
|
+
return oj_object_parse_cstr(argc, argv, json, len);
|
705
705
|
}
|
706
706
|
|
707
707
|
/* call-seq: safe_load(doc)
|
@@ -725,7 +725,7 @@ safe_load(VALUE self, VALUE doc) {
|
|
725
725
|
oj_set_strict_callbacks(&pi);
|
726
726
|
*args = doc;
|
727
727
|
|
728
|
-
return oj_pi_parse(1, args, &pi, 0);
|
728
|
+
return oj_pi_parse(1, args, &pi, 0, 0);
|
729
729
|
}
|
730
730
|
|
731
731
|
/* call-seq: saj_parse(handler, io)
|
@@ -850,15 +850,8 @@ str_writer_free(void *ptr) {
|
|
850
850
|
* construction is complete will return the document in it's current state.
|
851
851
|
*/
|
852
852
|
|
853
|
-
|
854
|
-
|
855
|
-
* Creates a new StringWriter.
|
856
|
-
* @param [Hash] options formating options
|
857
|
-
*/
|
858
|
-
static VALUE
|
859
|
-
str_writer_new(int argc, VALUE *argv, VALUE self) {
|
860
|
-
StrWriter sw = ALLOC(struct _StrWriter);
|
861
|
-
|
853
|
+
static void
|
854
|
+
str_writer_init(StrWriter sw) {
|
862
855
|
sw->opts = oj_default_options;
|
863
856
|
sw->depth = 0;
|
864
857
|
sw->types = ALLOC_N(char, 256);
|
@@ -871,12 +864,23 @@ str_writer_new(int argc, VALUE *argv, VALUE self) {
|
|
871
864
|
*sw->out.cur = '\0';
|
872
865
|
sw->out.circ_cnt = 0;
|
873
866
|
sw->out.hash_cnt = 0;
|
874
|
-
if (1 == argc) {
|
875
|
-
oj_parse_options(argv[0], &sw->opts);
|
876
|
-
}
|
877
867
|
sw->out.opts = &sw->opts;
|
878
868
|
sw->out.indent = sw->opts.indent;
|
869
|
+
}
|
879
870
|
|
871
|
+
/* call-seq: new(options)
|
872
|
+
*
|
873
|
+
* Creates a new StringWriter.
|
874
|
+
* @param [Hash] options formating options
|
875
|
+
*/
|
876
|
+
static VALUE
|
877
|
+
str_writer_new(int argc, VALUE *argv, VALUE self) {
|
878
|
+
StrWriter sw = ALLOC(struct _StrWriter);
|
879
|
+
|
880
|
+
str_writer_init(sw);
|
881
|
+
if (1 == argc) {
|
882
|
+
oj_parse_options(argv[0], &sw->opts);
|
883
|
+
}
|
880
884
|
return Data_Wrap_Struct(oj_string_writer_class, 0, str_writer_free, sw);
|
881
885
|
}
|
882
886
|
|
@@ -893,8 +897,12 @@ str_writer_push_object(int argc, VALUE *argv, VALUE self) {
|
|
893
897
|
oj_str_writer_push_object((StrWriter)DATA_PTR(self), 0);
|
894
898
|
break;
|
895
899
|
case 1:
|
896
|
-
|
897
|
-
|
900
|
+
if (Qnil == argv[0]) {
|
901
|
+
oj_str_writer_push_object((StrWriter)DATA_PTR(self), 0);
|
902
|
+
} else {
|
903
|
+
rb_check_type(argv[0], T_STRING);
|
904
|
+
oj_str_writer_push_object((StrWriter)DATA_PTR(self), StringValuePtr(argv[0]));
|
905
|
+
}
|
898
906
|
break;
|
899
907
|
default:
|
900
908
|
rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
|
@@ -916,8 +924,12 @@ str_writer_push_array(int argc, VALUE *argv, VALUE self) {
|
|
916
924
|
oj_str_writer_push_array((StrWriter)DATA_PTR(self), 0);
|
917
925
|
break;
|
918
926
|
case 1:
|
919
|
-
|
920
|
-
|
927
|
+
if (Qnil == argv[0]) {
|
928
|
+
oj_str_writer_push_array((StrWriter)DATA_PTR(self), 0);
|
929
|
+
} else {
|
930
|
+
rb_check_type(argv[0], T_STRING);
|
931
|
+
oj_str_writer_push_array((StrWriter)DATA_PTR(self), StringValuePtr(argv[0]));
|
932
|
+
}
|
921
933
|
break;
|
922
934
|
default:
|
923
935
|
rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
|
@@ -939,8 +951,12 @@ str_writer_push_value(int argc, VALUE *argv, VALUE self) {
|
|
939
951
|
oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
|
940
952
|
break;
|
941
953
|
case 2:
|
942
|
-
|
943
|
-
|
954
|
+
if (Qnil == argv[1]) {
|
955
|
+
oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
|
956
|
+
} else {
|
957
|
+
rb_check_type(argv[1], T_STRING);
|
958
|
+
oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
|
959
|
+
}
|
944
960
|
break;
|
945
961
|
default:
|
946
962
|
rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'.");
|
@@ -1000,6 +1016,217 @@ str_writer_to_s(VALUE self) {
|
|
1000
1016
|
return oj_encode(rstr);
|
1001
1017
|
}
|
1002
1018
|
|
1019
|
+
// StreamWriter
|
1020
|
+
|
1021
|
+
static void
|
1022
|
+
stream_writer_free(void *ptr) {
|
1023
|
+
StreamWriter sw;
|
1024
|
+
|
1025
|
+
if (0 == ptr) {
|
1026
|
+
return;
|
1027
|
+
}
|
1028
|
+
sw = (StreamWriter)ptr;
|
1029
|
+
xfree(sw->sw.out.buf);
|
1030
|
+
xfree(sw->sw.types);
|
1031
|
+
xfree(ptr);
|
1032
|
+
}
|
1033
|
+
|
1034
|
+
static void
|
1035
|
+
stream_writer_write(StreamWriter sw) {
|
1036
|
+
ssize_t size = sw->sw.out.cur - sw->sw.out.buf;
|
1037
|
+
|
1038
|
+
switch (sw->type) {
|
1039
|
+
case STRING_IO:
|
1040
|
+
rb_funcall(sw->stream, oj_write_id, 1, rb_str_new(sw->sw.out.buf, size));
|
1041
|
+
break;
|
1042
|
+
case STREAM_IO:
|
1043
|
+
rb_funcall(sw->stream, oj_write_id, 1, rb_str_new(sw->sw.out.buf, size));
|
1044
|
+
break;
|
1045
|
+
case FILE_IO:
|
1046
|
+
if (size != write(sw->fd, sw->sw.out.buf, size)) {
|
1047
|
+
rb_raise(rb_eIOError, "Write failed. [%d:%s]\n", errno, strerror(errno));
|
1048
|
+
}
|
1049
|
+
break;
|
1050
|
+
default:
|
1051
|
+
rb_raise(rb_eArgError, "expected an IO Object.");
|
1052
|
+
}
|
1053
|
+
}
|
1054
|
+
|
1055
|
+
static void
|
1056
|
+
stream_writer_reset_buf(StreamWriter sw) {
|
1057
|
+
sw->sw.out.cur = sw->sw.out.buf;
|
1058
|
+
*sw->sw.out.cur = '\0';
|
1059
|
+
}
|
1060
|
+
|
1061
|
+
/* call-seq: new(options)
|
1062
|
+
*
|
1063
|
+
* Creates a new StreamWriter.
|
1064
|
+
* @param [Hash] options formating options
|
1065
|
+
*/
|
1066
|
+
/* call-seq: new(options)
|
1067
|
+
*
|
1068
|
+
* Creates a new StreamWriter.
|
1069
|
+
* @param [Hash] options formating options
|
1070
|
+
*/
|
1071
|
+
static VALUE
|
1072
|
+
stream_writer_new(int argc, VALUE *argv, VALUE self) {
|
1073
|
+
StreamWriterType type = STREAM_IO;
|
1074
|
+
int fd = 0;
|
1075
|
+
VALUE stream = argv[0];
|
1076
|
+
VALUE clas = rb_obj_class(stream);
|
1077
|
+
VALUE s;
|
1078
|
+
StreamWriter sw;
|
1079
|
+
|
1080
|
+
if (oj_stringio_class == clas) {
|
1081
|
+
type = STRING_IO;
|
1082
|
+
#ifndef JRUBY_RUBY
|
1083
|
+
#if !IS_WINDOWS
|
1084
|
+
} else if (rb_respond_to(stream, oj_fileno_id) && Qnil != (s = rb_funcall(stream, oj_fileno_id, 0))) {
|
1085
|
+
type = FILE_IO;
|
1086
|
+
fd = FIX2INT(s);
|
1087
|
+
#endif
|
1088
|
+
#endif
|
1089
|
+
} else if (rb_respond_to(stream, oj_write_id)) {
|
1090
|
+
type = STREAM_IO;
|
1091
|
+
} else {
|
1092
|
+
rb_raise(rb_eArgError, "expected an IO Object.");
|
1093
|
+
}
|
1094
|
+
sw = ALLOC(struct _StreamWriter);
|
1095
|
+
str_writer_init(&sw->sw);
|
1096
|
+
if (1 == argc) {
|
1097
|
+
oj_parse_options(argv[0], &sw->sw.opts);
|
1098
|
+
}
|
1099
|
+
sw->stream = stream;
|
1100
|
+
sw->type = type;
|
1101
|
+
sw->fd = fd;
|
1102
|
+
|
1103
|
+
return Data_Wrap_Struct(oj_stream_writer_class, 0, stream_writer_free, sw);
|
1104
|
+
}
|
1105
|
+
|
1106
|
+
/* call-seq: push_object(key=nil)
|
1107
|
+
*
|
1108
|
+
* Pushes an object onto the JSON document. Future pushes will be to this object
|
1109
|
+
* until a pop() is called.
|
1110
|
+
* @param [String] key the key if adding to an object in the JSON document
|
1111
|
+
*/
|
1112
|
+
static VALUE
|
1113
|
+
stream_writer_push_object(int argc, VALUE *argv, VALUE self) {
|
1114
|
+
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
1115
|
+
|
1116
|
+
stream_writer_reset_buf(sw);
|
1117
|
+
switch (argc) {
|
1118
|
+
case 0:
|
1119
|
+
oj_str_writer_push_object(&sw->sw, 0);
|
1120
|
+
break;
|
1121
|
+
case 1:
|
1122
|
+
if (Qnil == argv[0]) {
|
1123
|
+
oj_str_writer_push_object(&sw->sw, 0);
|
1124
|
+
} else {
|
1125
|
+
rb_check_type(argv[0], T_STRING);
|
1126
|
+
oj_str_writer_push_object(&sw->sw, StringValuePtr(argv[0]));
|
1127
|
+
}
|
1128
|
+
break;
|
1129
|
+
default:
|
1130
|
+
rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
|
1131
|
+
break;
|
1132
|
+
}
|
1133
|
+
stream_writer_write(sw);
|
1134
|
+
return Qnil;
|
1135
|
+
}
|
1136
|
+
|
1137
|
+
/* call-seq: push_array(key=nil)
|
1138
|
+
*
|
1139
|
+
* Pushes an array onto the JSON document. Future pushes will be to this object
|
1140
|
+
* until a pop() is called.
|
1141
|
+
* @param [String] key the key if adding to an object in the JSON document
|
1142
|
+
*/
|
1143
|
+
static VALUE
|
1144
|
+
stream_writer_push_array(int argc, VALUE *argv, VALUE self) {
|
1145
|
+
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
1146
|
+
|
1147
|
+
stream_writer_reset_buf(sw);
|
1148
|
+
switch (argc) {
|
1149
|
+
case 0:
|
1150
|
+
oj_str_writer_push_array(&sw->sw, 0);
|
1151
|
+
break;
|
1152
|
+
case 1:
|
1153
|
+
if (Qnil == argv[0]) {
|
1154
|
+
oj_str_writer_push_array(&sw->sw, 0);
|
1155
|
+
} else {
|
1156
|
+
rb_check_type(argv[0], T_STRING);
|
1157
|
+
oj_str_writer_push_array(&sw->sw, StringValuePtr(argv[0]));
|
1158
|
+
}
|
1159
|
+
break;
|
1160
|
+
default:
|
1161
|
+
rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
|
1162
|
+
break;
|
1163
|
+
}
|
1164
|
+
stream_writer_write(sw);
|
1165
|
+
return Qnil;
|
1166
|
+
}
|
1167
|
+
|
1168
|
+
/* call-seq: push_value(value, key=nil)
|
1169
|
+
*
|
1170
|
+
* Pushes a value onto the JSON document.
|
1171
|
+
* @param [Object] value value to add to the JSON document
|
1172
|
+
* @param [String] key the key if adding to an object in the JSON document
|
1173
|
+
*/
|
1174
|
+
static VALUE
|
1175
|
+
stream_writer_push_value(int argc, VALUE *argv, VALUE self) {
|
1176
|
+
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
1177
|
+
|
1178
|
+
stream_writer_reset_buf(sw);
|
1179
|
+
switch (argc) {
|
1180
|
+
case 1:
|
1181
|
+
oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
|
1182
|
+
break;
|
1183
|
+
case 2:
|
1184
|
+
if (Qnil == argv[0]) {
|
1185
|
+
oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
|
1186
|
+
} else {
|
1187
|
+
rb_check_type(argv[1], T_STRING);
|
1188
|
+
oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
|
1189
|
+
}
|
1190
|
+
break;
|
1191
|
+
default:
|
1192
|
+
rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'.");
|
1193
|
+
break;
|
1194
|
+
}
|
1195
|
+
stream_writer_write(sw);
|
1196
|
+
return Qnil;
|
1197
|
+
}
|
1198
|
+
|
1199
|
+
/* call-seq: pop()
|
1200
|
+
*
|
1201
|
+
* Pops up a level in the JSON document closing the array or object that is
|
1202
|
+
* currently open.
|
1203
|
+
*/
|
1204
|
+
static VALUE
|
1205
|
+
stream_writer_pop(VALUE self) {
|
1206
|
+
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
1207
|
+
|
1208
|
+
stream_writer_reset_buf(sw);
|
1209
|
+
oj_str_writer_pop(&sw->sw);
|
1210
|
+
stream_writer_write(sw);
|
1211
|
+
return Qnil;
|
1212
|
+
}
|
1213
|
+
|
1214
|
+
/* call-seq: pop_all()
|
1215
|
+
*
|
1216
|
+
* Pops all level in the JSON document closing all the array or object that is
|
1217
|
+
* currently open.
|
1218
|
+
*/
|
1219
|
+
static VALUE
|
1220
|
+
stream_writer_pop_all(VALUE self) {
|
1221
|
+
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
1222
|
+
|
1223
|
+
stream_writer_reset_buf(sw);
|
1224
|
+
oj_str_writer_pop_all(&sw->sw);
|
1225
|
+
stream_writer_write(sw);
|
1226
|
+
|
1227
|
+
return Qnil;
|
1228
|
+
}
|
1229
|
+
|
1003
1230
|
// Mimic JSON section
|
1004
1231
|
|
1005
1232
|
static VALUE
|
@@ -1227,7 +1454,7 @@ mimic_parse(int argc, VALUE *argv, VALUE self) {
|
|
1227
1454
|
}
|
1228
1455
|
*args = *argv;
|
1229
1456
|
|
1230
|
-
return oj_pi_parse(1, args, &pi, 0);
|
1457
|
+
return oj_pi_parse(1, args, &pi, 0, 0);
|
1231
1458
|
}
|
1232
1459
|
|
1233
1460
|
static VALUE
|
@@ -1351,7 +1578,6 @@ define_mimic_json(int argc, VALUE *argv, VALUE self) {
|
|
1351
1578
|
return mimic;
|
1352
1579
|
}
|
1353
1580
|
|
1354
|
-
/*
|
1355
1581
|
extern void oj_hash_test();
|
1356
1582
|
|
1357
1583
|
static VALUE
|
@@ -1359,7 +1585,6 @@ hash_test(VALUE self) {
|
|
1359
1585
|
oj_hash_test();
|
1360
1586
|
return Qnil;
|
1361
1587
|
}
|
1362
|
-
*/
|
1363
1588
|
|
1364
1589
|
#if !HAS_ENCODING_SUPPORT
|
1365
1590
|
static VALUE
|
@@ -1401,7 +1626,13 @@ void Init_oj() {
|
|
1401
1626
|
rb_define_method(oj_string_writer_class, "reset", str_writer_reset, 0);
|
1402
1627
|
rb_define_method(oj_string_writer_class, "to_s", str_writer_to_s, 0);
|
1403
1628
|
|
1404
|
-
|
1629
|
+
oj_stream_writer_class = rb_define_class_under(Oj, "StreamWriter", rb_cObject);
|
1630
|
+
rb_define_module_function(oj_stream_writer_class, "new", stream_writer_new, -1);
|
1631
|
+
rb_define_method(oj_stream_writer_class, "push_object", stream_writer_push_object, -1);
|
1632
|
+
rb_define_method(oj_stream_writer_class, "push_array", stream_writer_push_array, -1);
|
1633
|
+
rb_define_method(oj_stream_writer_class, "push_value", stream_writer_push_value, -1);
|
1634
|
+
rb_define_method(oj_stream_writer_class, "pop", stream_writer_pop, 0);
|
1635
|
+
rb_define_method(oj_stream_writer_class, "pop_all", stream_writer_pop_all, 0);
|
1405
1636
|
|
1406
1637
|
rb_require("time");
|
1407
1638
|
rb_require("date");
|
@@ -1419,7 +1650,7 @@ void Init_oj() {
|
|
1419
1650
|
oj_utf8_encoding = Qnil;
|
1420
1651
|
#endif
|
1421
1652
|
|
1422
|
-
|
1653
|
+
rb_define_module_function(Oj, "hash_test", hash_test, 0);
|
1423
1654
|
|
1424
1655
|
rb_define_module_function(Oj, "default_options", get_def_opts, 0);
|
1425
1656
|
rb_define_module_function(Oj, "default_options=", set_def_opts, 1);
|
data/ext/oj/oj.h
CHANGED
@@ -105,6 +105,12 @@ typedef enum {
|
|
105
105
|
ObjectType = 'o',
|
106
106
|
} DumpType;
|
107
107
|
|
108
|
+
typedef enum {
|
109
|
+
STRING_IO = 'c',
|
110
|
+
STREAM_IO = 's',
|
111
|
+
FILE_IO = 'f',
|
112
|
+
} StreamWriterType;
|
113
|
+
|
108
114
|
typedef struct _DumpOpts {
|
109
115
|
const char *indent;
|
110
116
|
const char *before_sep;
|
@@ -157,6 +163,13 @@ typedef struct _StrWriter {
|
|
157
163
|
char *types_end;
|
158
164
|
} *StrWriter;
|
159
165
|
|
166
|
+
typedef struct _StreamWriter {
|
167
|
+
struct _StrWriter sw;
|
168
|
+
StreamWriterType type;
|
169
|
+
VALUE stream;
|
170
|
+
int fd;
|
171
|
+
} *StreamWriter;
|
172
|
+
|
160
173
|
enum {
|
161
174
|
STR_VAL = 0x00,
|
162
175
|
COL_VAL = 0x01,
|
@@ -186,9 +199,9 @@ extern VALUE oj_strict_parse(int argc, VALUE *argv, VALUE self);
|
|
186
199
|
extern VALUE oj_compat_parse(int argc, VALUE *argv, VALUE self);
|
187
200
|
extern VALUE oj_object_parse(int argc, VALUE *argv, VALUE self);
|
188
201
|
|
189
|
-
extern VALUE oj_strict_parse_cstr(int argc, VALUE *argv, char *json);
|
190
|
-
extern VALUE oj_compat_parse_cstr(int argc, VALUE *argv, char *json);
|
191
|
-
extern VALUE oj_object_parse_cstr(int argc, VALUE *argv, char *json);
|
202
|
+
extern VALUE oj_strict_parse_cstr(int argc, VALUE *argv, char *json, size_t len);
|
203
|
+
extern VALUE oj_compat_parse_cstr(int argc, VALUE *argv, char *json, size_t len);
|
204
|
+
extern VALUE oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len);
|
192
205
|
|
193
206
|
extern void oj_parse_options(VALUE ropts, Options copts);
|
194
207
|
|
data/ext/oj/parse.c
CHANGED
@@ -719,7 +719,7 @@ protect_parse(VALUE pip) {
|
|
719
719
|
}
|
720
720
|
|
721
721
|
VALUE
|
722
|
-
oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json) {
|
722
|
+
oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len) {
|
723
723
|
char *buf = 0;
|
724
724
|
volatile VALUE input;
|
725
725
|
volatile VALUE wrapped_stack;
|
@@ -737,9 +737,11 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json) {
|
|
737
737
|
pi->cbc = (void*)0;
|
738
738
|
if (0 != json) {
|
739
739
|
pi->json = json;
|
740
|
+
pi->end = json + len;
|
740
741
|
free_json = 1;
|
741
742
|
} else if (rb_type(input) == T_STRING) {
|
742
743
|
pi->json = rb_string_value_cstr((VALUE*)&input);
|
744
|
+
pi->end = pi->json + RSTRING_LEN(input);
|
743
745
|
} else {
|
744
746
|
VALUE clas = rb_obj_class(input);
|
745
747
|
volatile VALUE s;
|
@@ -747,6 +749,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json) {
|
|
747
749
|
if (oj_stringio_class == clas) {
|
748
750
|
s = rb_funcall2(input, oj_string_id, 0, 0);
|
749
751
|
pi->json = rb_string_value_cstr((VALUE*)&s);
|
752
|
+
pi->end = pi->json + RSTRING_LEN(s);
|
750
753
|
#if !IS_WINDOWS
|
751
754
|
} else if (rb_respond_to(input, oj_fileno_id) && Qnil != (s = rb_funcall(input, oj_fileno_id, 0))) {
|
752
755
|
int fd = FIX2INT(s);
|
@@ -756,6 +759,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json) {
|
|
756
759
|
lseek(fd, 0, SEEK_SET);
|
757
760
|
buf = ALLOC_N(char, len + 1);
|
758
761
|
pi->json = buf;
|
762
|
+
pi->end = buf + len;
|
759
763
|
if (0 >= (cnt = read(fd, (char*)pi->json, len)) || cnt != (ssize_t)len) {
|
760
764
|
if (0 != buf) {
|
761
765
|
xfree(buf);
|
@@ -771,6 +775,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json) {
|
|
771
775
|
} else if (rb_respond_to(input, oj_read_id)) {
|
772
776
|
s = rb_funcall2(input, oj_read_id, 0, 0);
|
773
777
|
pi->json = rb_string_value_cstr((VALUE*)&s);
|
778
|
+
pi->end = pi->json + RSTRING_LEN(s);
|
774
779
|
} else {
|
775
780
|
rb_raise(rb_eArgError, "strict_parse() expected a String or IO Object.");
|
776
781
|
}
|
data/ext/oj/parse.h
CHANGED
@@ -56,6 +56,7 @@ typedef struct _NumInfo {
|
|
56
56
|
typedef struct _ParseInfo {
|
57
57
|
const char *json;
|
58
58
|
const char *cur;
|
59
|
+
const char *end;
|
59
60
|
struct _Err err;
|
60
61
|
struct _Options options;
|
61
62
|
void *cbc;
|
@@ -81,7 +82,7 @@ typedef struct _ParseInfo {
|
|
81
82
|
|
82
83
|
extern void oj_parse2(ParseInfo pi);
|
83
84
|
extern void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char* file, int line, const char *format, ...);
|
84
|
-
extern VALUE oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json);
|
85
|
+
extern VALUE oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len);
|
85
86
|
extern VALUE oj_num_as_value(NumInfo ni);
|
86
87
|
|
87
88
|
extern void oj_set_strict_callbacks(ParseInfo pi);
|
data/ext/oj/strict.c
CHANGED
@@ -145,15 +145,15 @@ oj_strict_parse(int argc, VALUE *argv, VALUE self) {
|
|
145
145
|
pi.options = oj_default_options;
|
146
146
|
oj_set_strict_callbacks(&pi);
|
147
147
|
|
148
|
-
return oj_pi_parse(argc, argv, &pi, 0);
|
148
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0);
|
149
149
|
}
|
150
150
|
|
151
151
|
VALUE
|
152
|
-
oj_strict_parse_cstr(int argc, VALUE *argv, char *json) {
|
152
|
+
oj_strict_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
153
153
|
struct _ParseInfo pi;
|
154
154
|
|
155
155
|
pi.options = oj_default_options;
|
156
156
|
oj_set_strict_callbacks(&pi);
|
157
157
|
|
158
|
-
return oj_pi_parse(argc, argv, &pi, json);
|
158
|
+
return oj_pi_parse(argc, argv, &pi, json, len);
|
159
159
|
}
|
data/lib/oj/version.rb
CHANGED
data/test/debian_test.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
# Ubuntu does not accept arguments to ruby when called using env. To get warnings to show up the -w options is
|
5
|
+
# required. That can be set in the RUBYOPT environment variable.
|
6
|
+
# export RUBYOPT=-w
|
7
|
+
|
8
|
+
$VERBOSE = true
|
9
|
+
|
10
|
+
$: << File.join(File.dirname(__FILE__), "../lib")
|
11
|
+
$: << File.join(File.dirname(__FILE__), "../ext")
|
12
|
+
|
13
|
+
require 'test/unit'
|
14
|
+
require 'stringio'
|
15
|
+
require 'date'
|
16
|
+
require 'bigdecimal'
|
17
|
+
require 'oj'
|
18
|
+
|
19
|
+
$ruby = RUBY_DESCRIPTION.split(' ')[0]
|
20
|
+
$ruby = 'ree' if 'ruby' == $ruby && RUBY_DESCRIPTION.include?('Ruby Enterprise Edition')
|
21
|
+
|
22
|
+
def hash_eql(h1, h2)
|
23
|
+
return false if h1.size != h2.size
|
24
|
+
h1.keys.each do |k|
|
25
|
+
return false unless h1[k] == h2[k]
|
26
|
+
end
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
class Jam
|
31
|
+
attr_accessor :x, :y
|
32
|
+
|
33
|
+
def initialize(x, y)
|
34
|
+
@x = x
|
35
|
+
@y = y
|
36
|
+
end
|
37
|
+
|
38
|
+
def eql?(o)
|
39
|
+
self.class == o.class && @x == o.x && @y == o.y
|
40
|
+
end
|
41
|
+
alias == eql?
|
42
|
+
|
43
|
+
end# Jam
|
44
|
+
|
45
|
+
# contributed by sauliusg to fix as_json
|
46
|
+
class Orange < Jam
|
47
|
+
def initialize(x, y)
|
48
|
+
super
|
49
|
+
end
|
50
|
+
|
51
|
+
def as_json()
|
52
|
+
puts "Orange.as_json called"
|
53
|
+
{ :json_class => self.class,
|
54
|
+
:x => @x,
|
55
|
+
:y => @y }
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.json_create(h)
|
59
|
+
puts "Orange.json_create"
|
60
|
+
self.new(h['x'], h['y'])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class DebJuice < ::Test::Unit::TestCase
|
65
|
+
|
66
|
+
def test_class_hash
|
67
|
+
Oj.hash_test()
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_as_json_object_compat_hash_cached
|
71
|
+
Oj.default_options = { :mode => :compat, :class_cache => true }
|
72
|
+
obj = Orange.new(true, 58)
|
73
|
+
puts "dumping compat with cache"
|
74
|
+
json = Oj.dump(obj, :indent => 2)
|
75
|
+
assert(!json.nil?)
|
76
|
+
dump_and_load(obj, true)
|
77
|
+
end
|
78
|
+
|
79
|
+
def dump_and_load(obj, trace=false)
|
80
|
+
puts "dumping"
|
81
|
+
json = Oj.dump(obj, :indent => 2)
|
82
|
+
puts json if trace
|
83
|
+
puts "loading"
|
84
|
+
loaded = Oj.load(json);
|
85
|
+
puts "done"
|
86
|
+
assert_equal(obj, loaded)
|
87
|
+
loaded
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
data/test/test_writer.rb
CHANGED
@@ -23,7 +23,6 @@ class OjWriter < ::Test::Unit::TestCase
|
|
23
23
|
w.push_array()
|
24
24
|
w.pop()
|
25
25
|
assert_equal('[]', w.to_s)
|
26
|
-
|
27
26
|
end
|
28
27
|
|
29
28
|
def test_string_writer_nested_array
|
@@ -100,18 +99,6 @@ class OjWriter < ::Test::Unit::TestCase
|
|
100
99
|
assert(false, "*** expected an exception")
|
101
100
|
end
|
102
101
|
|
103
|
-
def test_string_writer_array_with_key
|
104
|
-
w = Oj::StringWriter.new(:indent => 0)
|
105
|
-
w.push_array()
|
106
|
-
begin
|
107
|
-
w.push_value(59, 'x')
|
108
|
-
rescue Exception
|
109
|
-
assert(true)
|
110
|
-
return
|
111
|
-
end
|
112
|
-
assert(false, "*** expected an exception")
|
113
|
-
end
|
114
|
-
|
115
102
|
def test_string_writer_deep
|
116
103
|
cnt = 1000
|
117
104
|
w = Oj::StringWriter.new(:indent => 0)
|
@@ -145,4 +132,55 @@ class OjWriter < ::Test::Unit::TestCase
|
|
145
132
|
assert_equal('', w.to_s)
|
146
133
|
end
|
147
134
|
|
135
|
+
# Stream Writer
|
136
|
+
|
137
|
+
def test_stream_writer_empty_array
|
138
|
+
output = StringIO.open("", "w+")
|
139
|
+
w = Oj::StreamWriter.new(output, :indent => 0)
|
140
|
+
w.push_array()
|
141
|
+
w.pop()
|
142
|
+
assert_equal('[]', output.string())
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_stream_writer_mixed_stringio
|
146
|
+
output = StringIO.open("", "w+")
|
147
|
+
w = Oj::StreamWriter.new(output, :indent => 0)
|
148
|
+
w.push_object()
|
149
|
+
w.push_object("a1")
|
150
|
+
w.pop()
|
151
|
+
w.push_object("a2")
|
152
|
+
w.push_array("b")
|
153
|
+
w.push_value(7)
|
154
|
+
w.push_value(true)
|
155
|
+
w.push_value("string")
|
156
|
+
w.pop()
|
157
|
+
w.pop()
|
158
|
+
w.push_object("a3")
|
159
|
+
w.pop()
|
160
|
+
w.pop()
|
161
|
+
assert_equal('{"a1":{},"a2":{"b":[7,true,"string"]},"a3":{}}', output.string())
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_stream_writer_mixed_file
|
165
|
+
filename = 'open_file_writer_test.json'
|
166
|
+
File.open(filename, "w") do |f|
|
167
|
+
w = Oj::StreamWriter.new(f, :indent => 0)
|
168
|
+
w.push_object()
|
169
|
+
w.push_object("a1")
|
170
|
+
w.pop()
|
171
|
+
w.push_object("a2")
|
172
|
+
w.push_array("b")
|
173
|
+
w.push_value(7)
|
174
|
+
w.push_value(true)
|
175
|
+
w.push_value("string")
|
176
|
+
w.pop()
|
177
|
+
w.pop()
|
178
|
+
w.push_object("a3")
|
179
|
+
w.pop()
|
180
|
+
w.pop()
|
181
|
+
end
|
182
|
+
content = File.read(filename)
|
183
|
+
assert_equal('{"a1":{},"a2":{"b":[7,true,"string"]},"a3":{}}', content)
|
184
|
+
end
|
185
|
+
|
148
186
|
end # OjWriter
|
data/test/tests.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oj
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Ohler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-12-
|
11
|
+
date: 2013-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: 'The fastest JSON parser and object serializer. '
|
14
14
|
email: peter@ohler.com
|
@@ -56,6 +56,7 @@ files:
|
|
56
56
|
- ext/oj/val_stack.c
|
57
57
|
- test/a.rb
|
58
58
|
- test/bug.rb
|
59
|
+
- test/debian_test.rb
|
59
60
|
- test/e.rb
|
60
61
|
- test/files.rb
|
61
62
|
- test/foo.rb
|