oj 0.5.1 → 0.5.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 CHANGED
@@ -18,7 +18,9 @@ A fast JSON parser and Object marshaller as a Ruby gem.
18
18
 
19
19
  ## <a name="release">Release Notes</a>
20
20
 
21
- ### Release 0.5
21
+ ### Release 0.5.2
22
+
23
+ - Release 0.5.2 fixes encoding and float encoding.
22
24
 
23
25
  This is the first release sith a version of 0.5 indicating it is only half
24
26
  done. Basic load() and dump() is supported for Hash, Array, NilClass,
@@ -158,7 +158,7 @@ grow(Out out, size_t len) {
158
158
 
159
159
  inline static void
160
160
  dump_hex(u_char c, Out out) {
161
- u_char d = c & 0xF0;
161
+ u_char d = (c >> 4) & 0x0F;
162
162
 
163
163
  if (9 < d) {
164
164
  *out->cur++ = (d - 10) + 'a';
@@ -116,7 +116,7 @@ parse(char *json, Options options) {
116
116
  /* initialize parse info */
117
117
  pi.str = json;
118
118
  pi.s = json;
119
- pi.encoding = 0;
119
+ pi.encoding = ('\0' == *options->encoding) ? 0 : rb_enc_find(options->encoding);
120
120
  pi.options = options;
121
121
  if (Qundef == (obj = read_next(&pi))) {
122
122
  raise_error("no object read", pi.str, pi.s);
@@ -298,14 +298,17 @@ read_num(ParseInfo pi) {
298
298
  e = e * 10 + (*pi->s - '0');
299
299
  }
300
300
  }
301
- if (neg) {
302
- n = -n;
303
- }
304
301
  if (0 == e && 0 == a && 1 == div) {
302
+ if (neg) {
303
+ n = -n;
304
+ }
305
305
  return LONG2NUM(n);
306
306
  } else {
307
307
  double d = (double)n + (double)a / (double)div;
308
308
 
309
+ if (neg) {
310
+ d = -d;
311
+ }
309
312
  if (0 != e) {
310
313
  if (eneg) {
311
314
  e = -e;
@@ -41,14 +41,6 @@ typedef struct _YesNoOpt {
41
41
  char *attr;
42
42
  } *YesNoOpt;
43
43
 
44
- struct _Options default_options = {
45
- { '\0' }, // encoding
46
- 2, // indent
47
- No, // circular
48
- NoMode, // mode
49
- TolerantEffort, // effort
50
- };
51
-
52
44
  void Init_oj();
53
45
 
54
46
  VALUE Oj = Qnil;
@@ -64,6 +56,13 @@ VALUE simple_sym;
64
56
  VALUE strict_sym;
65
57
  VALUE tolerant_sym;
66
58
 
59
+ static struct _Options default_options = {
60
+ { '\0' }, // encoding
61
+ 0, // indent
62
+ No, // circular
63
+ NoMode, // mode
64
+ TolerantEffort, // effort
65
+ };
67
66
 
68
67
  /* call-seq: default_options() => Hash
69
68
  *
@@ -106,8 +105,13 @@ get_def_opts(VALUE self) {
106
105
  * @param [Fixnum] :indent number of spaces to indent each element in an XML document
107
106
  * @param [String] :encoding character encoding for the JSON file
108
107
  * @param [true|false|nil] :circular support circular references while dumping
109
- * @param [:object|:simple|nil] :mode load method to use for JSON
110
- * @param [:strict|:tolerant|:lazy] :effort set the tolerance level for loading
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.
111
115
  * @return [nil]
112
116
  */
113
117
  static VALUE
@@ -121,8 +125,10 @@ set_def_opts(VALUE self, VALUE opts) {
121
125
 
122
126
  Check_Type(opts, T_HASH);
123
127
 
124
- v = rb_hash_aref(opts, encoding_sym);
125
- if (Qnil == v) {
128
+ v = rb_hash_lookup2(opts, encoding_sym, Qundef);
129
+ if (Qundef == v) {
130
+ // no change
131
+ } else if (Qnil == v) {
126
132
  *default_options.encoding = '\0';
127
133
  } else {
128
134
  Check_Type(v, T_STRING);
@@ -135,8 +141,10 @@ set_def_opts(VALUE self, VALUE opts) {
135
141
  default_options.indent = FIX2INT(v);
136
142
  }
137
143
 
138
- v = rb_hash_aref(opts, mode_sym);
139
- if (Qnil == v) {
144
+ v = rb_hash_lookup2(opts, mode_sym, Qundef);
145
+ if (Qundef == v) {
146
+ // no change
147
+ } else if (Qnil == v) {
140
148
  default_options.mode = NoMode;
141
149
  } else if (object_sym == v) {
142
150
  default_options.mode = ObjectMode;
@@ -146,8 +154,10 @@ set_def_opts(VALUE self, VALUE opts) {
146
154
  rb_raise(rb_eArgError, ":mode must be :object, :simple, or nil.\n");
147
155
  }
148
156
 
149
- v = rb_hash_aref(opts, effort_sym);
150
- if (Qnil == v) {
157
+ v = rb_hash_lookup2(opts, effort_sym, Qundef);
158
+ if (Qundef == v) {
159
+ // no change
160
+ } else if (Qnil == v) {
151
161
  default_options.effort = NoEffort;
152
162
  } else if (strict_sym == v) {
153
163
  default_options.effort = StrictEffort;
@@ -159,8 +169,10 @@ set_def_opts(VALUE self, VALUE opts) {
159
169
  rb_raise(rb_eArgError, ":effort must be :strict, :tolerant, :lazy, or nil.\n");
160
170
  }
161
171
  for (o = ynos; 0 != o->attr; o++) {
162
- v = rb_hash_lookup(opts, o->sym);
163
- if (Qnil == v) {
172
+ v = rb_hash_lookup2(opts, o->sym, Qundef);
173
+ if (Qundef == v) {
174
+ // no change
175
+ } else if (Qnil == v) {
164
176
  *o->attr = NotSet;
165
177
  } else if (Qtrue == v) {
166
178
  *o->attr = Yes;
@@ -246,13 +258,13 @@ load(char *json, int argc, VALUE *argv, VALUE self) {
246
258
  return obj;
247
259
  }
248
260
 
249
- /* call-seq: load(xml, options) => Hash, Array, String, Fixnum, Float, true, false, or nil
261
+ /* call-seq: load(json, options) => Hash, Array, String, Fixnum, Float, true, false, or nil
250
262
  *
251
263
  * Parses a JSON document String into a Hash, Array, String, Fixnum, Float,
252
- * true, false, or nil Raises an exception if the JSON is * malformed or the
264
+ * true, false, or nil. Raises an exception if the JSON is malformed or the
253
265
  * classes specified are not valid.
254
266
  * @param [String] json JSON String
255
- * @param [Hash] options load options
267
+ * @param [Hash] options load options (same as default_options)
256
268
  */
257
269
  static VALUE
258
270
  load_str(int argc, VALUE *argv, VALUE self) {
@@ -294,6 +306,12 @@ load_file(int argc, VALUE *argv, VALUE self) {
294
306
  return load(json, argc - 1, argv + 1, self);
295
307
  }
296
308
 
309
+ /* call-seq: dump(obj, options) => json-string
310
+ *
311
+ * Dumps an Object (obj) to a string.
312
+ * @param [Object] obj Object to serialize as an JSON document String
313
+ * @param [Hash] options same as default_options
314
+ */
297
315
  static VALUE
298
316
  dump(int argc, VALUE *argv, VALUE self) {
299
317
  char *json;
@@ -340,6 +358,7 @@ void Init_oj() {
340
358
  simple_sym = ID2SYM(rb_intern("simple")); rb_ary_push(keep, simple_sym);
341
359
  strict_sym = ID2SYM(rb_intern("strict")); rb_ary_push(keep, strict_sym);
342
360
  tolerant_sym = ID2SYM(rb_intern("tolerant")); rb_ary_push(keep, tolerant_sym);
361
+ default_options.effort = TolerantEffort;
343
362
  }
344
363
 
345
364
  void
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '0.5.1'
4
+ VERSION = '0.5.2'
5
5
  end
@@ -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]
@@ -0,0 +1,58 @@
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 'yajl'
10
+ require 'oj'
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
+
26
+ start = Time.now
27
+ iter.times do
28
+ Oj.load(s)
29
+ 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]
32
+
33
+ start = Time.now
34
+ iter.times do
35
+ Yajl::Parser.parse(s)
36
+ 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]
39
+
40
+ puts "Oj is %0.1f times faster than YAJL at parsing." % [yajl_dt / oj_dt]
41
+
42
+
43
+ obj = Oj.load(s)
44
+ start = Time.now
45
+ iter.times do
46
+ Oj.dump(obj)
47
+ 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]
50
+
51
+ start = Time.now
52
+ iter.times do
53
+ Yajl::Encoder.encode(obj)
54
+ 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]
57
+
58
+ puts "Oj is %0.1f times faster than YAJL at dumping." % [yajl_dt / oj_dt]
@@ -0,0 +1,65 @@
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 'yajl'
10
+ require 'oj'
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
+
26
+ Oj.default_options = { :indent => 0 }
27
+
28
+ puts
29
+
30
+ start = Time.now
31
+ iter.times do
32
+ Oj.load(s)
33
+ 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]
36
+
37
+ start = Time.now
38
+ iter.times do
39
+ Yajl::Parser.parse(s)
40
+ 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]
43
+
44
+ puts "Oj is %0.1f times faster than YAJL at parsing." % [yajl_dt / oj_dt]
45
+
46
+ puts
47
+
48
+ obj = Oj.load(s)
49
+ start = Time.now
50
+ iter.times do
51
+ Oj.dump(obj)
52
+ 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]
55
+
56
+ start = Time.now
57
+ iter.times do
58
+ Yajl::Encoder.encode(obj)
59
+ 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]
62
+
63
+ puts "Oj is %0.1f times faster than YAJL at dumping." % [yajl_dt / oj_dt]
64
+
65
+ puts
@@ -0,0 +1,104 @@
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 'oj'
9
+
10
+ class Juice < ::Test::Unit::TestCase
11
+
12
+ def test_get_options
13
+ opts = Oj.default_options()
14
+ assert_equal(opts, {
15
+ :encoding=>nil,
16
+ :indent=>0,
17
+ :circular=>false,
18
+ :mode=>nil,
19
+ :effort=>:tolerant})
20
+ end
21
+
22
+ def test_set_options
23
+ orig = {
24
+ :encoding=>nil,
25
+ :indent=>0,
26
+ :circular=>false,
27
+ :mode=>nil,
28
+ :effort=>:tolerant}
29
+ o2 = {
30
+ :encoding=>"UTF-8",
31
+ :indent=>4,
32
+ :circular=>true,
33
+ :mode=>:object,
34
+ :effort=>:strict }
35
+ o3 = { :indent => 4 }
36
+ Oj.default_options = o2
37
+ opts = Oj.default_options()
38
+ assert_equal(opts, o2);
39
+ Oj.default_options = o3 # see if it throws an exception
40
+ Oj.default_options = orig # return to original
41
+ end
42
+
43
+ def test_nil
44
+ dump_and_load(nil, false)
45
+ end
46
+
47
+ def test_true
48
+ dump_and_load(true, false)
49
+ end
50
+
51
+ def test_false
52
+ dump_and_load(false, false)
53
+ end
54
+
55
+ def test_fixnum
56
+ dump_and_load(0, false)
57
+ dump_and_load(12345, false)
58
+ dump_and_load(-54321, false)
59
+ dump_and_load(1, false)
60
+ end
61
+
62
+ def test_float
63
+ dump_and_load(0.0, false)
64
+ dump_and_load(12345.6789, false)
65
+ dump_and_load(-54321.012, true)
66
+ dump_and_load(2.48e16, false)
67
+ end
68
+
69
+ def test_string
70
+ dump_and_load('', false)
71
+ dump_and_load('abc', false)
72
+ dump_and_load("abc\ndef", false)
73
+ dump_and_load("a\u0041", false)
74
+ end
75
+
76
+ def test_array
77
+ dump_and_load([], false)
78
+ dump_and_load([true, false], false)
79
+ dump_and_load(['a', 1, nil], false)
80
+ dump_and_load([[nil]], false)
81
+ dump_and_load([[nil], 58], false)
82
+ end
83
+
84
+ def test_hash
85
+ dump_and_load({}, false)
86
+ dump_and_load({ 'true' => true, 'false' => false}, false)
87
+ dump_and_load({ 'true' => true, 'array' => [], 'hash' => { }}, false)
88
+ end
89
+
90
+ def test_encode
91
+ Oj.default_options = { :encoding => 'UTF-8' }
92
+ dump_and_load("ぴーたー", false)
93
+ Oj.default_options = { :encoding => nil }
94
+ end
95
+
96
+ def dump_and_load(obj, trace=false)
97
+ json = Oj.dump(obj, :indent => 2)
98
+ puts json if trace
99
+ loaded = Oj.load(json, :mode => :simple);
100
+ assert_equal(obj, loaded)
101
+ loaded
102
+ end
103
+
104
+ end
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: 0.5.1
4
+ version: 0.5.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,10 +11,7 @@ bindir: bin
11
11
  cert_chain: []
12
12
  date: 2012-02-19 00:00:00.000000000 Z
13
13
  dependencies: []
14
- description: ! "A fast JSON parser and object serializer that uses only standard C
15
- lib.\n \nOptimized JSON (Oj), as the name implies was written to provide
16
- speed optimized\nJSON handling. It was designed to be an alternative to Yajl and
17
- other Ruby\nJSON parsers and as an alternative to Marshal for Object serialization. "
14
+ description: ! 'The fastest JSON parser and object serializer. '
18
15
  email: peter@ohler.com
19
16
  executables: []
20
17
  extensions:
@@ -29,6 +26,10 @@ files:
29
26
  - ext/oj/dump.c
30
27
  - ext/oj/load.c
31
28
  - ext/oj/oj.c
29
+ - test/boo.rb
30
+ - test/foo.rb
31
+ - test/perf_simple.rb
32
+ - test/simple.rb
32
33
  - LICENSE
33
34
  - README.md
34
35
  homepage: https://github.com/ohler55/oj