oj 1.1.0 → 1.1.1

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 CHANGED
@@ -24,15 +24,11 @@ A fast JSON parser and Object marshaller as a Ruby gem.
24
24
 
25
25
  ## <a name="release">Release Notes</a>
26
26
 
27
- ### Release 1.1.0
27
+ ### Release 1.1.1
28
28
 
29
- - Errors are not longer raised when comments are encountered in JSON documents.
29
+ - The encoding option can now be an Encoding Object or a String.
30
30
 
31
- - Oj can now mimic JSON. With some expections calling JSON.mimic_JSON will allow all JSON calls to use OJ instead of JSON. This gives a speedup of more than 2x on parsing and 5x for generating over the JSON::Ext module.
32
-
33
- - Oj::Doc now allows a document to be left open and then closed with the Oj::Doc.close() class.
34
-
35
- - Changed the default encoding to UTF-8 instead of the Ruby default String encoding.
31
+ - Fixed Rubinius errors.
36
32
 
37
33
  ## <a name="description">Description</a>
38
34
 
@@ -336,7 +336,7 @@ static void
336
336
  dump_float(VALUE obj, Out out) {
337
337
  char buf[64];
338
338
  char *b;
339
- double d = RFLOAT_VALUE(obj);
339
+ double d = rb_num2dbl(obj);
340
340
  int cnt;
341
341
 
342
342
  switch (fpclassify(d)) {
@@ -775,7 +775,7 @@ doc_init(Doc doc) {
775
775
  doc->data = 0;
776
776
  doc->self = Qundef;
777
777
  #ifdef HAVE_RUBY_ENCODING_H
778
- doc->encoding = ('\0' == *oj_default_options.encoding) ? 0 : rb_enc_find(oj_default_options.encoding);
778
+ doc->encoding = oj_default_options.encoding;
779
779
  #else
780
780
  doc->encoding = 0;
781
781
  #endif
@@ -520,8 +520,10 @@ read_array(ParseInfo pi, int hint) {
520
520
  VALUE e;
521
521
  int type = T_NONE;
522
522
  int cnt = 0;
523
- long slen = 0;
524
523
  int a_str;
524
+ #ifndef NO_RSTRUCT
525
+ long slen = 0;
526
+ #endif
525
527
 
526
528
  pi->s++;
527
529
  next_non_white(pi);
@@ -896,7 +898,8 @@ oj_parse(char *json, Options options) {
896
898
  pi.circ_array = circ_array_new();
897
899
  }
898
900
  #ifdef HAVE_RUBY_ENCODING_H
899
- pi.encoding = ('\0' == *options->encoding) ? 0 : rb_enc_find(options->encoding);
901
+ pi.encoding = options->encoding;
902
+ //pi.encoding = ('\0' == *options->encoding) ? 0 : rb_enc_find(options->encoding);
900
903
  #else
901
904
  pi.encoding = 0;
902
905
  #endif
@@ -40,7 +40,7 @@
40
40
  #include "oj.h"
41
41
 
42
42
  // maximum to allocate on the stack, arbitrary limit
43
- #define SMALL_XML 65536
43
+ #define SMALL_JSON 65536
44
44
 
45
45
  typedef struct _YesNoOpt {
46
46
  VALUE sym;
@@ -100,8 +100,7 @@ Cache oj_class_cache = 0;
100
100
  Cache oj_attr_cache = 0;
101
101
 
102
102
  struct _Options oj_default_options = {
103
- // { '\0' }, // encoding
104
- "UTF-8", // encoding
103
+ 0, // encoding
105
104
  0, // indent
106
105
  No, // circular
107
106
  Yes, // auto_define
@@ -116,8 +115,8 @@ static VALUE define_mimic_json(VALUE self);
116
115
  /* call-seq: default_options() => Hash
117
116
  *
118
117
  * Returns the default load and dump options as a Hash. The options are
119
- * - indent: [Fixnum] number of spaces to indent each element in an XML document
120
- * - encoding: [String] character encoding for the JSON file
118
+ * - indent: [Fixnum] number of spaces to indent each element in an JSON document
119
+ * - encoding: [String|Encoding] character encoding for the JSON coument
121
120
  * - circular: [true|false|nil] support circular references while dumping
122
121
  * - auto_define: [true|false|nil] automatically define classes if they do not exist
123
122
  * - symbol_keys: [true|false|nil] use symbols instead of strings for hash keys
@@ -127,9 +126,10 @@ static VALUE define_mimic_json(VALUE self);
127
126
  static VALUE
128
127
  get_def_opts(VALUE self) {
129
128
  VALUE opts = rb_hash_new();
130
- int elen = (int)strlen(oj_default_options.encoding);
131
-
132
- rb_hash_aset(opts, encoding_sym, (0 == elen) ? Qnil : rb_str_new(oj_default_options.encoding, elen));
129
+
130
+ #ifdef HAVE_RUBY_ENCODING_H
131
+ rb_hash_aset(opts, encoding_sym, (0 == oj_default_options.encoding) ? Qnil : rb_enc_from_encoding(oj_default_options.encoding));
132
+ #endif
133
133
  rb_hash_aset(opts, indent_sym, INT2FIX(oj_default_options.indent));
134
134
  rb_hash_aset(opts, circular_sym, (Yes == oj_default_options.circular) ? Qtrue : ((No == oj_default_options.circular) ? Qfalse : Qnil));
135
135
  rb_hash_aset(opts, auto_define_sym, (Yes == oj_default_options.auto_define) ? Qtrue : ((No == oj_default_options.auto_define) ? Qfalse : Qnil));
@@ -149,7 +149,7 @@ get_def_opts(VALUE self) {
149
149
  *
150
150
  * Sets the default options for load and dump.
151
151
  * @param [Hash] opts options to change
152
- * @param [Fixnum] :indent number of spaces to indent each element in an XML document
152
+ * @param [Fixnum] :indent number of spaces to indent each element in an JSON document
153
153
  * @param [String] :encoding character encoding for the JSON file
154
154
  * @param [true|false|nil] :circular support circular references while dumping
155
155
  * @param [true|false|nil] :auto_define automatically define classes if they do not exist
@@ -178,15 +178,20 @@ set_def_opts(VALUE self, VALUE opts) {
178
178
 
179
179
  Check_Type(opts, T_HASH);
180
180
 
181
+ #ifdef HAVE_RUBY_ENCODING_H
181
182
  if (Qtrue == rb_funcall(opts, rb_intern("has_key?"), 1, encoding_sym)) {
182
183
  v = rb_hash_lookup(opts, encoding_sym);
183
184
  if (Qnil == v) {
184
- *oj_default_options.encoding = '\0';
185
+ oj_default_options.encoding = 0;
186
+ } else if (T_STRING == rb_type(v)) {
187
+ oj_default_options.encoding = rb_enc_find(StringValuePtr(v));
188
+ } else if (rb_cEncoding == rb_obj_class(v)) {
189
+ oj_default_options.encoding = rb_to_encoding(v);
185
190
  } else {
186
- Check_Type(v, T_STRING);
187
- strncpy(oj_default_options.encoding, StringValuePtr(v), sizeof(oj_default_options.encoding) - 1);
191
+ rb_raise(rb_eArgError, ":encoding must be nil, a String, or an Encoding.\n");
188
192
  }
189
193
  }
194
+ #endif
190
195
  v = rb_hash_aref(opts, indent_sym);
191
196
  if (Qnil != v) {
192
197
  Check_Type(v, T_FIXNUM);
@@ -245,12 +250,17 @@ parse_options(VALUE ropts, Options copts) {
245
250
  }
246
251
  copts->indent = NUM2INT(v);
247
252
  }
253
+ #ifdef HAVE_RUBY_ENCODING_H
248
254
  if (Qnil != (v = rb_hash_lookup(ropts, encoding_sym))) {
249
- if (rb_cString != rb_obj_class(v)) {
250
- rb_raise(rb_eArgError, ":encoding must be a String.\n");
251
- }
252
- strncpy(copts->encoding, StringValuePtr(v), sizeof(copts->encoding) - 1);
255
+ if (T_STRING == rb_type(v)) {
256
+ oj_default_options.encoding = rb_enc_find(StringValuePtr(v));
257
+ } else if (rb_cEncoding == rb_obj_class(v)) {
258
+ oj_default_options.encoding = rb_to_encoding(v);
259
+ } else {
260
+ rb_raise(rb_eArgError, ":encoding must be nil, a String, or an Encoding.\n");
261
+ }
253
262
  }
263
+ #endif
254
264
  if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) {
255
265
  if (object_sym == v) {
256
266
  copts->mode = ObjectMode;
@@ -287,7 +297,7 @@ load_with_opts(VALUE input, Options copts) {
287
297
  if (rb_type(input) == T_STRING) {
288
298
  // the json string gets modified so make a copy of it
289
299
  len = RSTRING_LEN(input) + 1;
290
- if (SMALL_XML < len) {
300
+ if (SMALL_JSON < len) {
291
301
  json = ALLOC_N(char, len);
292
302
  } else {
293
303
  json = ALLOCA_N(char, len);
@@ -300,7 +310,7 @@ load_with_opts(VALUE input, Options copts) {
300
310
  if (oj_stringio_class == clas) {
301
311
  s = rb_funcall2(input, oj_string_id, 0, 0);
302
312
  len = RSTRING_LEN(s) + 1;
303
- if (SMALL_XML < len) {
313
+ if (SMALL_JSON < len) {
304
314
  json = ALLOC_N(char, len);
305
315
  } else {
306
316
  json = ALLOCA_N(char, len);
@@ -312,7 +322,7 @@ load_with_opts(VALUE input, Options copts) {
312
322
 
313
323
  len = lseek(fd, 0, SEEK_END);
314
324
  lseek(fd, 0, SEEK_SET);
315
- if (SMALL_XML < len) {
325
+ if (SMALL_JSON < len) {
316
326
  json = ALLOC_N(char, len + 1);
317
327
  } else {
318
328
  json = ALLOCA_N(char, len + 1);
@@ -324,7 +334,7 @@ load_with_opts(VALUE input, Options copts) {
324
334
  } else if (rb_respond_to(input, oj_read_id)) {
325
335
  s = rb_funcall2(input, oj_read_id, 0, 0);
326
336
  len = RSTRING_LEN(s) + 1;
327
- if (SMALL_XML < len) {
337
+ if (SMALL_JSON < len) {
328
338
  json = ALLOC_N(char, len);
329
339
  } else {
330
340
  json = ALLOCA_N(char, len);
@@ -335,7 +345,7 @@ load_with_opts(VALUE input, Options copts) {
335
345
  }
336
346
  }
337
347
  obj = oj_parse(json, copts);
338
- if (SMALL_XML < len) {
348
+ if (SMALL_JSON < len) {
339
349
  xfree(json);
340
350
  }
341
351
  return obj;
@@ -378,7 +388,7 @@ load_file(int argc, VALUE *argv, VALUE self) {
378
388
  }
379
389
  fseek(f, 0, SEEK_END);
380
390
  len = ftell(f);
381
- if (SMALL_XML < len) {
391
+ if (SMALL_JSON < len) {
382
392
  json = ALLOC_N(char, len + 1);
383
393
  } else {
384
394
  json = ALLOCA_N(char, len + 1);
@@ -394,7 +404,7 @@ load_file(int argc, VALUE *argv, VALUE self) {
394
404
  parse_options(argv[1], &options);
395
405
  }
396
406
  obj = oj_parse(json, &options);
397
- if (SMALL_XML < len) {
407
+ if (SMALL_JSON < len) {
398
408
  xfree(json);
399
409
  }
400
410
  return obj;
@@ -420,8 +430,8 @@ dump(int argc, VALUE *argv, VALUE self) {
420
430
  }
421
431
  rstr = rb_str_new2(json);
422
432
  #ifdef HAVE_RUBY_ENCODING_H
423
- if ('\0' != *copts.encoding) {
424
- rb_enc_associate(rstr, rb_enc_find(copts.encoding));
433
+ if (0 != copts.encoding) {
434
+ rb_enc_associate(rstr, copts.encoding);
425
435
  }
426
436
  #endif
427
437
  xfree(json);
@@ -465,8 +475,8 @@ mimic_dump(int argc, VALUE *argv, VALUE self) {
465
475
  }
466
476
  rstr = rb_str_new2(json);
467
477
  #ifdef ENCODING_INLINE_MAX
468
- if ('\0' != *copts.encoding) {
469
- rb_enc_associate(rstr, rb_enc_find(copts.encoding));
478
+ if (0 != copts.encoding) {
479
+ rb_enc_associate(rstr, copts.encoding);
470
480
  }
471
481
  #endif
472
482
  if (2 <= argc && Qnil != argv[1]) {
@@ -485,8 +495,6 @@ mimic_dump(int argc, VALUE *argv, VALUE self) {
485
495
  // This is the signature for the hash_foreach callback also.
486
496
  static int
487
497
  mimic_walk(VALUE key, VALUE obj, VALUE proc) {
488
- VALUE args[1];
489
-
490
498
  switch (rb_type(obj)) {
491
499
  case T_HASH:
492
500
  rb_hash_foreach(obj, mimic_walk, proc);
@@ -504,11 +512,19 @@ mimic_walk(VALUE key, VALUE obj, VALUE proc) {
504
512
  default:
505
513
  break;
506
514
  }
507
- *args = obj;
508
515
  if (Qnil == proc) {
509
- rb_yield_values2(1, args);
516
+ if (rb_block_given_p()) {
517
+ rb_yield(obj);
518
+ }
510
519
  } else {
520
+ #ifdef RUBINIUS
521
+ rb_raise(rb_eNotImpError, "Not supported in Rubinius.\n");
522
+ #else
523
+ VALUE args[1];
524
+
525
+ *args = obj;
511
526
  rb_proc_call_with_block(proc, 1, args, Qnil);
527
+ #endif
512
528
  }
513
529
  return ST_CONTINUE;
514
530
  }
@@ -516,10 +532,13 @@ mimic_walk(VALUE key, VALUE obj, VALUE proc) {
516
532
  static VALUE
517
533
  mimic_load(int argc, VALUE *argv, VALUE self) {
518
534
  VALUE obj = load(1, argv, self);
535
+ VALUE p = Qnil;
519
536
 
520
- if (2 <= argc && Qnil != argv[1]) {
521
- mimic_walk(Qnil, obj, argv[1]);
537
+ if (2 <= argc) {
538
+ p = argv[1];
522
539
  }
540
+ mimic_walk(Qnil, obj, p);
541
+
523
542
  return obj;
524
543
  }
525
544
 
@@ -596,8 +615,8 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) {
596
615
  }
597
616
  rstr = rb_str_new2(json);
598
617
  #ifdef ENCODING_INLINE_MAX
599
- if ('\0' != *copts->encoding) {
600
- rb_enc_associate(rstr, rb_enc_find(copts->encoding));
618
+ if (0 != copts->encoding) {
619
+ rb_enc_associate(rstr, copts->encoding);
601
620
  }
602
621
  #endif
603
622
  xfree(json);
@@ -673,6 +692,14 @@ no_op1(VALUE self, VALUE obj) {
673
692
  return Qnil;
674
693
  }
675
694
 
695
+ /* call-seq: mimic_JSON() => Module
696
+ *
697
+ * Creates the JSON module with methods and classes to mimic the JSON
698
+ * gem. After this method is invoked calls that expect the JSON module will
699
+ * use Oj instead and be faster than the original JSON. Most options that
700
+ * could be passed to the JSON methods are supported. The calls to set parser
701
+ * or generator will not raise an Exception but will not have any effect.
702
+ */
676
703
  static VALUE
677
704
  define_mimic_json(VALUE self) {
678
705
  if (Qnil == mimic) {
@@ -762,6 +789,9 @@ void Init_oj() {
762
789
  oj_slash_string = rb_str_new2("/"); rb_ary_push(keep, oj_slash_string);
763
790
 
764
791
  oj_default_options.mode = ObjectMode;
792
+ #ifdef HAVE_RUBY_ENCODING_H
793
+ oj_default_options.encoding = rb_enc_find("UTF-8");
794
+ #endif
765
795
 
766
796
  oj_cache_new(&oj_class_cache);
767
797
  oj_cache_new(&oj_attr_cache);
@@ -99,7 +99,12 @@ typedef struct _DumpOpts {
99
99
  } *DumpOpts;
100
100
 
101
101
  typedef struct _Options {
102
- char encoding[64]; // encoding, stored in the option to avoid GC invalidation in default values
102
+ #ifdef HAVE_RUBY_ENCODING_H
103
+ rb_encoding *encoding;
104
+ #else
105
+ void *encoding;
106
+ #endif
107
+ //char encoding[64]; // encoding, stored in the option to avoid GC invalidation in default values
103
108
  int indent; // indention for dump, default 2
104
109
  char circular; // YesNo
105
110
  char auto_define; // YesNo
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '1.1.0'
4
+ VERSION = '1.1.1'
5
5
  end
@@ -42,7 +42,7 @@ class Perf
42
42
  end
43
43
  iva = @items.clone
44
44
  iva.delete_if { |i| i.duration.nil? }
45
- iva.sort_by! { |i| i.duration }
45
+ iva = iva.sort_by { |i| i.duration }
46
46
  puts
47
47
  puts "Summary:"
48
48
  puts "%*s time (secs) rate (ops/sec)" % [width, 'System']
@@ -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
@@ -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
- 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]
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
- 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]
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 "Oj is %0.1f times faster than YAJL at parsing." % [yajl_dt / oj_dt]
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
- 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]
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
- 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]
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 "Oj is %0.1f times faster than YAJL at dumping." % [yajl_dt / oj_dt]
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
@@ -6,14 +6,14 @@ $: << File.join(File.dirname(__FILE__), "../lib")
6
6
  $: << File.join(File.dirname(__FILE__), "../ext")
7
7
 
8
8
  require 'optparse'
9
- require 'yajl'
9
+ #require 'yajl'
10
10
  require 'perf'
11
- require 'json'
12
- require 'json/pure'
13
- require 'json/ext'
14
- require 'msgpack'
11
+ #require 'json'
12
+ #require 'json/pure'
13
+ #require 'json/ext'
14
+ #require 'msgpack'
15
15
  require 'oj'
16
- require 'ox'
16
+ #require 'ox'
17
17
 
18
18
  class Jazz
19
19
  attr_accessor :boolean, :number, :string
@@ -108,11 +108,9 @@ end
108
108
  $obj['j'] = Jazz.new() if $with_object
109
109
 
110
110
  Oj.default_options = { :indent => $indent, :mode => :compat }
111
- Ox.default_options = { :indent => $indent, :mode => :object }
112
111
 
113
112
  $json = Oj.dump($obj)
114
113
  $obj_json = Oj.dump($obj, :mode => :object)
115
- $xml = Ox.dump($obj, :indent => $indent)
116
114
  $failed = {} # key is same as String used in tests later
117
115
 
118
116
  def capture_error(tag, orig, load_key, dump_key, &blk)
@@ -127,15 +125,23 @@ end
127
125
  # Verify that all packages dump and load correctly and return the same Object as the original.
128
126
  capture_error('Oj:compat', $obj, 'load', 'dump') { |o| Oj.load(Oj.dump(o)) }
129
127
  capture_error('Oj', $obj, 'load', 'dump') { |o| Oj.load(Oj.dump(o, :mode => :compat), :mode => :compat) }
130
- capture_error('Ox', $obj, 'load', 'dump') { |o| Ox.load(Ox.dump(o, :mode => :object), :mode => :object) }
131
- capture_error('MessagePack', $obj, 'unpack', 'pack') { |o| MessagePack.unpack(MessagePack.pack($obj)) }
132
- capture_error('Yajl', $obj, 'encode', 'parse') { |o| Yajl::Parser.parse(Yajl::Encoder.encode(o)) }
128
+ capture_error('Ox', $obj, 'load', 'dump') { |o|
129
+ require 'ox'
130
+ Ox.default_options = { :indent => $indent, :mode => :object }
131
+ $xml = Ox.dump($obj, :indent => $indent)
132
+ Ox.load(Ox.dump(o, :mode => :object), :mode => :object)
133
+ }
134
+ capture_error('MessagePack', $obj, 'unpack', 'pack') { |o| require 'msgpack'; MessagePack.unpack(MessagePack.pack($obj)) }
135
+ capture_error('Yajl', $obj, 'encode', 'parse') { |o| require 'yajl'; Yajl::Parser.parse(Yajl::Encoder.encode(o)) }
133
136
  capture_error('JSON::Ext', $obj, 'generate', 'parse') { |o|
137
+ require 'json'
138
+ require 'json/ext'
134
139
  JSON.generator = JSON::Ext::Generator
135
140
  JSON.parser = JSON::Ext::Parser
136
141
  JSON.parse(JSON.generate(o))
137
142
  }
138
143
  capture_error('JSON::Pure', $obj, 'generate', 'parse') { |o|
144
+ require 'json/pure'
139
145
  JSON.generator = JSON::Pure::Generator
140
146
  JSON.parser = JSON::Pure::Parser
141
147
  JSON.parse(JSON.generate(o))
@@ -69,10 +69,15 @@ class Mimic < ::Test::Unit::TestCase
69
69
  def test_load_proc
70
70
  children = []
71
71
  json = %{{"a":1,"b":[true,false]}}
72
- p = Proc.new {|x| children << x }
73
- obj = JSON.load(json, p)
72
+ if RUBY_ENGINE == 'rbx'
73
+ obj = JSON.load(json) {|x| children << x }
74
+ else
75
+ p = Proc.new {|x| children << x }
76
+ obj = JSON.load(json, p)
77
+ end
74
78
  assert_equal({ 'a' => 1, 'b' => [true, false]}, obj)
75
- assert_equal([1, true, false, [true, false], { 'a' => 1, 'b' => [true, false]}], children)
79
+ assert([1, true, false, [true, false], { 'a' => 1, 'b' => [true, false]}] == children ||
80
+ [true, false, [true, false], 1, { 'a' => 1, 'b' => [true, false]}] == children)
76
81
  end
77
82
 
78
83
  # []
@@ -90,7 +95,8 @@ class Mimic < ::Test::Unit::TestCase
90
95
  # generate
91
96
  def test_generate
92
97
  json = JSON.generate({ 'a' => 1, 'b' => [true, false]})
93
- assert_equal(%{{"a":1,"b":[true,false]}}, json)
98
+ assert(%{{"a":1,"b":[true,false]}} == json ||
99
+ %{{"b":[true,false],"a":1}} == json)
94
100
  end
95
101
  def test_generate_options
96
102
  json = JSON.generate({ 'a' => 1, 'b' => [true, false]},
@@ -99,33 +105,48 @@ class Mimic < ::Test::Unit::TestCase
99
105
  :object_nl => "#\n",
100
106
  :space => "*",
101
107
  :space_before => "~")
102
- assert_equal(%{{#
108
+ assert(%{{#
103
109
  --"a"~:*1,#
104
110
  --"b"~:*[
105
111
  ----true,
106
112
  ----false
107
113
  --]#
108
- }}, json)
114
+ }} == json ||
115
+ %{{#
116
+ --"b"~:*[
117
+ ----true,
118
+ ----false
119
+ --],#
120
+ --"a"~:*1#
121
+ }} == json)
122
+
109
123
  end
110
124
 
111
125
  # fast_generate
112
126
  def test_fast_generate
113
127
  json = JSON.generate({ 'a' => 1, 'b' => [true, false]})
114
- assert_equal(%{{"a":1,"b":[true,false]}}, json)
128
+ assert(%{{"a":1,"b":[true,false]}} == json ||
129
+ %{{"b":[true,false],"a":1}} == json)
115
130
  end
116
131
 
117
132
  # pretty_generate
118
133
  def test_pretty_generate
119
134
  json = JSON.pretty_generate({ 'a' => 1, 'b' => [true, false]})
120
- assert_equal(%{{
135
+ assert(%{{
121
136
  "a" : 1,
122
137
  "b" : [
123
138
  true,
124
139
  false
125
140
  ]
126
- }}, json)
141
+ }} == json ||
142
+ %{{
143
+ "b" : [
144
+ true,
145
+ false
146
+ ],
147
+ "a" : 1
148
+ }} == json)
127
149
  end
128
- # TBD with options
129
150
 
130
151
  # parse
131
152
  def test_parse
@@ -158,7 +179,8 @@ class Mimic < ::Test::Unit::TestCase
158
179
  def test_recurse_proc
159
180
  children = []
160
181
  obj = JSON.recurse_proc({ 'a' => 1, 'b' => [true, false]}) { |x| children << x }
161
- assert_equal([1, true, false, [true, false], { 'a' => 1, 'b' => [true, false]}], children)
182
+ assert([1, true, false, [true, false], { 'a' => 1, 'b' => [true, false]}] == children ||
183
+ [true, false, [true, false], 1, { 'b' => [true, false], 'a' => 1}] == children)
162
184
  end
163
185
 
164
186
  end # Mimic
@@ -67,7 +67,7 @@ class Juice < ::Test::Unit::TestCase
67
67
 
68
68
  def test0_get_options
69
69
  opts = Oj.default_options()
70
- assert_equal({ :encoding=>nil,
70
+ assert_equal({ :encoding=>Encoding.find('UTF-8'),
71
71
  :indent=>0,
72
72
  :circular=>false,
73
73
  :auto_define=>true,
@@ -96,6 +96,7 @@ class Juice < ::Test::Unit::TestCase
96
96
  o3 = { :indent => 4 }
97
97
  Oj.default_options = o2
98
98
  opts = Oj.default_options()
99
+ o2[:encoding] = Encoding.find('UTF-8')
99
100
  assert_equal(opts, o2);
100
101
  Oj.default_options = o3 # see if it throws an exception
101
102
  Oj.default_options = orig # return to original
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.1.0
4
+ version: 1.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -32,12 +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
35
  - test/files.rb
37
- - test/foo.rb
38
36
  - test/perf.rb
37
+ - test/perf1.rb
38
+ - test/perf2.rb
39
39
  - test/perf_fast.rb
40
40
  - test/perf_obj.rb
41
+ - test/perf_obj_old.rb
41
42
  - test/perf_simple.rb
42
43
  - test/perf_strict.rb
43
44
  - test/sample/change.rb
@@ -57,7 +58,6 @@ files:
57
58
  - test/test_fast.rb
58
59
  - test/test_mimic.rb
59
60
  - test/tests.rb
60
- - test/where.rb
61
61
  - LICENSE
62
62
  - README.md
63
63
  homepage: https://github.com/ohler55/oj
@@ -83,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
83
  version: '0'
84
84
  requirements: []
85
85
  rubyforge_project: oj
86
- rubygems_version: 1.8.15
86
+ rubygems_version: 1.8.21
87
87
  signing_key:
88
88
  specification_version: 3
89
89
  summary: A fast JSON parser and serializer.
@@ -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]
@@ -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