oj 1.3.0 → 1.3.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of oj might be problematic. Click here for more details.
- data/README.md +2 -2
- data/ext/oj/dump.c +38 -10
- data/ext/oj/extconf.rb +1 -1
- data/ext/oj/load.c +2 -0
- data/ext/oj/oj.c +5 -2
- data/ext/oj/oj.h +6 -3
- data/lib/oj/version.rb +1 -1
- data/test/perf1.rb +64 -0
- data/test/{foo.rb → perf2.rb} +30 -12
- data/test/perf_obj_old.rb +213 -0
- data/test/tests.rb +37 -3
- metadata +5 -7
- data/test/boo.rb +0 -26
- data/test/bug.rb +0 -18
- data/test/oj-test/test.rb +0 -137
- data/test/where.rb +0 -54
data/README.md
CHANGED
@@ -32,9 +32,9 @@ A fast JSON parser and Object marshaller as a Ruby gem.
|
|
32
32
|
|
33
33
|
## <a name="release">Release Notes</a>
|
34
34
|
|
35
|
-
### Release 1.3.
|
35
|
+
### Release 1.3.2
|
36
36
|
|
37
|
-
-
|
37
|
+
- Fixed compile problems with native Ruby on OS X 10.8 (Mountain Lion)
|
38
38
|
|
39
39
|
## <a name="description">Description</a>
|
40
40
|
|
data/ext/oj/dump.c
CHANGED
@@ -34,6 +34,7 @@
|
|
34
34
|
#include <time.h>
|
35
35
|
#include <stdio.h>
|
36
36
|
#include <string.h>
|
37
|
+
#include <math.h>
|
37
38
|
|
38
39
|
#include "oj.h"
|
39
40
|
#include "cache8.h"
|
@@ -42,8 +43,6 @@
|
|
42
43
|
#define rb_eEncodingError rb_eException
|
43
44
|
#endif
|
44
45
|
|
45
|
-
#define DBL_INF 1.e500
|
46
|
-
|
47
46
|
typedef unsigned long ulong;
|
48
47
|
|
49
48
|
typedef struct _Out {
|
@@ -421,10 +420,10 @@ dump_float(VALUE obj, Out out) {
|
|
421
420
|
*b++ = '0';
|
422
421
|
*b++ = '\0';
|
423
422
|
cnt = 3;
|
424
|
-
} else if (
|
423
|
+
} else if (INFINITY == d) {
|
425
424
|
strcpy(buf, "Infinity");
|
426
425
|
cnt = 8;
|
427
|
-
} else if (-
|
426
|
+
} else if (-INFINITY == d) {
|
428
427
|
strcpy(buf, "-Infinity");
|
429
428
|
cnt = 9;
|
430
429
|
} else {
|
@@ -970,6 +969,7 @@ dump_xml_time(VALUE obj, Out out) {
|
|
970
969
|
long nsec = NUM2LONG(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
|
971
970
|
#endif
|
972
971
|
#endif
|
972
|
+
long tz_secs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
|
973
973
|
int tzhour, tzmin;
|
974
974
|
char tzsign = '+';
|
975
975
|
|
@@ -977,7 +977,19 @@ dump_xml_time(VALUE obj, Out out) {
|
|
977
977
|
grow(out, 36);
|
978
978
|
}
|
979
979
|
// 2012-01-05T23:58:07.123456000+09:00
|
980
|
-
tm = localtime(&sec);
|
980
|
+
//tm = localtime(&sec);
|
981
|
+
sec += tz_secs;
|
982
|
+
tm = gmtime(&sec);
|
983
|
+
#if 1
|
984
|
+
if (0 > tz_secs) {
|
985
|
+
tzsign = '-';
|
986
|
+
tzhour = (int)(tz_secs / -3600);
|
987
|
+
tzmin = (int)(tz_secs / -60) - (tzhour * 60);
|
988
|
+
} else {
|
989
|
+
tzhour = (int)(tz_secs / 3600);
|
990
|
+
tzmin = (int)(tz_secs / 60) - (tzhour * 60);
|
991
|
+
}
|
992
|
+
#else
|
981
993
|
if (0 > tm->tm_gmtoff) {
|
982
994
|
tzsign = '-';
|
983
995
|
tzhour = (int)(tm->tm_gmtoff / -3600);
|
@@ -986,11 +998,27 @@ dump_xml_time(VALUE obj, Out out) {
|
|
986
998
|
tzhour = (int)(tm->tm_gmtoff / 3600);
|
987
999
|
tzmin = (int)(tm->tm_gmtoff / 60) - (tzhour * 60);
|
988
1000
|
}
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
1001
|
+
#endif
|
1002
|
+
if (0 == nsec) {
|
1003
|
+
if (0 == tzhour && 0 == tzmin) {
|
1004
|
+
sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ",
|
1005
|
+
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
1006
|
+
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
1007
|
+
dump_cstr(buf, 20, 0, 0, out);
|
1008
|
+
} else {
|
1009
|
+
sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
|
1010
|
+
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
1011
|
+
tm->tm_hour, tm->tm_min, tm->tm_sec,
|
1012
|
+
tzsign, tzhour, tzmin);
|
1013
|
+
dump_cstr(buf, 25, 0, 0, out);
|
1014
|
+
}
|
1015
|
+
} else {
|
1016
|
+
sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d",
|
1017
|
+
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
1018
|
+
tm->tm_hour, tm->tm_min, tm->tm_sec, nsec,
|
1019
|
+
tzsign, tzhour, tzmin);
|
1020
|
+
dump_cstr(buf, 35, 0, 0, out);
|
1021
|
+
}
|
994
1022
|
}
|
995
1023
|
|
996
1024
|
static void
|
data/ext/oj/extconf.rb
CHANGED
@@ -32,7 +32,7 @@ dflags = {
|
|
32
32
|
# missing #define. This is the quick and easy way around it.
|
33
33
|
if 'x86_64-linux' == RUBY_PLATFORM && '1.9.3' == RUBY_VERSION && '2011-10-30' == RUBY_RELEASE_DATE
|
34
34
|
begin
|
35
|
-
dflags['NEEDS_STPCPY'] = nil if
|
35
|
+
dflags['NEEDS_STPCPY'] = nil if File.read('/etc/redhat-release').include?('CentOS release 5.4')
|
36
36
|
rescue Exception => e
|
37
37
|
end
|
38
38
|
end
|
data/ext/oj/load.c
CHANGED
data/ext/oj/oj.c
CHANGED
@@ -29,7 +29,6 @@
|
|
29
29
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
30
|
*/
|
31
31
|
|
32
|
-
#include <pthread.h>
|
33
32
|
#include <stdlib.h>
|
34
33
|
#include <errno.h>
|
35
34
|
#include <stdio.h>
|
@@ -64,6 +63,7 @@ ID oj_to_time_id;
|
|
64
63
|
ID oj_tv_nsec_id;
|
65
64
|
ID oj_tv_sec_id;
|
66
65
|
ID oj_tv_usec_id;
|
66
|
+
ID oj_utc_offset_id;
|
67
67
|
ID oj_write_id;
|
68
68
|
|
69
69
|
VALUE oj_bag_class;
|
@@ -107,8 +107,9 @@ Cache oj_attr_cache = 0;
|
|
107
107
|
rb_encoding *oj_utf8_encoding = 0;
|
108
108
|
#endif
|
109
109
|
|
110
|
+
#ifdef SAFE_CACHE
|
110
111
|
pthread_mutex_t oj_cache_mutex; // only used if SAFE_CACHE defined
|
111
|
-
|
112
|
+
#endif
|
112
113
|
static const char json_class[] = "json_class";
|
113
114
|
|
114
115
|
struct _Options oj_default_options = {
|
@@ -628,6 +629,7 @@ mimic_dump_load(int argc, VALUE *argv, VALUE self) {
|
|
628
629
|
} else {
|
629
630
|
return mimic_dump(argc, argv, self);
|
630
631
|
}
|
632
|
+
return Qnil;
|
631
633
|
}
|
632
634
|
|
633
635
|
static VALUE
|
@@ -872,6 +874,7 @@ void Init_oj() {
|
|
872
874
|
oj_tv_nsec_id = rb_intern("tv_nsec");
|
873
875
|
oj_tv_sec_id = rb_intern("tv_sec");
|
874
876
|
oj_tv_usec_id = rb_intern("tv_usec");
|
877
|
+
oj_utc_offset_id = rb_intern("utc_offset");
|
875
878
|
oj_write_id = rb_intern("write");
|
876
879
|
|
877
880
|
oj_bag_class = rb_const_get_at(Oj, rb_intern("Bag"));
|
data/ext/oj/oj.h
CHANGED
@@ -46,8 +46,9 @@ extern "C" {
|
|
46
46
|
#endif
|
47
47
|
|
48
48
|
#include "stdint.h"
|
49
|
-
#
|
50
|
-
|
49
|
+
#ifdef SAFE_CACHE
|
50
|
+
#include <pthread.h>
|
51
|
+
#endif
|
51
52
|
#include "cache.h"
|
52
53
|
|
53
54
|
#ifdef RUBINIUS_RUBY
|
@@ -182,12 +183,14 @@ extern ID oj_to_time_id;
|
|
182
183
|
extern ID oj_tv_nsec_id;
|
183
184
|
extern ID oj_tv_sec_id;
|
184
185
|
extern ID oj_tv_usec_id;
|
186
|
+
extern ID oj_utc_offset_id;
|
185
187
|
|
186
188
|
extern Cache oj_class_cache;
|
187
189
|
extern Cache oj_attr_cache;
|
188
190
|
|
191
|
+
#ifdef SAFE_CACHE
|
189
192
|
extern pthread_mutex_t oj_cache_mutex;
|
190
|
-
|
193
|
+
#endif
|
191
194
|
#if defined(__cplusplus)
|
192
195
|
#if 0
|
193
196
|
{ /* satisfy cc-mode */
|
data/lib/oj/version.rb
CHANGED
data/test/perf1.rb
ADDED
@@ -0,0 +1,64 @@
|
|
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/{foo.rb → perf2.rb}
RENAMED
@@ -15,6 +15,19 @@ 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
|
+
|
18
31
|
iter = 100000
|
19
32
|
s = %{
|
20
33
|
{ "class": "Foo::Bar",
|
@@ -23,36 +36,41 @@ s = %{
|
|
23
36
|
}
|
24
37
|
}
|
25
38
|
|
39
|
+
obj = Oj.load(s)
|
40
|
+
obj["foo"] = Foo.new()
|
41
|
+
|
42
|
+
Oj.default_options = { :indent => 0, :effort => :internal }
|
43
|
+
|
44
|
+
puts
|
45
|
+
|
26
46
|
start = Time.now
|
27
47
|
iter.times do
|
28
48
|
Oj.load(s)
|
29
49
|
end
|
30
|
-
|
31
|
-
puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/msec" % [iter,
|
50
|
+
dt = Time.now - start
|
51
|
+
puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/msec" % [iter, dt, iter/dt/1000.0]
|
32
52
|
|
33
53
|
start = Time.now
|
34
54
|
iter.times do
|
35
55
|
Yajl::Parser.parse(s)
|
36
56
|
end
|
37
|
-
|
38
|
-
puts "%d Yajl::Parser.parse()s in %0.3f seconds or %0.1f parses/msec" % [iter,
|
57
|
+
dt = Time.now - start
|
58
|
+
puts "%d Yajl::Parser.parse()s in %0.3f seconds or %0.1f parses/msec" % [iter, dt, iter/dt/1000.0]
|
39
59
|
|
40
|
-
puts
|
60
|
+
puts
|
41
61
|
|
42
|
-
|
43
|
-
obj = Oj.load(s)
|
44
62
|
start = Time.now
|
45
63
|
iter.times do
|
46
64
|
Oj.dump(obj)
|
47
65
|
end
|
48
|
-
|
49
|
-
puts "%d Oj.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter,
|
66
|
+
dt = Time.now - start
|
67
|
+
puts "%d Oj.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter, dt, iter/dt/1000.0]
|
50
68
|
|
51
69
|
start = Time.now
|
52
70
|
iter.times do
|
53
71
|
Yajl::Encoder.encode(obj)
|
54
72
|
end
|
55
|
-
|
56
|
-
puts "%d Yajl::Encoder.encode()s in %0.3f seconds or %0.1f encodes/msec" % [iter,
|
73
|
+
dt = Time.now - start
|
74
|
+
puts "%d Yajl::Encoder.encode()s in %0.3f seconds or %0.1f encodes/msec" % [iter, dt, iter/dt/1000.0]
|
57
75
|
|
58
|
-
puts
|
76
|
+
puts
|
@@ -0,0 +1,213 @@
|
|
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
|
data/test/tests.rb
CHANGED
@@ -266,9 +266,43 @@ class Juice < ::Test::Unit::TestCase
|
|
266
266
|
assert_equal(%{"#{t.to_s}"}, json)
|
267
267
|
end
|
268
268
|
def test_xml_time_compat
|
269
|
-
|
270
|
-
|
271
|
-
|
269
|
+
begin
|
270
|
+
t = Time.new(2012, 1, 5, 23, 58, 7.123456000, 34200)
|
271
|
+
json = Oj.dump(t, :mode => :compat, :time_format => :xmlschema)
|
272
|
+
assert_equal(%{"2012-01-05T23:58:07.123456000+09:30"}, json)
|
273
|
+
rescue Exception => e
|
274
|
+
# some Rubies (1.8.7) do not allow the timezome to be set
|
275
|
+
t = Time.local(2012, 1, 5, 23, 58, 7, 123456)
|
276
|
+
json = Oj.dump(t, :mode => :compat, :time_format => :xmlschema)
|
277
|
+
tz = t.utc_offset
|
278
|
+
assert_equal(%{"2012-01-05T23:58:07.123456000+%02d:%02d"} % [tz / 3600, tz / 60 % 60], json)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
def test_xml_time_compat_no_secs
|
282
|
+
begin
|
283
|
+
t = Time.new(2012, 1, 5, 23, 58, 7.0, 34200)
|
284
|
+
json = Oj.dump(t, :mode => :compat, :time_format => :xmlschema)
|
285
|
+
assert_equal(%{"2012-01-05T23:58:07+09:30"}, json)
|
286
|
+
rescue Exception => e
|
287
|
+
# some Rubies (1.8.7) do not allow the timezome to be set
|
288
|
+
t = Time.local(2012, 1, 5, 23, 58, 7, 0)
|
289
|
+
json = Oj.dump(t, :mode => :compat, :time_format => :xmlschema)
|
290
|
+
tz = t.utc_offset
|
291
|
+
assert_equal(%{"2012-01-05T23:58:07+%02d:%02d"} % [tz / 3600, tz / 60 % 60], json)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
def test_xml_time_compat_zulu
|
295
|
+
begin
|
296
|
+
t = Time.new(2012, 1, 5, 23, 58, 7.0, 0)
|
297
|
+
json = Oj.dump(t, :mode => :compat, :time_format => :xmlschema)
|
298
|
+
assert_equal(%{"2012-01-05T23:58:07Z"}, json)
|
299
|
+
rescue Exception => e
|
300
|
+
# some Rubies (1.8.7) do not allow the timezome to be set
|
301
|
+
t = Time.utc(2012, 1, 5, 23, 58, 7, 0)
|
302
|
+
json = Oj.dump(t, :mode => :compat, :time_format => :xmlschema)
|
303
|
+
tz = t.utc_offset
|
304
|
+
assert_equal(%{"2012-01-05T23:58:07Z"}, json)
|
305
|
+
end
|
272
306
|
end
|
273
307
|
def test_time_object
|
274
308
|
t = Time.now()
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oj
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07-
|
12
|
+
date: 2012-07-28 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! 'The fastest JSON parser and object serializer. '
|
15
15
|
email: peter@ohler.com
|
@@ -32,14 +32,13 @@ files:
|
|
32
32
|
- ext/oj/fast.c
|
33
33
|
- ext/oj/load.c
|
34
34
|
- ext/oj/oj.c
|
35
|
-
- test/boo.rb
|
36
|
-
- test/bug.rb
|
37
35
|
- test/files.rb
|
38
|
-
- test/foo.rb
|
39
|
-
- test/oj-test/test.rb
|
40
36
|
- test/perf.rb
|
37
|
+
- test/perf1.rb
|
38
|
+
- test/perf2.rb
|
41
39
|
- test/perf_fast.rb
|
42
40
|
- test/perf_obj.rb
|
41
|
+
- test/perf_obj_old.rb
|
43
42
|
- test/perf_simple.rb
|
44
43
|
- test/perf_strict.rb
|
45
44
|
- test/sample/change.rb
|
@@ -59,7 +58,6 @@ files:
|
|
59
58
|
- test/test_fast.rb
|
60
59
|
- test/test_mimic.rb
|
61
60
|
- test/tests.rb
|
62
|
-
- test/where.rb
|
63
61
|
- LICENSE
|
64
62
|
- README.md
|
65
63
|
homepage: http://www.ohler.com/oj
|
data/test/boo.rb
DELETED
@@ -1,26 +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 '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
DELETED
@@ -1,18 +0,0 @@
|
|
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/oj-test/test.rb
DELETED
@@ -1,137 +0,0 @@
|
|
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
|
-
class BidResponseParser
|
85
|
-
REQUIRED_ATTRIBUTES = [:id, :impid, :price].freeze
|
86
|
-
|
87
|
-
def self.parse(json)
|
88
|
-
return nil if !json
|
89
|
-
extract_fast(json)
|
90
|
-
end
|
91
|
-
|
92
|
-
def self.extract_fast(json)
|
93
|
-
bid = nil
|
94
|
-
Oj::Doc.open(json) do |doc|
|
95
|
-
bid = Bid.new
|
96
|
-
|
97
|
-
# bid-response object
|
98
|
-
bid.id = doc.fetch '/id'
|
99
|
-
|
100
|
-
bid.bidid = doc.fetch '/bidid'
|
101
|
-
bid.units = doc.fetch('/units') || 0
|
102
|
-
bid.cur = doc.fetch '/cur'
|
103
|
-
bid.nbr = doc.fetch('/nbr') || 0 # Mobile RTB 1.0 only
|
104
|
-
|
105
|
-
# EM: we do not expect more than 1 bid object in the response,
|
106
|
-
# as we only send single ads in the bid-request (no multi-ad-auctions) atm.
|
107
|
-
# seatbid-obj
|
108
|
-
bid.seat = doc.fetch '/seatbid/0/seat'
|
109
|
-
bid.group = doc.fetch '/seatbid/0/group'
|
110
|
-
|
111
|
-
# bid-obj
|
112
|
-
bid_path = '/seatbid/0/bid/0'
|
113
|
-
bid.impid = doc.fetch "#{bid_path}/impid"
|
114
|
-
bid.adid = doc.fetch "#{bid_path}/adid"
|
115
|
-
bid.nurl = doc.fetch "#{bid_path}/nurl"
|
116
|
-
bid.adm = doc.fetch "#{bid_path}/adm"
|
117
|
-
bid.adomain = doc.fetch "#{bid_path}/adomain"
|
118
|
-
bid.iurl = doc.fetch "#{bid_path}/iurl"
|
119
|
-
bid.cid = doc.fetch "#{bid_path}/cid"
|
120
|
-
bid.crid = doc.fetch "#{bid_path}/crid"
|
121
|
-
bid.attr = doc.fetch "#{bid_path}/attr"
|
122
|
-
|
123
|
-
# sadly we need to check this explicitly, because nil.to_f returns 0.0
|
124
|
-
if doc.fetch("#{bid_path}/price") == nil
|
125
|
-
raise "required attribute price missing"
|
126
|
-
end
|
127
|
-
|
128
|
-
bid.price = doc.fetch("#{bid_path}/price").to_f
|
129
|
-
end
|
130
|
-
|
131
|
-
return bid
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
1000.times do
|
136
|
-
BidResponseParser.parse(LARGE_JSON)
|
137
|
-
end
|
data/test/where.rb
DELETED
@@ -1,54 +0,0 @@
|
|
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
|