oj 2.1.6 → 2.1.7
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 +6 -2
- data/ext/oj/dump.c +38 -9
- data/ext/oj/extconf.rb +1 -0
- data/ext/oj/object.c +1 -1
- data/ext/oj/oj.c +6 -0
- data/ext/oj/parse.c +66 -50
- data/ext/oj/parse.h +1 -0
- data/lib/oj/version.rb +1 -1
- data/test/test_scp.rb +1 -1
- data/test/tests.rb +28 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70957d2247e339a9ad73f19ad36df9da6979848b
|
4
|
+
data.tar.gz: b2bdcf86cf0920e464560066b7054c997656b53c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4ec5a8db9aa7fd4d9c3721ccbd09f7aa357583d4a8c75f071ee007356b9371164ab75dd2ea897117cb332cf9d6158f47e0c8338aacb3b77c389e0ca08c099a6
|
7
|
+
data.tar.gz: 5849f4c725ee2db364c41a034aead4e1c547ae53bb090db10e6bbb65013a19812cd024586fcba1f0d58285ded793a5f5c4675103f095cd57f184ba36beca6fe8
|
data/README.md
CHANGED
@@ -20,9 +20,13 @@ Follow [@peterohler on Twitter](http://twitter.com/#!/peterohler) for announceme
|
|
20
20
|
|
21
21
|
[![Build Status](https://secure.travis-ci.org/ohler55/oj.png?branch=master)](http://travis-ci.org/ohler55/oj)
|
22
22
|
|
23
|
-
### Current Release 2.1.
|
23
|
+
### Current Release 2.1.7
|
24
24
|
|
25
|
-
- Added
|
25
|
+
- Added support for NaN and -NaN to address issue #102. This is not according to the JSON spec but seems to be expected.
|
26
|
+
|
27
|
+
- Added require for rational if the Ruby version is 1.8.7 to address issue #104.
|
28
|
+
|
29
|
+
- Added Rails re-call of Oj.dump in the to_json() method which caused loops with Rational objects to fix issue #108 and #105.
|
26
30
|
|
27
31
|
[Older release notes](http://www.ohler.com/dev/oj_misc/release_notes.html).
|
28
32
|
|
data/ext/oj/dump.c
CHANGED
@@ -105,6 +105,10 @@ static void dump_leaf_float(Leaf leaf, Out out);
|
|
105
105
|
static void dump_leaf_array(Leaf leaf, int depth, Out out);
|
106
106
|
static void dump_leaf_hash(Leaf leaf, int depth, Out out);
|
107
107
|
|
108
|
+
// These are used to detect rails re-call of Oj.dump() inside the to_json()
|
109
|
+
// method. It is not thread safe.
|
110
|
+
static VALUE last_obj = Qundef;
|
111
|
+
static int oj_rails_hack = -1;
|
108
112
|
|
109
113
|
static const char hex_chars[17] = "0123456789abcdef";
|
110
114
|
|
@@ -429,6 +433,9 @@ dump_float(VALUE obj, Out out) {
|
|
429
433
|
} else if (-OJ_INFINITY == d) {
|
430
434
|
strcpy(buf, "-Infinity");
|
431
435
|
cnt = 9;
|
436
|
+
} else if (isnan(d)) {
|
437
|
+
strcpy(buf, "NaN");
|
438
|
+
cnt = 3;
|
432
439
|
} else if (d == (double)(long long int)d) {
|
433
440
|
cnt = sprintf(buf, "%.1f", d); // used sprintf due to bug in snprintf
|
434
441
|
} else {
|
@@ -585,6 +592,10 @@ dump_array(VALUE a, int depth, Out out) {
|
|
585
592
|
if (id < 0) {
|
586
593
|
return;
|
587
594
|
}
|
595
|
+
|
596
|
+
#if HAS_GC_GUARD
|
597
|
+
RB_GC_GUARD(a);
|
598
|
+
#endif
|
588
599
|
np = RARRAY_PTR(a);
|
589
600
|
cnt = (int)RARRAY_LEN(a);
|
590
601
|
*out->cur++ = '[';
|
@@ -1121,10 +1132,16 @@ dump_data_comp(VALUE obj, int depth, Out out) {
|
|
1121
1132
|
dump_hash(h, depth, out->opts->mode, out);
|
1122
1133
|
} else if (rb_respond_to(obj, oj_as_json_id) && obj != (o2 = rb_funcall(obj, oj_as_json_id, 0))) {
|
1123
1134
|
dump_val(o2, depth, out);
|
1124
|
-
} else if (rb_respond_to(obj, oj_to_json_id)) {
|
1125
|
-
VALUE rs
|
1126
|
-
const char *s
|
1127
|
-
int len
|
1135
|
+
} else if (rb_respond_to(obj, oj_to_json_id) && (!oj_rails_hack || last_obj != obj)) {
|
1136
|
+
VALUE rs;
|
1137
|
+
const char *s;
|
1138
|
+
int len;
|
1139
|
+
|
1140
|
+
last_obj = obj;
|
1141
|
+
rs = rb_funcall(obj, oj_to_json_id, 0);
|
1142
|
+
last_obj = Qundef;
|
1143
|
+
s = StringValuePtr(rs);
|
1144
|
+
len = (int)RSTRING_LEN(rs);
|
1128
1145
|
|
1129
1146
|
if (out->end - out->cur <= len + 1) {
|
1130
1147
|
grow(out, len);
|
@@ -1199,6 +1216,9 @@ dump_data_obj(VALUE obj, int depth, Out out) {
|
|
1199
1216
|
|
1200
1217
|
static void
|
1201
1218
|
dump_obj_comp(VALUE obj, int depth, Out out) {
|
1219
|
+
#if HAS_GC_GUARD
|
1220
|
+
RB_GC_GUARD(obj);
|
1221
|
+
#endif
|
1202
1222
|
if (rb_respond_to(obj, oj_to_hash_id)) {
|
1203
1223
|
VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
|
1204
1224
|
|
@@ -1208,10 +1228,16 @@ dump_obj_comp(VALUE obj, int depth, Out out) {
|
|
1208
1228
|
dump_hash(h, depth, out->opts->mode, out);
|
1209
1229
|
} else if (rb_respond_to(obj, oj_as_json_id)) {
|
1210
1230
|
dump_val(rb_funcall(obj, oj_as_json_id, 0), depth, out);
|
1211
|
-
} else if (rb_respond_to(obj, oj_to_json_id)) {
|
1212
|
-
VALUE rs
|
1213
|
-
const char *s
|
1214
|
-
int len
|
1231
|
+
} else if (rb_respond_to(obj, oj_to_json_id) && (!oj_rails_hack || last_obj != obj)) {
|
1232
|
+
VALUE rs;
|
1233
|
+
const char *s;
|
1234
|
+
int len;
|
1235
|
+
|
1236
|
+
last_obj = obj;
|
1237
|
+
rs = rb_funcall(obj, oj_to_json_id, 0);
|
1238
|
+
last_obj = Qundef;
|
1239
|
+
s = StringValuePtr(rs);
|
1240
|
+
len = (int)RSTRING_LEN(rs);
|
1215
1241
|
|
1216
1242
|
if (out->end - out->cur <= len + 1) {
|
1217
1243
|
grow(out, len);
|
@@ -1661,6 +1687,9 @@ oj_dump_obj_to_json(VALUE obj, Options copts, Out out) {
|
|
1661
1687
|
oj_cache8_new(&out->circ_cache);
|
1662
1688
|
}
|
1663
1689
|
out->indent = copts->indent;
|
1690
|
+
if (0 > oj_rails_hack) {
|
1691
|
+
oj_rails_hack = (rb_const_defined_at(rb_cObject, rb_intern("ActiveSupport")));
|
1692
|
+
}
|
1664
1693
|
dump_val(obj, 0, out);
|
1665
1694
|
if (Yes == copts->circular) {
|
1666
1695
|
oj_cache8_delete(out->circ_cache);
|
@@ -1702,7 +1731,7 @@ void
|
|
1702
1731
|
oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
1703
1732
|
char buf[4096];
|
1704
1733
|
struct _Out out;
|
1705
|
-
|
1734
|
+
ssize_t size;
|
1706
1735
|
VALUE clas = rb_obj_class(stream);
|
1707
1736
|
VALUE s;
|
1708
1737
|
|
data/ext/oj/extconf.rb
CHANGED
@@ -30,6 +30,7 @@ dflags = {
|
|
30
30
|
'HAS_PROC_WITH_BLOCK' => ('ruby' == type && (('1' == version[0] && '9' == version[1]) || '2' <= version[0])) ? 1 : 0,
|
31
31
|
'HAS_GC_GUARD' => ('jruby' != type && 'rubinius' != type) ? 1 : 0,
|
32
32
|
'HAS_TOP_LEVEL_ST_H' => ('ree' == type || ('ruby' == type && '1' == version[0] && '8' == version[1])) ? 1 : 0,
|
33
|
+
'NEEDS_RATIONAL' => ('ruby' == type && '1' == version[0] && '8' == version[1]) ? 1 : 0,
|
33
34
|
'IS_WINDOWS' => is_windows ? 1 : 0,
|
34
35
|
'SAFE_CACHE' => is_windows ? 0 : 1,
|
35
36
|
}
|
data/ext/oj/object.c
CHANGED
@@ -199,7 +199,7 @@ hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, VALUE value) {
|
|
199
199
|
#if HAS_ENCODING_SUPPORT
|
200
200
|
s = rb_struct_alloc_noinit(sc);
|
201
201
|
#else
|
202
|
-
s = rb_struct_new(sc);
|
202
|
+
s = rb_struct_new(sc, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil);
|
203
203
|
#endif
|
204
204
|
sv = RSTRUCT_PTR(s);
|
205
205
|
if (RSTRUCT_LEN(s) < len - 1) {
|
data/ext/oj/oj.c
CHANGED
@@ -1007,6 +1007,9 @@ mimic_create_id(VALUE self, VALUE id) {
|
|
1007
1007
|
* raise an Exception but will not have any effect. The method can also be
|
1008
1008
|
* called after the json gem is loaded. The necessary methods on the json gem
|
1009
1009
|
* will be replaced with Oj methods.
|
1010
|
+
*
|
1011
|
+
* Note that this also sets the default options of :mode to :compat and
|
1012
|
+
* :ascii_only to true.
|
1010
1013
|
*/
|
1011
1014
|
static VALUE
|
1012
1015
|
define_mimic_json(int argc, VALUE *argv, VALUE self) {
|
@@ -1114,6 +1117,9 @@ void Init_oj() {
|
|
1114
1117
|
rb_require("time");
|
1115
1118
|
rb_require("date");
|
1116
1119
|
rb_require("bigdecimal");
|
1120
|
+
#if NEEDS_RATIONAL
|
1121
|
+
rb_require("rational");
|
1122
|
+
#endif
|
1117
1123
|
rb_require("stringio");
|
1118
1124
|
#if HAS_ENCODING_SUPPORT
|
1119
1125
|
oj_utf8_encoding = rb_enc_find("UTF-8");
|
data/ext/oj/parse.c
CHANGED
@@ -387,6 +387,7 @@ read_num(ParseInfo pi) {
|
|
387
387
|
ni.dec_cnt = 0;
|
388
388
|
ni.big = 0;
|
389
389
|
ni.infinity = 0;
|
390
|
+
ni.nan = 0;
|
390
391
|
ni.neg = 0;
|
391
392
|
|
392
393
|
if ('-' == *pi->cur) {
|
@@ -402,66 +403,73 @@ read_num(ParseInfo pi) {
|
|
402
403
|
}
|
403
404
|
pi->cur += 8;
|
404
405
|
ni.infinity = 1;
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
if (ni.big) {
|
410
|
-
ni.big++;
|
411
|
-
} else {
|
412
|
-
int d = (*pi->cur - '0');
|
413
|
-
|
414
|
-
if (0 == d) {
|
415
|
-
zero_cnt++;
|
416
|
-
} else {
|
417
|
-
zero_cnt = 0;
|
418
|
-
}
|
419
|
-
ni.i = ni.i * 10 + d;
|
420
|
-
if (LONG_MAX <= ni.i || DEC_MAX < ni.dec_cnt - zero_cnt) {
|
421
|
-
ni.big = 1;
|
422
|
-
}
|
406
|
+
} else if ('N' == *pi->cur || 'n' == *pi->cur) {
|
407
|
+
if ('a' != pi->cur[1] || ('N' != pi->cur[2] && 'n' != pi->cur[2])) {
|
408
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
409
|
+
return;
|
423
410
|
}
|
424
|
-
|
425
|
-
|
426
|
-
|
411
|
+
pi->cur += 3;
|
412
|
+
ni.nan = 1;
|
413
|
+
} else {
|
427
414
|
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
zero_cnt++;
|
415
|
+
ni.dec_cnt++;
|
416
|
+
if (ni.big) {
|
417
|
+
ni.big++;
|
432
418
|
} else {
|
433
|
-
|
419
|
+
int d = (*pi->cur - '0');
|
420
|
+
|
421
|
+
if (0 == d) {
|
422
|
+
zero_cnt++;
|
423
|
+
} else {
|
424
|
+
zero_cnt = 0;
|
425
|
+
}
|
426
|
+
ni.i = ni.i * 10 + d;
|
427
|
+
if (LONG_MAX <= ni.i || DEC_MAX < ni.dec_cnt - zero_cnt) {
|
428
|
+
ni.big = 1;
|
429
|
+
}
|
434
430
|
}
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
431
|
+
}
|
432
|
+
if ('.' == *pi->cur) {
|
433
|
+
pi->cur++;
|
434
|
+
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
435
|
+
int d = (*pi->cur - '0');
|
436
|
+
|
437
|
+
if (0 == d) {
|
438
|
+
zero_cnt++;
|
439
|
+
} else {
|
440
|
+
zero_cnt = 0;
|
441
|
+
}
|
442
|
+
ni.dec_cnt++;
|
443
|
+
ni.num = ni.num * 10 + d;
|
444
|
+
ni.div *= 10;
|
445
|
+
if (LONG_MAX <= ni.div || DEC_MAX < ni.dec_cnt - zero_cnt) {
|
446
|
+
ni.big = 1;
|
447
|
+
}
|
440
448
|
}
|
441
449
|
}
|
442
|
-
|
443
|
-
|
444
|
-
int eneg = 0;
|
450
|
+
if ('e' == *pi->cur || 'E' == *pi->cur) {
|
451
|
+
int eneg = 0;
|
445
452
|
|
446
|
-
pi->cur++;
|
447
|
-
if ('-' == *pi->cur) {
|
448
|
-
pi->cur++;
|
449
|
-
eneg = 1;
|
450
|
-
} else if ('+' == *pi->cur) {
|
451
453
|
pi->cur++;
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
if (
|
456
|
-
|
454
|
+
if ('-' == *pi->cur) {
|
455
|
+
pi->cur++;
|
456
|
+
eneg = 1;
|
457
|
+
} else if ('+' == *pi->cur) {
|
458
|
+
pi->cur++;
|
459
|
+
}
|
460
|
+
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
461
|
+
ni.exp = ni.exp * 10 + (*pi->cur - '0');
|
462
|
+
if (EXP_MAX <= ni.exp) {
|
463
|
+
ni.big = 1;
|
464
|
+
}
|
465
|
+
}
|
466
|
+
if (eneg) {
|
467
|
+
ni.exp = -ni.exp;
|
457
468
|
}
|
458
469
|
}
|
459
|
-
|
460
|
-
|
461
|
-
}
|
470
|
+
ni.dec_cnt -= zero_cnt;
|
471
|
+
ni.len = pi->cur - ni.str;
|
462
472
|
}
|
463
|
-
ni.dec_cnt -= zero_cnt;
|
464
|
-
ni.len = pi->cur - ni.str;
|
465
473
|
if (Yes == pi->options.bigdec_load) {
|
466
474
|
ni.big = 1;
|
467
475
|
}
|
@@ -603,6 +611,7 @@ oj_parse2(ParseInfo pi) {
|
|
603
611
|
case '8':
|
604
612
|
case '9':
|
605
613
|
case 'I':
|
614
|
+
case 'N':
|
606
615
|
pi->cur--;
|
607
616
|
read_num(pi);
|
608
617
|
break;
|
@@ -613,7 +622,12 @@ oj_parse2(ParseInfo pi) {
|
|
613
622
|
read_false(pi);
|
614
623
|
break;
|
615
624
|
case 'n':
|
616
|
-
|
625
|
+
if ('u' == *pi->cur) {
|
626
|
+
read_null(pi);
|
627
|
+
} else {
|
628
|
+
pi->cur--;
|
629
|
+
read_num(pi);
|
630
|
+
}
|
617
631
|
break;
|
618
632
|
case '/':
|
619
633
|
skip_comment(pi);
|
@@ -641,6 +655,8 @@ oj_num_as_value(NumInfo ni) {
|
|
641
655
|
} else {
|
642
656
|
rnum = rb_float_new(OJ_INFINITY);
|
643
657
|
}
|
658
|
+
} else if (ni->nan) {
|
659
|
+
rnum = rb_float_new(NAN);
|
644
660
|
} else if (1 == ni->div && 0 == ni->exp) { // fixnum
|
645
661
|
if (ni->big) {
|
646
662
|
if (256 > ni->len) {
|
data/ext/oj/parse.h
CHANGED
data/lib/oj/version.rb
CHANGED
data/test/test_scp.rb
CHANGED
@@ -217,7 +217,7 @@ class ScpTest < ::Test::Unit::TestCase
|
|
217
217
|
begin
|
218
218
|
Oj.sc_parse(handler, json)
|
219
219
|
rescue Exception => e
|
220
|
-
assert_equal("unexpected character at line 1, column 6 [parse.c:
|
220
|
+
assert_equal("unexpected character at line 1, column 6 [parse.c:639]", e.message)
|
221
221
|
end
|
222
222
|
end
|
223
223
|
|
data/test/tests.rb
CHANGED
@@ -105,6 +105,20 @@ class Range
|
|
105
105
|
end
|
106
106
|
end # Range
|
107
107
|
|
108
|
+
# define the symbol
|
109
|
+
class ActiveSupport
|
110
|
+
end
|
111
|
+
|
112
|
+
class RailsLike
|
113
|
+
attr_accessor :x
|
114
|
+
def initialize(x)
|
115
|
+
@x = x
|
116
|
+
end
|
117
|
+
def to_json(options = nil)
|
118
|
+
Oj.dump(self, :mode => :compat)
|
119
|
+
end
|
120
|
+
end # RailsLike
|
121
|
+
|
108
122
|
class Juice < ::Test::Unit::TestCase
|
109
123
|
|
110
124
|
def test0_get_options
|
@@ -185,6 +199,12 @@ class Juice < ::Test::Unit::TestCase
|
|
185
199
|
dump_and_load(2.48e16, false)
|
186
200
|
dump_and_load(2.48e100 * 1.0e10, false)
|
187
201
|
dump_and_load(-2.48e100 * 1.0e10, false)
|
202
|
+
dump_and_load(1/0.0, false)
|
203
|
+
# NaN does not always == NaN
|
204
|
+
json = Oj.dump(0/0.0)
|
205
|
+
assert_equal('NaN', json)
|
206
|
+
loaded = Oj.load(json);
|
207
|
+
assert_equal(true, loaded.nan?)
|
188
208
|
end
|
189
209
|
|
190
210
|
def test_string
|
@@ -1002,6 +1022,14 @@ class Juice < ::Test::Unit::TestCase
|
|
1002
1022
|
assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
|
1003
1023
|
end
|
1004
1024
|
|
1025
|
+
# Rails re-call test. Active support recalls the json dumper when the to_json
|
1026
|
+
# method is called. This mimics that and verifies Oj detects it.
|
1027
|
+
def test_rails_like
|
1028
|
+
obj = RailsLike.new(3)
|
1029
|
+
json = Oj.dump(obj, :mode => :compat)
|
1030
|
+
assert_equal('{"x":3}', json)
|
1031
|
+
end
|
1032
|
+
|
1005
1033
|
def dump_and_load(obj, trace=false)
|
1006
1034
|
json = Oj.dump(obj, :indent => 2)
|
1007
1035
|
puts json if trace
|
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.1.
|
4
|
+
version: 2.1.7
|
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-10-
|
11
|
+
date: 2013-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: 'The fastest JSON parser and object serializer. '
|
14
14
|
email: peter@ohler.com
|