oj 1.2.11 → 1.2.12
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of oj might be problematic. Click here for more details.
- data/README.md +11 -13
- data/ext/oj/dump.c +33 -0
- data/ext/oj/extconf.rb +1 -0
- data/ext/oj/fast.c +6 -2
- data/ext/oj/load.c +15 -0
- data/lib/oj/version.rb +1 -1
- data/test/boo.rb +26 -0
- data/test/bug.rb +18 -0
- data/test/{perf2.rb → foo.rb} +12 -30
- data/test/oj-test/test.rb +140 -0
- data/test/tests.rb +8 -4
- data/test/where.rb +54 -0
- metadata +26 -30
- data/test/perf1.rb +0 -64
- data/test/perf_obj_old.rb +0 -213
data/README.md
CHANGED
@@ -4,12 +4,20 @@ A fast JSON parser and Object marshaller as a Ruby gem.
|
|
4
4
|
## <a name="installation">Installation</a>
|
5
5
|
gem install oj
|
6
6
|
|
7
|
+
## <a name="documentation">Documentation</a>
|
8
|
+
|
9
|
+
*Documentation*: http://www.ohler.com/oj
|
10
|
+
|
7
11
|
## <a name="source">Source</a>
|
8
12
|
|
9
13
|
*GitHub* *repo*: https://github.com/ohler55/oj
|
10
14
|
|
11
15
|
*RubyGems* *repo*: https://rubygems.org/gems/oj
|
12
16
|
|
17
|
+
## <a name="follow">Follow @oxgem on Twitter</a>
|
18
|
+
|
19
|
+
[Follow @peterohler on Twitter](http://twitter.com/#!/peterohler) for announcements and news about the Oj gem.
|
20
|
+
|
13
21
|
## <a name="build_status">Build Status</a>
|
14
22
|
|
15
23
|
[![Build Status](https://secure.travis-ci.org/ohler55/oj.png?branch=master)](http://travis-ci.org/ohler55/oj)
|
@@ -24,21 +32,11 @@ A fast JSON parser and Object marshaller as a Ruby gem.
|
|
24
32
|
|
25
33
|
## <a name="release">Release Notes</a>
|
26
34
|
|
27
|
-
### Release 1.2.
|
28
|
-
|
29
|
-
- Added :max_stack option to limit the size of string allocated on the stack.
|
30
|
-
|
31
|
-
### Release 1.2.10
|
32
|
-
|
33
|
-
- Added check for circular on loading of circular dumped JSON.
|
34
|
-
|
35
|
-
- Added support for direct serialization of BigDecimal, Rational, Date, and DateTime.
|
36
|
-
|
37
|
-
- Added json.rb to $" in mimic mode to avoid pulling in the real JSON by accident.
|
35
|
+
### Release 1.2.12
|
38
36
|
|
39
|
-
-
|
37
|
+
- Fixed GC bug in Oj::Doc, the fast parser.
|
40
38
|
|
41
|
-
-
|
39
|
+
- Serialization of Exceptions in Ruby 1.8.7 now includes message and backtrace.
|
42
40
|
|
43
41
|
## <a name="description">Description</a>
|
44
42
|
|
data/ext/oj/dump.c
CHANGED
@@ -1146,6 +1146,39 @@ dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out) {
|
|
1146
1146
|
}
|
1147
1147
|
#else
|
1148
1148
|
size = d2 * out->indent + 1;
|
1149
|
+
#if HAS_EXCEPTION_MAGIC
|
1150
|
+
if (Qtrue == rb_obj_is_kind_of(obj, rb_eException)) {
|
1151
|
+
if (',' != *(out->cur - 1)) {
|
1152
|
+
*out->cur++ = ',';
|
1153
|
+
}
|
1154
|
+
// message
|
1155
|
+
if (out->end - out->cur <= (long)size) {
|
1156
|
+
grow(out, size);
|
1157
|
+
}
|
1158
|
+
fill_indent(out, d2);
|
1159
|
+
dump_cstr("~mesg", 5, 0, 0, out);
|
1160
|
+
*out->cur++ = ':';
|
1161
|
+
dump_val(rb_funcall2(obj, rb_intern("message"), 0, 0), d2, out);
|
1162
|
+
if (out->end - out->cur <= 2) {
|
1163
|
+
grow(out, 2);
|
1164
|
+
}
|
1165
|
+
*out->cur++ = ',';
|
1166
|
+
// backtrace
|
1167
|
+
if (out->end - out->cur <= (long)size) {
|
1168
|
+
grow(out, size);
|
1169
|
+
}
|
1170
|
+
fill_indent(out, d2);
|
1171
|
+
dump_cstr("~bt", 3, 0, 0, out);
|
1172
|
+
*out->cur++ = ':';
|
1173
|
+
dump_val(rb_funcall2(obj, rb_intern("backtrace"), 0, 0), d2, out);
|
1174
|
+
if (out->end - out->cur <= 2) {
|
1175
|
+
grow(out, 2);
|
1176
|
+
}
|
1177
|
+
if (0 < cnt) {
|
1178
|
+
*out->cur++ = ',';
|
1179
|
+
}
|
1180
|
+
}
|
1181
|
+
#endif
|
1149
1182
|
for (i = cnt; 0 < i; i--, np++) {
|
1150
1183
|
if (out->end - out->cur <= (long)size) {
|
1151
1184
|
grow(out, size);
|
data/ext/oj/extconf.rb
CHANGED
@@ -22,6 +22,7 @@ dflags = {
|
|
22
22
|
'HAS_NANO_TIME' => ('ruby' == type && ('1' == version[0] && '9' == version[1]) || '2' <= version[0]) ? 1 : 0,
|
23
23
|
'HAS_RSTRUCT' => ('ruby' == type || 'ree' == type) ? 1 : 0,
|
24
24
|
'HAS_IVAR_HELPERS' => ('ruby' == type && ('1' == version[0] && '9' == version[1]) || '2' <= version[0]) ? 1 : 0,
|
25
|
+
'HAS_EXCEPTION_MAGIC' => ('ruby' == type && ('1' == version[0] && '9' == version[1]) || '2' <= version[0]) ? 0 : 1,
|
25
26
|
'HAS_PROC_WITH_BLOCK' => ('ruby' == type && ('1' == version[0] && '9' == version[1]) || '2' <= version[0]) ? 1 : 0,
|
26
27
|
'HAS_TOP_LEVEL_ST_H' => ('ree' == type || ('ruby' == type && '1' == version[0] && '8' == version[1])) ? 1 : 0,
|
27
28
|
'SAFE_CACHE' => nil,
|
data/ext/oj/fast.c
CHANGED
@@ -562,7 +562,7 @@ read_obj(ParseInfo pi) {
|
|
562
562
|
} else if (',' == *pi->s) {
|
563
563
|
pi->s++;
|
564
564
|
} else {
|
565
|
-
printf("*** '%s'\n", pi->s);
|
565
|
+
//printf("*** '%s'\n", pi->s);
|
566
566
|
raise_error("invalid format, expected , or } while in an object", pi->str, pi->s);
|
567
567
|
}
|
568
568
|
*end = '\0';
|
@@ -839,10 +839,12 @@ parse_json(VALUE clas, char *json, int given, int allocated) {
|
|
839
839
|
pi.doc = doc;
|
840
840
|
// last arg is free func void* func(void*)
|
841
841
|
doc->self = rb_data_object_alloc(clas, doc, 0, free_doc_cb);
|
842
|
+
rb_gc_register_address(&doc->self);
|
842
843
|
doc->json = json;
|
843
844
|
DATA_PTR(doc->self) = doc;
|
844
845
|
result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
|
845
846
|
if (given || 0 != ex) {
|
847
|
+
rb_gc_unregister_address(&doc->self);
|
846
848
|
DATA_PTR(doc->self) = 0;
|
847
849
|
doc_free(pi.doc);
|
848
850
|
if (allocated) {
|
@@ -1318,11 +1320,12 @@ doc_type(int argc, VALUE *argv, VALUE self) {
|
|
1318
1320
|
*/
|
1319
1321
|
static VALUE
|
1320
1322
|
doc_fetch(int argc, VALUE *argv, VALUE self) {
|
1321
|
-
Doc doc
|
1323
|
+
Doc doc;
|
1322
1324
|
Leaf leaf;
|
1323
1325
|
VALUE val = Qnil;
|
1324
1326
|
const char *path = 0;
|
1325
1327
|
|
1328
|
+
doc = self_doc(self);
|
1326
1329
|
if (1 <= argc) {
|
1327
1330
|
Check_Type(*argv, T_STRING);
|
1328
1331
|
path = StringValuePtr(*argv);
|
@@ -1584,6 +1587,7 @@ static VALUE
|
|
1584
1587
|
doc_close(VALUE self) {
|
1585
1588
|
Doc doc = self_doc(self);
|
1586
1589
|
|
1590
|
+
rb_gc_unregister_address(&doc->self);
|
1587
1591
|
DATA_PTR(doc->self) = 0;
|
1588
1592
|
if (0 != doc) {
|
1589
1593
|
xfree(doc->json);
|
data/ext/oj/load.c
CHANGED
@@ -510,7 +510,22 @@ read_obj(ParseInfo pi) {
|
|
510
510
|
#ifdef SAFE_CACHE
|
511
511
|
pthread_mutex_unlock(&oj_cache_mutex);
|
512
512
|
#endif
|
513
|
+
#if HAS_EXCEPTION_MAGIC
|
514
|
+
if ('~' == *ks && Qtrue == rb_obj_is_kind_of(obj, rb_eException)) {
|
515
|
+
if (0 == strcmp("~mesg", ks)) {
|
516
|
+
VALUE args[1];
|
517
|
+
|
518
|
+
args[0] = val;
|
519
|
+
obj = rb_class_new_instance(1, args, rb_class_of(obj));
|
520
|
+
} else if (0 == strcmp("~bt", ks)) {
|
521
|
+
rb_funcall(obj, rb_intern("set_backtrace"), 1, val);
|
522
|
+
}
|
523
|
+
} else {
|
524
|
+
rb_ivar_set(obj, var_id, val);
|
525
|
+
}
|
526
|
+
#else
|
513
527
|
rb_ivar_set(obj, var_id, val);
|
528
|
+
#endif
|
514
529
|
} else if (T_HASH == obj_type) {
|
515
530
|
if (Yes == pi->options->sym_key) {
|
516
531
|
rb_hash_aset(obj, rb_str_intern(key), val);
|
data/lib/oj/version.rb
CHANGED
data/test/boo.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby -wW1
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
$: << File.join(File.dirname(__FILE__), "../lib")
|
5
|
+
$: << File.join(File.dirname(__FILE__), "../ext")
|
6
|
+
|
7
|
+
require 'yajl'
|
8
|
+
require 'oj'
|
9
|
+
|
10
|
+
iter = 100
|
11
|
+
s = File.read("boo.json")
|
12
|
+
start = Time.now
|
13
|
+
iter.times do
|
14
|
+
Oj.load(s)
|
15
|
+
end
|
16
|
+
oj_dt = Time.now - start
|
17
|
+
puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/second" % [iter, oj_dt, iter/oj_dt]
|
18
|
+
|
19
|
+
start = Time.now
|
20
|
+
iter.times do
|
21
|
+
Yajl::Parser.parse(s)
|
22
|
+
end
|
23
|
+
yajl_dt = Time.now - start
|
24
|
+
puts "%d Yajl::Parser.parse()s in %0.3f seconds or %0.1f parsed/second" % [iter, yajl_dt, iter/yajl_dt]
|
25
|
+
|
26
|
+
puts "Oj is %0.1f times faster than YAJL" % [yajl_dt / oj_dt]
|
data/test/bug.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
$: << File.join(File.dirname(__FILE__), "../lib")
|
3
|
+
$: << File.join(File.dirname(__FILE__), "../ext")
|
4
|
+
|
5
|
+
require 'oj'
|
6
|
+
require 'bigdecimal'
|
7
|
+
|
8
|
+
stuff = [
|
9
|
+
BigDecimal.new('10'),
|
10
|
+
Date.today,
|
11
|
+
Time.now,
|
12
|
+
DateTime.now
|
13
|
+
]
|
14
|
+
|
15
|
+
puts Oj.dump(stuff, :mode => :strict)
|
16
|
+
puts Oj.dump(stuff, :mode => :compat)
|
17
|
+
puts Oj.dump(stuff, :mode => :object)
|
18
|
+
|
data/test/{perf2.rb → foo.rb}
RENAMED
@@ -15,19 +15,6 @@ opts = OptionParser.new
|
|
15
15
|
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
|
16
16
|
files = opts.parse(ARGV)
|
17
17
|
|
18
|
-
class Foo
|
19
|
-
def initialize()
|
20
|
-
@x = true
|
21
|
-
@y = 58
|
22
|
-
end
|
23
|
-
def to_json()
|
24
|
-
%{{"x":#{@x},"y":#{@y}}}
|
25
|
-
end
|
26
|
-
def to_hash()
|
27
|
-
{ 'x' => @x, 'y' => @y }
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
18
|
iter = 100000
|
32
19
|
s = %{
|
33
20
|
{ "class": "Foo::Bar",
|
@@ -36,41 +23,36 @@ s = %{
|
|
36
23
|
}
|
37
24
|
}
|
38
25
|
|
39
|
-
obj = Oj.load(s)
|
40
|
-
obj["foo"] = Foo.new()
|
41
|
-
|
42
|
-
Oj.default_options = { :indent => 0, :effort => :internal }
|
43
|
-
|
44
|
-
puts
|
45
|
-
|
46
26
|
start = Time.now
|
47
27
|
iter.times do
|
48
28
|
Oj.load(s)
|
49
29
|
end
|
50
|
-
|
51
|
-
puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/msec" % [iter,
|
30
|
+
oj_dt = Time.now - start
|
31
|
+
puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/msec" % [iter, oj_dt, iter/oj_dt/1000.0]
|
52
32
|
|
53
33
|
start = Time.now
|
54
34
|
iter.times do
|
55
35
|
Yajl::Parser.parse(s)
|
56
36
|
end
|
57
|
-
|
58
|
-
puts "%d Yajl::Parser.parse()s in %0.3f seconds or %0.1f parses/msec" % [iter,
|
37
|
+
yajl_dt = Time.now - start
|
38
|
+
puts "%d Yajl::Parser.parse()s in %0.3f seconds or %0.1f parses/msec" % [iter, yajl_dt, iter/yajl_dt/1000.0]
|
59
39
|
|
60
|
-
puts
|
40
|
+
puts "Oj is %0.1f times faster than YAJL at parsing." % [yajl_dt / oj_dt]
|
61
41
|
|
42
|
+
|
43
|
+
obj = Oj.load(s)
|
62
44
|
start = Time.now
|
63
45
|
iter.times do
|
64
46
|
Oj.dump(obj)
|
65
47
|
end
|
66
|
-
|
67
|
-
puts "%d Oj.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter,
|
48
|
+
oj_dt = Time.now - start
|
49
|
+
puts "%d Oj.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter, oj_dt, iter/oj_dt/1000.0]
|
68
50
|
|
69
51
|
start = Time.now
|
70
52
|
iter.times do
|
71
53
|
Yajl::Encoder.encode(obj)
|
72
54
|
end
|
73
|
-
|
74
|
-
puts "%d Yajl::Encoder.encode()s in %0.3f seconds or %0.1f encodes/msec" % [iter,
|
55
|
+
yajl_dt = Time.now - start
|
56
|
+
puts "%d Yajl::Encoder.encode()s in %0.3f seconds or %0.1f encodes/msec" % [iter, yajl_dt, iter/yajl_dt/1000.0]
|
75
57
|
|
76
|
-
puts
|
58
|
+
puts "Oj is %0.1f times faster than YAJL at dumping." % [yajl_dt / oj_dt]
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'oj'
|
3
|
+
|
4
|
+
AD_MARKUP = CGI.escape("asdf" * 100)
|
5
|
+
|
6
|
+
SEATBID = '{
|
7
|
+
"bid" : [{
|
8
|
+
"id": "1",
|
9
|
+
"impid" : "102",
|
10
|
+
"price": 9.43,
|
11
|
+
"adid" : "314",
|
12
|
+
"nurl": "http://adserver.com/winnotice?impid=102",
|
13
|
+
"adm" : "' + AD_MARKUP + '",
|
14
|
+
"adomain" : ["advertiserdomain.com"],
|
15
|
+
"iurl" : "http://adserver.com/pathtosampleimage",
|
16
|
+
"cid" : "campaign111",
|
17
|
+
"crid" : "creative112",
|
18
|
+
"attr" : [1,2,3,4,5,6,7,12]
|
19
|
+
}],
|
20
|
+
"seat" : "512",
|
21
|
+
"group" : "128"
|
22
|
+
}'
|
23
|
+
|
24
|
+
|
25
|
+
LARGE_JSON = '{
|
26
|
+
"id": "1234567890",
|
27
|
+
"units" : 0,
|
28
|
+
"bidid": "abc1123",
|
29
|
+
"cur": "EUR",
|
30
|
+
"seatbid": [' + ([SEATBID] * 100).join(', ') + ']
|
31
|
+
}'
|
32
|
+
|
33
|
+
|
34
|
+
class Bid
|
35
|
+
|
36
|
+
attr_accessor :id,
|
37
|
+
:bidid,
|
38
|
+
:cur,
|
39
|
+
:seat,
|
40
|
+
:group,
|
41
|
+
:impid,
|
42
|
+
:price,
|
43
|
+
:units,
|
44
|
+
:adid,
|
45
|
+
:nurl,
|
46
|
+
:adm,
|
47
|
+
:adomain,
|
48
|
+
:iurl,
|
49
|
+
:cid,
|
50
|
+
:crid,
|
51
|
+
:attr,
|
52
|
+
:nbr,
|
53
|
+
:partner_id
|
54
|
+
|
55
|
+
alias :currency :cur
|
56
|
+
alias :auction_id :id
|
57
|
+
|
58
|
+
def parsed_adm
|
59
|
+
return replace_macros(self.adm)
|
60
|
+
end
|
61
|
+
|
62
|
+
def parsed_nurl
|
63
|
+
return replace_macros(self.nurl)
|
64
|
+
end
|
65
|
+
|
66
|
+
def replace_macros(template)
|
67
|
+
return nil if !template
|
68
|
+
{
|
69
|
+
'${AUCTION_ID}' => self.id,
|
70
|
+
'${AUCTION_BID_ID}' => self.bidid,
|
71
|
+
'${AUCTION_IMP_ID}' => self.impid,
|
72
|
+
'${AUCTION_SEAT_ID}' => self.seat,
|
73
|
+
'${AUCTION_AD_ID}' => self.adid,
|
74
|
+
'${AUCTION_PRICE}' => self.price,
|
75
|
+
'${AUCTION_CURRENCY}' => self.cur,
|
76
|
+
'${AUCTION_UNITS}' => self.units,
|
77
|
+
}.each do |macro, v|
|
78
|
+
template = template.gsub(macro, v.to_s)
|
79
|
+
end
|
80
|
+
template
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
#GC.disable
|
85
|
+
|
86
|
+
class BidResponseParser
|
87
|
+
REQUIRED_ATTRIBUTES = [:id, :impid, :price].freeze
|
88
|
+
|
89
|
+
def self.parse(json)
|
90
|
+
return nil if !json
|
91
|
+
extract_fast(json)
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.extract_fast(json)
|
95
|
+
doc = Oj::Doc.open(json)
|
96
|
+
#Oj::Doc.open(json) do |doc|
|
97
|
+
bid = Bid.new
|
98
|
+
|
99
|
+
# bid-response object
|
100
|
+
bid.id = doc.fetch '/id'
|
101
|
+
|
102
|
+
bid.bidid = doc.fetch '/bidid'
|
103
|
+
bid.units = doc.fetch('/units') || 0
|
104
|
+
bid.cur = doc.fetch '/cur'
|
105
|
+
bid.nbr = doc.fetch('/nbr') || 0 # Mobile RTB 1.0 only
|
106
|
+
|
107
|
+
# EM: we do not expect more than 1 bid object in the response,
|
108
|
+
# as we only send single ads in the bid-request (no multi-ad-auctions) atm.
|
109
|
+
# seatbid-obj
|
110
|
+
bid.seat = doc.fetch '/seatbid/0/seat'
|
111
|
+
bid.group = doc.fetch '/seatbid/0/group'
|
112
|
+
|
113
|
+
# bid-obj
|
114
|
+
bid_path = '/seatbid/0/bid/0'
|
115
|
+
bid.impid = doc.fetch "#{bid_path}/impid"
|
116
|
+
bid.adid = doc.fetch "#{bid_path}/adid"
|
117
|
+
bid.nurl = doc.fetch "#{bid_path}/nurl"
|
118
|
+
bid.adm = doc.fetch "#{bid_path}/adm"
|
119
|
+
bid.adomain = doc.fetch "#{bid_path}/adomain"
|
120
|
+
bid.iurl = doc.fetch "#{bid_path}/iurl"
|
121
|
+
bid.cid = doc.fetch "#{bid_path}/cid"
|
122
|
+
bid.crid = doc.fetch "#{bid_path}/crid"
|
123
|
+
bid.attr = doc.fetch "#{bid_path}/attr"
|
124
|
+
|
125
|
+
# sadly we need to check this explicitly, because nil.to_f returns 0.0
|
126
|
+
if doc.fetch("#{bid_path}/price") == nil
|
127
|
+
raise "required attribute price missing"
|
128
|
+
end
|
129
|
+
|
130
|
+
bid.price = doc.fetch("#{bid_path}/price").to_f
|
131
|
+
|
132
|
+
doc.close # needed when not in Proc to cleanup
|
133
|
+
return bid
|
134
|
+
#end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
1000.times do
|
139
|
+
BidResponseParser.parse(LARGE_JSON)
|
140
|
+
end
|
data/test/tests.rb
CHANGED
@@ -519,10 +519,14 @@ class Juice < ::Test::Unit::TestCase
|
|
519
519
|
#puts "*** #{json}"
|
520
520
|
e2 = Oj.load(json, :mode => :strict)
|
521
521
|
assert_equal(err.class.to_s, e2['^o'])
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
522
|
+
assert_equal(err.message, e2['~mesg'])
|
523
|
+
assert_equal(err.backtrace, e2['~bt'])
|
524
|
+
e2 = Oj.load(json, :mode => :object)
|
525
|
+
if RUBY_VERSION.start_with?('1.8') || 'rubinius' == $ruby
|
526
|
+
assert_equal(e.class, e2.class);
|
527
|
+
assert_equal(e.message, e2.message);
|
528
|
+
assert_equal(e.backtrace, e2.backtrace);
|
529
|
+
else
|
526
530
|
assert_equal(e, e2);
|
527
531
|
end
|
528
532
|
end
|
data/test/where.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env ruby -wW1
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
$: << '.'
|
5
|
+
$: << File.join(File.dirname(__FILE__), "../lib")
|
6
|
+
$: << File.join(File.dirname(__FILE__), "../ext")
|
7
|
+
|
8
|
+
require 'optparse'
|
9
|
+
require 'perf'
|
10
|
+
require 'oj'
|
11
|
+
|
12
|
+
$verbose = false
|
13
|
+
$indent = 0
|
14
|
+
$iter = 1000000
|
15
|
+
|
16
|
+
opts = OptionParser.new
|
17
|
+
opts.on("-v", "verbose") { $verbose = true }
|
18
|
+
opts.on("-c", "--count [Int]", Integer, "iterations") { |i| $iter = i }
|
19
|
+
opts.on("-i", "--indent [Int]", Integer, "indentation") { |i| $indent = i }
|
20
|
+
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
|
21
|
+
files = opts.parse(ARGV)
|
22
|
+
|
23
|
+
$obj = {
|
24
|
+
'a' => 'Alpha', # string
|
25
|
+
'b' => true, # boolean
|
26
|
+
'c' => 12345, # number
|
27
|
+
'd' => [ true, [false, [12345, nil], 3.967, ['something', false], nil]], # mix it up array
|
28
|
+
'e' => { 'one' => 1, 'two' => 2 }, # hash
|
29
|
+
'f' => nil, # nil
|
30
|
+
'g' => 12345678901234567890123456789, # big number
|
31
|
+
'h' => { 'a' => { 'b' => { 'c' => { 'd' => {'e' => { 'f' => { 'g' => nil }}}}}}}, # deep hash, not that deep
|
32
|
+
'i' => [[[[[[[nil]]]]]]] # deep array, again, not that deep
|
33
|
+
}
|
34
|
+
|
35
|
+
Oj.default_options = { :indent => $indent, :mode => :strict }
|
36
|
+
|
37
|
+
$json = Oj.dump($obj)
|
38
|
+
|
39
|
+
if $verbose
|
40
|
+
puts "json:\n#{$json}\n"
|
41
|
+
end
|
42
|
+
|
43
|
+
puts '-' * 80
|
44
|
+
puts "Parse Performance"
|
45
|
+
Oj::Fast.open($json) do |fast|
|
46
|
+
fast.move('/d/2/4/2')
|
47
|
+
puts fast.where2?
|
48
|
+
puts fast.where?
|
49
|
+
perf = Perf.new()
|
50
|
+
perf.add('Oj:fast', 'where') { fast.where? }
|
51
|
+
perf.add('Oj:fast2', 'where2') { fast.where2? }
|
52
|
+
perf.run($iter)
|
53
|
+
end
|
54
|
+
puts
|
metadata
CHANGED
@@ -1,27 +1,24 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: oj
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.12
|
4
5
|
prerelease:
|
5
|
-
version: 1.2.11
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Peter Ohler
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
date: 2012-06-21 00:00:00 Z
|
12
|
+
date: 2012-07-06 00:00:00.000000000 Z
|
14
13
|
dependencies: []
|
15
|
-
|
16
|
-
description: "The fastest JSON parser and object serializer. "
|
14
|
+
description: ! 'The fastest JSON parser and object serializer. '
|
17
15
|
email: peter@ohler.com
|
18
16
|
executables: []
|
19
|
-
|
20
|
-
extensions:
|
17
|
+
extensions:
|
21
18
|
- ext/oj/extconf.rb
|
22
|
-
extra_rdoc_files:
|
19
|
+
extra_rdoc_files:
|
23
20
|
- README.md
|
24
|
-
files:
|
21
|
+
files:
|
25
22
|
- lib/oj/bag.rb
|
26
23
|
- lib/oj/version.rb
|
27
24
|
- lib/oj.rb
|
@@ -35,13 +32,14 @@ files:
|
|
35
32
|
- ext/oj/fast.c
|
36
33
|
- ext/oj/load.c
|
37
34
|
- ext/oj/oj.c
|
35
|
+
- test/boo.rb
|
36
|
+
- test/bug.rb
|
38
37
|
- test/files.rb
|
38
|
+
- test/foo.rb
|
39
|
+
- test/oj-test/test.rb
|
39
40
|
- test/perf.rb
|
40
|
-
- test/perf1.rb
|
41
|
-
- test/perf2.rb
|
42
41
|
- test/perf_fast.rb
|
43
42
|
- test/perf_obj.rb
|
44
|
-
- test/perf_obj_old.rb
|
45
43
|
- test/perf_simple.rb
|
46
44
|
- test/perf_strict.rb
|
47
45
|
- test/sample/change.rb
|
@@ -61,37 +59,35 @@ files:
|
|
61
59
|
- test/test_fast.rb
|
62
60
|
- test/test_mimic.rb
|
63
61
|
- test/tests.rb
|
62
|
+
- test/where.rb
|
64
63
|
- LICENSE
|
65
64
|
- README.md
|
66
65
|
homepage: http://www.ohler.com/oj
|
67
66
|
licenses: []
|
68
|
-
|
69
67
|
post_install_message:
|
70
|
-
rdoc_options:
|
68
|
+
rdoc_options:
|
71
69
|
- --main
|
72
70
|
- README.md
|
73
|
-
require_paths:
|
71
|
+
require_paths:
|
74
72
|
- lib
|
75
73
|
- ext
|
76
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
75
|
none: false
|
78
|
-
requirements:
|
79
|
-
- -
|
80
|
-
- !ruby/object:Gem::Version
|
81
|
-
version:
|
82
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
81
|
none: false
|
84
|
-
requirements:
|
85
|
-
- -
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
version:
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
88
86
|
requirements: []
|
89
|
-
|
90
87
|
rubyforge_project: oj
|
91
88
|
rubygems_version: 1.8.23
|
92
89
|
signing_key:
|
93
90
|
specification_version: 3
|
94
91
|
summary: A fast JSON parser and serializer.
|
95
92
|
test_files: []
|
96
|
-
|
97
93
|
has_rdoc: true
|
data/test/perf1.rb
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby -wW1
|
2
|
-
# encoding: UTF-8
|
3
|
-
|
4
|
-
$: << File.join(File.dirname(__FILE__), "../lib")
|
5
|
-
$: << File.join(File.dirname(__FILE__), "../ext")
|
6
|
-
|
7
|
-
#require 'test/unit'
|
8
|
-
require 'optparse'
|
9
|
-
require 'oj'
|
10
|
-
require 'ox'
|
11
|
-
|
12
|
-
$indent = 2
|
13
|
-
|
14
|
-
opts = OptionParser.new
|
15
|
-
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
|
16
|
-
files = opts.parse(ARGV)
|
17
|
-
|
18
|
-
iter = 100000
|
19
|
-
s = %{
|
20
|
-
{ "class": "Foo::Bar",
|
21
|
-
"attr1": [ true, [false, [12345, null], 3.967, ["something", false], null]],
|
22
|
-
"attr2": { "one": 1 }
|
23
|
-
}
|
24
|
-
}
|
25
|
-
#s = File.read('sample.json')
|
26
|
-
|
27
|
-
Oj.default_options = { :indent => 0 }
|
28
|
-
|
29
|
-
obj = Oj.load(s)
|
30
|
-
xml = Ox.dump(obj, :indent => 0)
|
31
|
-
|
32
|
-
puts xml
|
33
|
-
|
34
|
-
start = Time.now
|
35
|
-
iter.times do
|
36
|
-
Oj.load(s)
|
37
|
-
end
|
38
|
-
dt = Time.now - start
|
39
|
-
puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/msec" % [iter, dt, iter/dt/1000.0]
|
40
|
-
|
41
|
-
start = Time.now
|
42
|
-
iter.times do
|
43
|
-
Ox.load(xml)
|
44
|
-
end
|
45
|
-
dt = Time.now - start
|
46
|
-
puts "%d Ox.load()s in %0.3f seconds or %0.1f loads/msec" % [iter, dt, iter/dt/1000.0]
|
47
|
-
|
48
|
-
puts
|
49
|
-
|
50
|
-
start = Time.now
|
51
|
-
iter.times do
|
52
|
-
Oj.dump(obj)
|
53
|
-
end
|
54
|
-
dt = Time.now - start
|
55
|
-
puts "%d Oj.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter, dt, iter/dt/1000.0]
|
56
|
-
|
57
|
-
start = Time.now
|
58
|
-
iter.times do
|
59
|
-
Ox.dump(obj)
|
60
|
-
end
|
61
|
-
dt = Time.now - start
|
62
|
-
puts "%d Ox.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter, dt, iter/dt/1000.0]
|
63
|
-
|
64
|
-
puts
|
data/test/perf_obj_old.rb
DELETED
@@ -1,213 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby -wW1
|
2
|
-
|
3
|
-
$: << '.'
|
4
|
-
$: << '..'
|
5
|
-
$: << '../lib'
|
6
|
-
$: << '../ext'
|
7
|
-
|
8
|
-
if __FILE__ == $0
|
9
|
-
if (i = ARGV.index('-I'))
|
10
|
-
x,path = ARGV.slice!(i, 2)
|
11
|
-
$: << path
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
require 'optparse'
|
16
|
-
require 'ox'
|
17
|
-
require 'oj'
|
18
|
-
require 'perf'
|
19
|
-
require 'sample'
|
20
|
-
require 'files'
|
21
|
-
|
22
|
-
$verbose = 0
|
23
|
-
$circular = false
|
24
|
-
$indent = 0
|
25
|
-
|
26
|
-
do_sample = false
|
27
|
-
do_files = false
|
28
|
-
|
29
|
-
do_load = false
|
30
|
-
do_dump = false
|
31
|
-
do_read = false
|
32
|
-
do_write = false
|
33
|
-
$iter = 1000
|
34
|
-
|
35
|
-
opts = OptionParser.new
|
36
|
-
opts.on("-v", "increase verbosity") { $verbose += 1 }
|
37
|
-
|
38
|
-
opts.on("-c", "circular options") { $circular = true }
|
39
|
-
|
40
|
-
opts.on("-s", "load and dump as sample Ruby object") { do_sample = true }
|
41
|
-
opts.on("-f", "load and dump as files Ruby object") { do_files = true }
|
42
|
-
|
43
|
-
opts.on("-l", "load") { do_load = true }
|
44
|
-
opts.on("-d", "dump") { do_dump = true }
|
45
|
-
opts.on("-r", "read") { do_read = true }
|
46
|
-
opts.on("-w", "write") { do_write = true }
|
47
|
-
opts.on("-a", "load, dump, read and write") { do_load = true; do_dump = true; do_read = true; do_write = true }
|
48
|
-
|
49
|
-
opts.on("-i", "--iterations [Int]", Integer, "iterations") { |i| $iter = i }
|
50
|
-
|
51
|
-
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
|
52
|
-
files = opts.parse(ARGV)
|
53
|
-
|
54
|
-
if files.empty?
|
55
|
-
data = []
|
56
|
-
obj = do_sample ? sample_doc(2) : files('..')
|
57
|
-
mars = Marshal.dump(obj)
|
58
|
-
xml = Ox.dump(obj, :indent => $indent, circular: $circular)
|
59
|
-
json = Oj.dump(obj, :indent => $indent, circular: $circular)
|
60
|
-
File.open('sample.xml', 'w') { |f| f.write(xml) }
|
61
|
-
File.open('sample.json', 'w') { |f| f.write(json) }
|
62
|
-
File.open('sample.marshal', 'w') { |f| f.write(mars) }
|
63
|
-
data << { :file => 'sample.xml', :obj => obj, :xml => xml, :marshal => mars, :json => json }
|
64
|
-
else
|
65
|
-
puts "loading and parsing #{files}\n\n"
|
66
|
-
# TBD change to allow xml and json
|
67
|
-
data = files.map do |f|
|
68
|
-
xml = File.read(f)
|
69
|
-
obj = Ox.load(xml);
|
70
|
-
mars = Marshal.dump(obj)
|
71
|
-
json = Oj.dump(obj, :indent => $indent, circular: $circular)
|
72
|
-
{ :file => f, :obj => obj, :xml => xml, :marshal => mars, :json => json }
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
$ox_load_time = 0
|
77
|
-
$mars_load_time = 0
|
78
|
-
$ox_dump_time = 0
|
79
|
-
$oj_dump_time = 0
|
80
|
-
$mars_dump_time = 0
|
81
|
-
|
82
|
-
def perf_load(d)
|
83
|
-
filename = d[:file]
|
84
|
-
marshal_filename = 'sample.marshal'
|
85
|
-
xml = d[:xml]
|
86
|
-
mars = d[:marshal]
|
87
|
-
json = d[:json]
|
88
|
-
|
89
|
-
if 0 < $verbose
|
90
|
-
obj = Ox.load(xml, :mode => :object, :trace => $verbose)
|
91
|
-
return
|
92
|
-
end
|
93
|
-
start = Time.now
|
94
|
-
(1..$iter).each do
|
95
|
-
obj = Ox.load(xml, :mode => :object)
|
96
|
-
end
|
97
|
-
$ox_load_time = Time.now - start
|
98
|
-
puts "Parsing #{$iter} times with Ox took #{$ox_load_time} seconds."
|
99
|
-
|
100
|
-
start = Time.now
|
101
|
-
(1..$iter).each do
|
102
|
-
obj = Oj.load(json, :mode => :object)
|
103
|
-
end
|
104
|
-
$oj_load_time = Time.now - start
|
105
|
-
puts "Parsing #{$iter} times with Oj took #{$oj_load_time} seconds."
|
106
|
-
|
107
|
-
start = Time.now
|
108
|
-
(1..$iter).each do
|
109
|
-
obj = Marshal.load(mars)
|
110
|
-
end
|
111
|
-
$mars_load_time = Time.now - start
|
112
|
-
puts "Marshalling #{$iter} times took #{$mars_load_time} seconds."
|
113
|
-
puts ">>> Ox is %0.1f faster than Marshal loading.\n\n" % [$mars_load_time/$ox_load_time]
|
114
|
-
end
|
115
|
-
|
116
|
-
def perf_dump(d)
|
117
|
-
obj = d[:obj]
|
118
|
-
|
119
|
-
start = Time.now
|
120
|
-
(1..$iter).each do
|
121
|
-
xml = Ox.dump(obj, :indent => $indent, :circular => $circular)
|
122
|
-
#puts "*** ox:\n#{xml}"
|
123
|
-
end
|
124
|
-
$ox_dump_time = Time.now - start
|
125
|
-
puts "Ox dumping #{$iter} times with ox took #{$ox_dump_time} seconds."
|
126
|
-
|
127
|
-
Oj.default_options = {:indent => $indent}
|
128
|
-
start = Time.now
|
129
|
-
(1..$iter).each do
|
130
|
-
json = Oj.dump(obj)
|
131
|
-
end
|
132
|
-
$oj_dump_time = Time.now - start
|
133
|
-
puts "Oj dumping #{$iter} times with oj took #{$oj_dump_time} seconds."
|
134
|
-
|
135
|
-
obj = d[:obj]
|
136
|
-
start = Time.now
|
137
|
-
(1..$iter).each do
|
138
|
-
m = Marshal.dump(obj)
|
139
|
-
end
|
140
|
-
$mars_dump_time = Time.now - start
|
141
|
-
puts "Marshal dumping #{$iter} times took #{$mars_dump_time} seconds."
|
142
|
-
puts ">>> Ox is %0.1f faster than Marshal dumping.\n\n" % [$mars_dump_time/$ox_dump_time]
|
143
|
-
end
|
144
|
-
|
145
|
-
def perf_read(d)
|
146
|
-
ox_read_time = 0
|
147
|
-
mars_read_time = 0
|
148
|
-
|
149
|
-
filename = d[:file]
|
150
|
-
marshal_filename = 'sample.marshal'
|
151
|
-
xml = d[:xml]
|
152
|
-
mars = d[:marshal]
|
153
|
-
|
154
|
-
# now load from the file
|
155
|
-
start = Time.now
|
156
|
-
(1..$iter).each do
|
157
|
-
obj = Ox.load_file(filename, :mode => :object)
|
158
|
-
end
|
159
|
-
ox_read_time = Time.now - start
|
160
|
-
puts "Loading and parsing #{$iter} times with ox took #{ox_read_time} seconds."
|
161
|
-
|
162
|
-
start = Time.now
|
163
|
-
(1..$iter).each do
|
164
|
-
m = File.read(marshal_filename)
|
165
|
-
obj = Marshal.load(m)
|
166
|
-
end
|
167
|
-
mars_read_time = Time.now - start
|
168
|
-
puts "Reading and marshalling #{$iter} times took #{mars_read_time} seconds."
|
169
|
-
puts ">>> Ox is %0.1f faster than Marshal loading and parsing.\n\n" % [mars_read_time/ox_read_time]
|
170
|
-
|
171
|
-
end
|
172
|
-
|
173
|
-
def perf_write(d)
|
174
|
-
ox_write_time = 0
|
175
|
-
mars_write_time = 0
|
176
|
-
|
177
|
-
ox_filename = 'out.xml'
|
178
|
-
marshal_filename = 'out.marshal'
|
179
|
-
obj = d[:obj]
|
180
|
-
|
181
|
-
start = Time.now
|
182
|
-
(1..$iter).each do
|
183
|
-
xml = Ox.to_file(ox_filename, obj, :indent => $indent)
|
184
|
-
end
|
185
|
-
ox_write_time = Time.now - start
|
186
|
-
puts "Ox dumping #{$iter} times with ox took #{ox_write_time} seconds."
|
187
|
-
|
188
|
-
start = Time.now
|
189
|
-
(1..$iter).each do
|
190
|
-
m = Marshal.dump(obj, circular: $circular)
|
191
|
-
File.open(marshal_filename, "w") { |f| f.write(m) }
|
192
|
-
end
|
193
|
-
mars_write_time = Time.now - start
|
194
|
-
puts "Marshal dumping and writing #{$iter} times took #{mars_write_time} seconds."
|
195
|
-
puts ">>> Ox is %0.1f faster than Marshal dumping.\n\n" % [mars_write_time/ox_write_time]
|
196
|
-
|
197
|
-
end
|
198
|
-
|
199
|
-
#if do_sample or do_files
|
200
|
-
data.each do |d|
|
201
|
-
puts "Using file #{d[:file]}."
|
202
|
-
|
203
|
-
perf_load(d) if do_load
|
204
|
-
perf_dump(d) if do_dump
|
205
|
-
if do_load and do_dump
|
206
|
-
puts ">>> Ox is %0.1f faster than Marshal dumping and loading.\n\n" % [($mars_load_time + $mars_dump_time)/($ox_load_time + $ox_dump_time)] unless 0 == $mars_load_time
|
207
|
-
end
|
208
|
-
|
209
|
-
perf_read(d) if do_read
|
210
|
-
perf_write(d) if do_write
|
211
|
-
|
212
|
-
end
|
213
|
-
#end
|