oj 0.5.2 → 0.6.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.

@@ -106,7 +106,7 @@ next_white(ParseInfo pi) {
106
106
  }
107
107
 
108
108
  VALUE
109
- parse(char *json, Options options) {
109
+ oj_parse(char *json, Options options) {
110
110
  VALUE obj;
111
111
  struct _ParseInfo pi;
112
112
 
@@ -116,7 +116,11 @@ parse(char *json, Options options) {
116
116
  /* initialize parse info */
117
117
  pi.str = json;
118
118
  pi.s = json;
119
+ #ifdef HAVE_RUBY_ENCODING_H
119
120
  pi.encoding = ('\0' == *options->encoding) ? 0 : rb_enc_find(options->encoding);
121
+ #else
122
+ pi.encoding = 0;
123
+ #endif
120
124
  pi.options = options;
121
125
  if (Qundef == (obj = read_next(&pi))) {
122
126
  raise_error("no object read", pi.str, pi.s);
@@ -261,14 +265,22 @@ read_str(ParseInfo pi) {
261
265
  return s;
262
266
  }
263
267
 
268
+ #ifdef RUBINIUS
269
+ #define NUM_MAX 0x07FFFFFF
270
+ #else
271
+ #define NUM_MAX (FIXNUM_MAX >> 8)
272
+ #endif
273
+
264
274
  static VALUE
265
275
  read_num(ParseInfo pi) {
276
+ char *start = pi->s;
266
277
  int64_t n = 0;
267
278
  long a = 0;
268
279
  long div = 1;
269
280
  long e = 0;
270
281
  int neg = 0;
271
282
  int eneg = 0;
283
+ int big = 0;
272
284
 
273
285
  if ('-' == *pi->s) {
274
286
  pi->s++;
@@ -278,6 +290,19 @@ read_num(ParseInfo pi) {
278
290
  }
279
291
  for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
280
292
  n = n * 10 + (*pi->s - '0');
293
+ if (NUM_MAX <= n) {
294
+ big = 1;
295
+ }
296
+ }
297
+ if (big) {
298
+ char c = *pi->s;
299
+ VALUE num;
300
+
301
+ *pi->s = '\0';
302
+ num = rb_cstr_to_inum(start, 10, 0);
303
+ *pi->s = c;
304
+
305
+ return num;
281
306
  }
282
307
  if ('.' == *pi->s) {
283
308
  pi->s++;
@@ -45,23 +45,26 @@ void Init_oj();
45
45
 
46
46
  VALUE Oj = Qnil;
47
47
 
48
- VALUE circular_sym;
49
- VALUE effort_sym;
50
- VALUE encoding_sym;
51
- VALUE indent_sym;
52
- VALUE lazy_sym;
53
- VALUE mode_sym;
54
- VALUE object_sym;
55
- VALUE simple_sym;
56
- VALUE strict_sym;
57
- VALUE tolerant_sym;
48
+ ID oj_instance_variables_id;
49
+ ID oj_to_hash_id;
50
+ ID oj_to_json_id;
51
+ ID oj_tv_sec_id;
52
+ ID oj_tv_usec_id;
53
+
54
+ static VALUE circular_sym;
55
+ static VALUE compat_sym;
56
+ static VALUE encoding_sym;
57
+ static VALUE indent_sym;
58
+ static VALUE mode_sym;
59
+ static VALUE null_sym;
60
+ static VALUE object_sym;
61
+ static VALUE strict_sym;
58
62
 
59
63
  static struct _Options default_options = {
60
64
  { '\0' }, // encoding
61
65
  0, // indent
62
66
  No, // circular
63
- NoMode, // mode
64
- TolerantEffort, // effort
67
+ ObjectMode, // mode
65
68
  };
66
69
 
67
70
  /* call-seq: default_options() => Hash
@@ -70,8 +73,7 @@ static struct _Options default_options = {
70
73
  * - indent: [Fixnum] number of spaces to indent each element in an XML document
71
74
  * - encoding: [String] character encoding for the JSON file
72
75
  * - circular: [true|false|nil] support circular references while dumping
73
- * - mode: [:object|:simple|nil] load method to use for JSON
74
- * - effort: [:strict|:tolerant|:lazy_define] set the tolerance level for loading
76
+ * - mode: [:object|:strict|:compat|:null] load and dump modes to use for JSON
75
77
  * @return [Hash] all current option settings.
76
78
  */
77
79
  static VALUE
@@ -83,17 +85,11 @@ get_def_opts(VALUE self) {
83
85
  rb_hash_aset(opts, indent_sym, INT2FIX(default_options.indent));
84
86
  rb_hash_aset(opts, circular_sym, (Yes == default_options.circular) ? Qtrue : ((No == default_options.circular) ? Qfalse : Qnil));
85
87
  switch (default_options.mode) {
86
- case ObjectMode: rb_hash_aset(opts, mode_sym, object_sym); break;
87
- case SimpleMode: rb_hash_aset(opts, mode_sym, simple_sym); break;
88
- case NoMode:
89
- default: rb_hash_aset(opts, mode_sym, Qnil); break;
90
- }
91
- switch (default_options.effort) {
92
- case StrictEffort: rb_hash_aset(opts, effort_sym, strict_sym); break;
93
- case TolerantEffort: rb_hash_aset(opts, effort_sym, tolerant_sym); break;
94
- case LazyEffort: rb_hash_aset(opts, effort_sym, lazy_sym); break;
95
- case NoEffort:
96
- default: rb_hash_aset(opts, effort_sym, Qnil); break;
88
+ case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break;
89
+ case CompatMode: rb_hash_aset(opts, mode_sym, compat_sym); break;
90
+ case NullMode: rb_hash_aset(opts, mode_sym, null_sym); break;
91
+ case ObjectMode:
92
+ default: rb_hash_aset(opts, mode_sym, object_sym); break;
97
93
  }
98
94
  return opts;
99
95
  }
@@ -105,14 +101,14 @@ get_def_opts(VALUE self) {
105
101
  * @param [Fixnum] :indent number of spaces to indent each element in an XML document
106
102
  * @param [String] :encoding character encoding for the JSON file
107
103
  * @param [true|false|nil] :circular support circular references while dumping
108
- * @param [:object|:simple|nil] :mode load and dump methods to use for JSON
109
- * @param [:strict|:tolerant|:lazy] :effort set the tolerance level for
110
- * loading. :strict raises an exception when a non-supported Object is
111
- * encountered. :tolerant attempts to extract variable values from an
112
- * Object using to_json() then it walks the Object's variables. The
113
- * :lazy mode ignores non-supported Objects and replaces them with a
114
- * null.
115
- * @return [nil]
104
+ * @parsm [:object|:strict|:compat|:null] load and dump mode to use for JSON
105
+ * :strict raises an exception when a non-supported Object is
106
+ * encountered. :compat attempts to extract variable values from an
107
+ * Object using to_json() or to_hash() then it walks the Object's
108
+ * variables if neither is found. The :object mode ignores to_hash()
109
+ * and to_json() methods and encodes variables using code internal to
110
+ * the Oj gem. The :null mode ignores non-supported Objects and
111
+ * replaces them with a null. @return [nil]
116
112
  */
117
113
  static VALUE
118
114
  set_def_opts(VALUE self, VALUE opts) {
@@ -142,32 +138,20 @@ set_def_opts(VALUE self, VALUE opts) {
142
138
  }
143
139
 
144
140
  v = rb_hash_lookup2(opts, mode_sym, Qundef);
145
- if (Qundef == v) {
146
- // no change
147
- } else if (Qnil == v) {
148
- default_options.mode = NoMode;
141
+ if (Qundef == v || Qnil == v) {
142
+ // ignore
149
143
  } else if (object_sym == v) {
150
144
  default_options.mode = ObjectMode;
151
- } else if (simple_sym == v) {
152
- default_options.mode = SimpleMode;
153
- } else {
154
- rb_raise(rb_eArgError, ":mode must be :object, :simple, or nil.\n");
155
- }
156
-
157
- v = rb_hash_lookup2(opts, effort_sym, Qundef);
158
- if (Qundef == v) {
159
- // no change
160
- } else if (Qnil == v) {
161
- default_options.effort = NoEffort;
162
145
  } else if (strict_sym == v) {
163
- default_options.effort = StrictEffort;
164
- } else if (tolerant_sym == v) {
165
- default_options.effort = TolerantEffort;
166
- } else if (lazy_sym == v) {
167
- default_options.effort = LazyEffort;
146
+ default_options.mode = StrictMode;
147
+ } else if (compat_sym == v) {
148
+ default_options.mode = CompatMode;
149
+ } else if (null_sym == v) {
150
+ default_options.mode = NullMode;
168
151
  } else {
169
- rb_raise(rb_eArgError, ":effort must be :strict, :tolerant, :lazy, or nil.\n");
152
+ rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.\n");
170
153
  }
154
+
171
155
  for (o = ynos; 0 != o->attr; o++) {
172
156
  v = rb_hash_lookup2(opts, o->sym, Qundef);
173
157
  if (Qundef == v) {
@@ -211,21 +195,14 @@ parse_options(VALUE ropts, Options copts) {
211
195
  if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) {
212
196
  if (object_sym == v) {
213
197
  copts->mode = ObjectMode;
214
- } else if (simple_sym == v) {
215
- copts->mode = SimpleMode;
216
- } else {
217
- rb_raise(rb_eArgError, ":mode must be :object or :simple.\n");
218
- }
219
- }
220
- if (Qnil != (v = rb_hash_lookup(ropts, effort_sym))) {
221
- if (lazy_sym == v) {
222
- copts->effort = LazyEffort;
223
- } else if (tolerant_sym == v) {
224
- copts->effort = TolerantEffort;
225
198
  } else if (strict_sym == v) {
226
- copts->effort = StrictEffort;
199
+ copts->mode = StrictMode;
200
+ } else if (compat_sym == v) {
201
+ copts->mode = CompatMode;
202
+ } else if (null_sym == v) {
203
+ copts->mode = NullMode;
227
204
  } else {
228
- rb_raise(rb_eArgError, ":effort must be :strict, :tolerant, or :lazy.\n");
205
+ rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.\n");
229
206
  }
230
207
  }
231
208
  for (o = ynos; 0 != o->attr; o++) {
@@ -252,7 +229,7 @@ load(char *json, int argc, VALUE *argv, VALUE self) {
252
229
  if (1 == argc) {
253
230
  parse_options(*argv, &options);
254
231
  }
255
- obj = parse(json, &options);
232
+ obj = oj_parse(json, &options);
256
233
  free(json);
257
234
 
258
235
  return obj;
@@ -321,7 +298,7 @@ dump(int argc, VALUE *argv, VALUE self) {
321
298
  if (2 == argc) {
322
299
  parse_options(argv[1], &copts);
323
300
  }
324
- if (0 == (json = write_obj_to_str(*argv, &copts))) {
301
+ if (0 == (json = oj_write_obj_to_str(*argv, &copts))) {
325
302
  rb_raise(rb_eNoMemError, "Not enough memory.\n");
326
303
  }
327
304
  rstr = rb_str_new2(json);
@@ -348,21 +325,26 @@ void Init_oj() {
348
325
  rb_define_module_function(Oj, "load_file", load_file, -1);
349
326
  rb_define_module_function(Oj, "dump", dump, -1);
350
327
 
328
+ oj_instance_variables_id = rb_intern("instance_variables");
329
+ oj_to_hash_id = rb_intern("to_hash");
330
+ oj_to_json_id = rb_intern("to_json");
331
+ oj_tv_sec_id = rb_intern("tv_sec");
332
+ oj_tv_usec_id = rb_intern("tv_usec");
333
+
351
334
  circular_sym = ID2SYM(rb_intern("circular")); rb_ary_push(keep, circular_sym);
352
- effort_sym = ID2SYM(rb_intern("effort")); rb_ary_push(keep, effort_sym);
335
+ compat_sym = ID2SYM(rb_intern("compat")); rb_ary_push(keep, compat_sym);
353
336
  encoding_sym = ID2SYM(rb_intern("encoding")); rb_ary_push(keep, encoding_sym);
354
337
  indent_sym = ID2SYM(rb_intern("indent")); rb_ary_push(keep, indent_sym);
355
- lazy_sym = ID2SYM(rb_intern("lazy")); rb_ary_push(keep, lazy_sym);
356
338
  mode_sym = ID2SYM(rb_intern("mode")); rb_ary_push(keep, mode_sym);
339
+ null_sym = ID2SYM(rb_intern("null")); rb_ary_push(keep, null_sym);
357
340
  object_sym = ID2SYM(rb_intern("object")); rb_ary_push(keep, object_sym);
358
- simple_sym = ID2SYM(rb_intern("simple")); rb_ary_push(keep, simple_sym);
359
341
  strict_sym = ID2SYM(rb_intern("strict")); rb_ary_push(keep, strict_sym);
360
- tolerant_sym = ID2SYM(rb_intern("tolerant")); rb_ary_push(keep, tolerant_sym);
361
- default_options.effort = TolerantEffort;
342
+
343
+ default_options.mode = ObjectMode;
362
344
  }
363
345
 
364
346
  void
365
- _raise_error(const char *msg, const char *xml, const char *current, const char* file, int line) {
347
+ _oj_raise_error(const char *msg, const char *xml, const char *current, const char* file, int line) {
366
348
  int xline = 1;
367
349
  int col = 1;
368
350
 
@@ -41,6 +41,7 @@ extern "C" {
41
41
  #include "ruby.h"
42
42
  #ifdef HAVE_RUBY_ENCODING_H
43
43
  // HAVE_RUBY_ENCODING_H defined for Ruby 1.9
44
+ #define IVAR_HELPERS 1
44
45
  #include "ruby/encoding.h"
45
46
  #endif
46
47
 
@@ -56,9 +57,10 @@ extern "C" {
56
57
  #undef T_RATIONAL
57
58
  #undef T_COMPLEX
58
59
  #define NO_RSTRUCT 1
60
+ #define IVAR_HELPERS 0
59
61
  #endif
60
62
 
61
- #define raise_error(msg, xml, current) _raise_error(msg, xml, current, __FILE__, __LINE__)
63
+ #define raise_error(msg, xml, current) _oj_raise_error(msg, xml, current, __FILE__, __LINE__)
62
64
 
63
65
  typedef enum {
64
66
  Yes = 'y',
@@ -67,34 +69,33 @@ typedef enum {
67
69
  } YesNo;
68
70
 
69
71
  typedef enum {
72
+ StrictMode = 's',
70
73
  ObjectMode = 'o',
71
- SimpleMode = 's',
72
- NoMode = 0
74
+ NullMode = 'n',
75
+ CompatMode = 'c'
73
76
  } Mode;
74
77
 
75
- typedef enum {
76
- StrictEffort = 's',
77
- TolerantEffort = 't',
78
- LazyEffort = 'z',
79
- NoEffort = 0,
80
- } Effort;
81
-
82
78
  typedef struct _Options {
83
79
  char encoding[64]; // encoding, stored in the option to avoid GC invalidation in default values
84
80
  int indent; // indention for dump, default 2
85
81
  char circular; // YesNo
86
82
  char mode; // Mode
87
- char effort; // Effort
88
83
  } *Options;
89
84
 
90
- extern VALUE parse(char *json, Options options);
91
- extern char* write_obj_to_str(VALUE obj, Options copts);
92
-
93
- extern void _raise_error(const char *msg, const char *xml, const char *current, const char* file, int line);
85
+ extern VALUE oj_parse(char *json, Options options);
86
+ extern char* oj_write_obj_to_str(VALUE obj, Options copts);
87
+ extern void oj_write_obj_to_file(VALUE obj, const char *path, Options copts);
94
88
 
89
+ extern void _oj_raise_error(const char *msg, const char *xml, const char *current, const char* file, int line);
95
90
 
96
91
  extern VALUE Oj;
97
92
 
93
+ extern ID oj_instance_variables_id;
94
+ extern ID oj_to_hash_id;
95
+ extern ID oj_to_json_id;
96
+ extern ID oj_tv_sec_id;
97
+ extern ID oj_tv_usec_id;
98
+
98
99
  #if defined(__cplusplus)
99
100
  #if 0
100
101
  { /* satisfy cc-mode */
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '0.5.2'
4
+ VERSION = '0.6.0'
5
5
  end
@@ -4,62 +4,284 @@
4
4
  $: << File.join(File.dirname(__FILE__), "../lib")
5
5
  $: << File.join(File.dirname(__FILE__), "../ext")
6
6
 
7
- #require 'test/unit'
8
7
  require 'optparse'
9
8
  require 'yajl'
9
+ require 'json'
10
+ require 'json/pure'
11
+ require 'json/ext'
12
+ require 'msgpack'
10
13
  require 'oj'
14
+ require 'ox'
15
+
16
+ class Jazz
17
+ def initialize()
18
+ @boolean = true
19
+ @number = 58
20
+ @string = "A string"
21
+ @array = [true, false, nil]
22
+ @hash = { 'one' => 1, 'two' => 2 }
23
+ end
24
+ def to_json()
25
+ %{
26
+ { "boolean":#{@boolean},
27
+ "number":#{@number},
28
+ "string":#{@string},
29
+ "array":#{@array},
30
+ "hash":#{@hash},
31
+ }
32
+ }
33
+ end
34
+ def to_hash()
35
+ { 'boolean' => @boolean,
36
+ 'number' => @number,
37
+ 'string' => @string,
38
+ 'array' => @array,
39
+ 'hash' => @hash,
40
+ }
41
+ end
42
+ def to_msgpack(out)
43
+ out << MessagePack.pack(to_hash())
44
+ end
45
+ end
11
46
 
12
47
  $indent = 2
48
+ $iter = 10000
49
+ $with_object = true
50
+ $with_bignum = true
51
+ $with_nums = true
13
52
 
14
53
  opts = OptionParser.new
54
+ opts.on("-c", "--count [Int]", Integer, "iterations") { |i| $iter = i }
55
+ opts.on("-i", "--indent [Int]", Integer, "indentation") { |i| $indent = i }
56
+ opts.on("-o", "without objects") { $with_object = false }
57
+ opts.on("-b", "without bignum") { $with_bignum = false }
58
+ opts.on("-n", "without numbers") { $with_nums = false }
15
59
  opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
16
60
  files = opts.parse(ARGV)
17
61
 
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
- }
62
+ if $with_nums
63
+ obj = {
64
+ 'a' => 'Alpha',
65
+ 'b' => true,
66
+ 'c' => 12345,
67
+ 'd' => [ true, [false, [12345, nil], 3.967, ['something', false], nil]],
68
+ 'e' => { 'one' => 1, 'two' => 2 },
69
+ 'f' => nil,
70
+ }
71
+ obj['g'] = Jazz.new() if $with_object
72
+ obj['h'] = 12345678901234567890123456789 if $with_bignum
73
+ else
74
+ obj = {
75
+ 'a' => 'Alpha',
76
+ 'b' => true,
77
+ 'c' => '12345',
78
+ 'd' => [ true, [false, ['12345', nil], '3.967', ['something', false], nil]],
79
+ 'e' => { 'one' => '1', 'two' => '2' },
80
+ 'f' => nil,
81
+ }
82
+ end
83
+
84
+ Oj.default_options = { :indent => $indent, :mode => :object }
85
+
86
+ s = Oj.dump(obj)
25
87
 
26
- Oj.default_options = { :indent => 0 }
88
+ xml = Ox.dump(obj, :indent => $indent)
27
89
 
28
90
  puts
29
91
 
92
+ # Put Oj in strict mode so it only create JSON native types instead of the
93
+ # original Ruby Objects. None of the other packages other than Ox support
94
+ # Object recreation so no need for Oj to do it in the performance tests.
95
+ Oj.default_options = { :mode => :strict }
96
+ parse_results = { :oj => 0.0, :yajl => 0.0, :msgpack => 0.0, :pure => 0.0, :ext => 0.0, :ox => 0.0 }
97
+
30
98
  start = Time.now
31
- iter.times do
99
+ $iter.times do
32
100
  Oj.load(s)
33
101
  end
34
- oj_dt = Time.now - start
35
- puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/msec" % [iter, oj_dt, iter/oj_dt/1000.0]
102
+ dt = Time.now - start
103
+ base_dt = dt
104
+ parse_results[:oj] = dt
105
+ puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/msec" % [$iter, dt, $iter/dt/1000.0]
36
106
 
37
107
  start = Time.now
38
- iter.times do
108
+ $iter.times do
39
109
  Yajl::Parser.parse(s)
40
110
  end
41
- yajl_dt = Time.now - start
42
- puts "%d Yajl::Parser.parse()s in %0.3f seconds or %0.1f parses/msec" % [iter, yajl_dt, iter/yajl_dt/1000.0]
111
+ dt = Time.now - start
112
+ if base_dt < dt
113
+ base_dt = dt
114
+ base_name = 'Yajl'
115
+ end
116
+ parse_results[:yajl] = dt
117
+ puts "%d Yajl::Parser.parse()s in %0.3f seconds or %0.1f parses/msec" % [$iter, dt, $iter/dt/1000.0]
118
+
119
+ begin
120
+ JSON.parser = JSON::Ext::Parser
121
+ start = Time.now
122
+ $iter.times do
123
+ JSON.parse(s)
124
+ end
125
+ dt = Time.now - start
126
+ if base_dt < dt
127
+ base_dt = dt
128
+ base_name = 'JSON::Ext'
129
+ end
130
+ parse_results[:ext] = dt
131
+ puts "%d JSON::Ext::Parser parse()s in %0.3f seconds or %0.1f parses/msec" % [$iter, dt, $iter/dt/1000.0]
132
+ rescue Exception => e
133
+ puts "JSON::Ext failed: #{e.class}: #{e.message}"
134
+ end
135
+
136
+ begin
137
+ JSON.parser = JSON::Pure::Parser
138
+ start = Time.now
139
+ $iter.times do
140
+ JSON.parse(s)
141
+ end
142
+ dt = Time.now - start
143
+ if base_dt < dt
144
+ base_dt = dt
145
+ base_name = 'JSON::Pure'
146
+ end
147
+ parse_results[:pure] = dt
148
+ puts "%d JSON::Pure::Parser parse()s in %0.3f seconds or %0.1f parses/msec" % [$iter, dt, $iter/dt/1000.0]
149
+ rescue Exception => e
150
+ puts "JSON::Pure failed: #{e.class}: #{e.message}"
151
+ end
152
+
153
+ begin
154
+ mp = MessagePack.pack(obj)
155
+ start = Time.now
156
+ $iter.times do
157
+ MessagePack.unpack(mp)
158
+ end
159
+ dt = Time.now - start
160
+ if base_dt < dt
161
+ base_dt = dt
162
+ base_name = 'MessagePack'
163
+ end
164
+ parse_results[:msgpack] = dt
165
+ puts "%d MessagePack.unpack()s in %0.3f seconds or %0.1f packs/msec" % [$iter, dt, $iter/dt/1000.0]
166
+ rescue Exception => e
167
+ puts "MessagePack failed: #{e.class}: #{e.message}"
168
+ end
43
169
 
44
- puts "Oj is %0.1f times faster than YAJL at parsing." % [yajl_dt / oj_dt]
170
+ start = Time.now
171
+ $iter.times do
172
+ Ox.load(xml)
173
+ end
174
+ dt = Time.now - start
175
+ parse_results[:ox] = dt
176
+ puts "%d Ox.load()s in %0.3f seconds or %0.1f loads/msec" % [$iter, dt, $iter/dt/1000.0]
177
+
178
+ puts "Parser results:"
179
+ puts "gem seconds parses/msec X faster than #{base_name} (higher is better)"
180
+ parse_results.each do |name,dt|
181
+ if 0.0 == dt
182
+ puts "#{name} failed to generate JSON"
183
+ next
184
+ end
185
+ puts "%-7s %6.3f %5.1f %4.1f" % [name, dt, $iter/dt/1000.0, base_dt/dt]
186
+ end
45
187
 
46
188
  puts
47
189
 
48
- obj = Oj.load(s)
190
+ # Back to object mode for best performance when dumping.
191
+ Oj.default_options = { :indent => $indent, :mode => :object }
192
+ dump_results = { :oj => 0.0, :yajl => 0.0, :msgpack => 0.0, :pure => 0.0, :ext => 0.0, :ox => 0.0 }
193
+
49
194
  start = Time.now
50
- iter.times do
195
+ $iter.times do
51
196
  Oj.dump(obj)
52
197
  end
53
- oj_dt = Time.now - start
54
- puts "%d Oj.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter, oj_dt, iter/oj_dt/1000.0]
198
+ dt = Time.now - start
199
+ base_dt = dt
200
+ base_name = 'Oj'
201
+ parse_results[:oj] = dt
202
+ puts "%d Oj.dump()s in %0.3f seconds or %0.1f dumps/msec" % [$iter, dt, $iter/dt/1000.0]
55
203
 
56
204
  start = Time.now
57
- iter.times do
205
+ $iter.times do
58
206
  Yajl::Encoder.encode(obj)
59
207
  end
60
- yajl_dt = Time.now - start
61
- puts "%d Yajl::Encoder.encode()s in %0.3f seconds or %0.1f encodes/msec" % [iter, yajl_dt, iter/yajl_dt/1000.0]
208
+ dt = Time.now - start
209
+ if base_dt < dt
210
+ base_dt = dt
211
+ base_name = 'Yajl'
212
+ end
213
+ parse_results[:yajl] = dt
214
+ puts "%d Yajl::Encoder.encode()s in %0.3f seconds or %0.1f encodes/msec" % [$iter, dt, $iter/dt/1000.0]
215
+
216
+ begin
217
+ JSON.parser = JSON::Ext::Parser
218
+ start = Time.now
219
+ $iter.times do
220
+ JSON.generate(obj)
221
+ end
222
+ dt = Time.now - start
223
+ if base_dt < dt
224
+ base_dt = dt
225
+ base_name = 'JSON::Ext'
226
+ end
227
+ parse_results[:pure] = dt
228
+ puts "%d JSON::Ext generate()s in %0.3f seconds or %0.1f generates/msec" % [$iter, dt, $iter/dt/1000.0]
229
+ rescue Exception => e
230
+ parse_results[:ext] = 0.0
231
+ puts "JSON::Ext failed: #{e.class}: #{e.message}"
232
+ end
62
233
 
63
- puts "Oj is %0.1f times faster than YAJL at dumping." % [yajl_dt / oj_dt]
234
+ begin
235
+ JSON.parser = JSON::Pure::Parser
236
+ start = Time.now
237
+ $iter.times do
238
+ JSON.generate(obj)
239
+ end
240
+ dt = Time.now - start
241
+ if base_dt < dt
242
+ base_dt = dt
243
+ base_name = 'JSON::Pure'
244
+ end
245
+ parse_results[:pure] = dt
246
+ puts "%d JSON::Pure generate()s in %0.3f seconds or %0.1f generates/msec" % [$iter, dt, $iter/dt/1000.0]
247
+ rescue Exception => e
248
+ parse_results[:pure] = 0.0
249
+ puts "JSON::Pure failed: #{e.class}: #{e.message}"
250
+ end
251
+
252
+ begin
253
+ start = Time.now
254
+ $iter.times do
255
+ MessagePack.pack(obj)
256
+ end
257
+ dt = Time.now - start
258
+ if base_dt < dt
259
+ base_dt = dt
260
+ base_name = 'MessagePack'
261
+ end
262
+ parse_results[:msgpack] = dt
263
+ puts "%d Msgpack()s in %0.3f seconds or %0.1f unpacks/msec" % [$iter, dt, $iter/dt/1000.0]
264
+ rescue Exception => e
265
+ parse_results[:msgpack] = 0.0
266
+ puts "MessagePack failed: #{e.class}: #{e.message}"
267
+ end
268
+
269
+ start = Time.now
270
+ $iter.times do
271
+ Ox.dump(obj)
272
+ end
273
+ dt = Time.now - start
274
+ parse_results[:ox] = dt
275
+ puts "%d Ox.dump()s in %0.3f seconds or %0.1f dumps/msec" % [$iter, dt, $iter/dt/1000.0]
276
+
277
+ puts "Parser results:"
278
+ puts "gem seconds dumps/msec X faster than #{base_name} (higher is better)"
279
+ parse_results.each do |name,dt|
280
+ if 0.0 == dt
281
+ puts "#{name} failed to generate JSON"
282
+ next
283
+ end
284
+ puts "%-7s %6.3f %5.1f %4.1f" % [name, dt, $iter/dt/1000.0, base_dt/dt]
285
+ end
64
286
 
65
287
  puts