oj 1.2.9 → 1.2.10

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.

@@ -29,6 +29,7 @@
29
29
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
30
  */
31
31
 
32
+ #include <pthread.h> // TBD LOCK
32
33
  #include <stdlib.h>
33
34
  #include <errno.h>
34
35
  #include <stdio.h>
@@ -55,18 +56,21 @@ ID oj_as_json_id;
55
56
  ID oj_fileno_id;
56
57
  ID oj_instance_variables_id;
57
58
  ID oj_json_create_id;
59
+ ID oj_new_id;
58
60
  ID oj_read_id;
59
61
  ID oj_string_id;
60
62
  ID oj_to_hash_id;
61
63
  ID oj_to_json_id;
64
+ ID oj_to_s_id;
62
65
  ID oj_to_sym_id;
63
- ID oj_write_id;
66
+ ID oj_to_time_id;
64
67
  ID oj_tv_nsec_id;
65
68
  ID oj_tv_sec_id;
66
69
  ID oj_tv_usec_id;
70
+ ID oj_write_id;
67
71
 
68
72
  VALUE oj_bag_class;
69
- VALUE oj_date_class;
73
+ VALUE oj_bigdecimal_class;
70
74
  VALUE oj_stringio_class;
71
75
  VALUE oj_struct_class;
72
76
  VALUE oj_time_class;
@@ -101,6 +105,8 @@ Cache oj_attr_cache = 0;
101
105
  rb_encoding *oj_utf8_encoding = 0;
102
106
  #endif
103
107
 
108
+ pthread_mutex_t oj_cache_mutex; // only used if SAFE_CACHE defined
109
+
104
110
  static const char json_class[] = "json_class";
105
111
 
106
112
  struct _Options oj_default_options = {
@@ -116,6 +122,20 @@ struct _Options oj_default_options = {
116
122
 
117
123
  static VALUE define_mimic_json(VALUE self);
118
124
 
125
+ static struct _Odd odds[4]; // bump up if new Odd classes are added
126
+
127
+ Odd
128
+ oj_get_odd(VALUE clas) {
129
+ Odd odd = odds;
130
+
131
+ for (; Qundef != odd->clas; odd++) {
132
+ if (clas == odd->clas) {
133
+ return odd;
134
+ }
135
+ }
136
+ return 0;
137
+ }
138
+
119
139
  /* call-seq: default_options() => Hash
120
140
  *
121
141
  * Returns the default load and dump options as a Hash. The options are
@@ -764,10 +784,14 @@ define_mimic_json(VALUE self) {
764
784
  }
765
785
 
766
786
  void Init_oj() {
787
+ Odd odd;
788
+ ID *idp;
789
+
767
790
  Oj = rb_define_module("Oj");
768
791
 
769
792
  rb_require("time");
770
793
  rb_require("date");
794
+ rb_require("bigdecimal");
771
795
  rb_require("stringio");
772
796
 
773
797
  rb_define_module_function(Oj, "default_options", get_def_opts, 0);
@@ -783,20 +807,23 @@ void Init_oj() {
783
807
  oj_fileno_id = rb_intern("fileno");
784
808
  oj_instance_variables_id = rb_intern("instance_variables");
785
809
  oj_json_create_id = rb_intern("json_create");
810
+ oj_new_id = rb_intern("new");
786
811
  oj_read_id = rb_intern("read");
787
812
  oj_string_id = rb_intern("string");
788
813
  oj_to_hash_id = rb_intern("to_hash");
789
814
  oj_to_json_id = rb_intern("to_json");
815
+ oj_to_s_id = rb_intern("to_s");
790
816
  oj_to_sym_id = rb_intern("to_sym");
791
- oj_write_id = rb_intern("write");
817
+ oj_to_time_id = rb_intern("to_time");
792
818
  oj_tv_nsec_id = rb_intern("tv_nsec");
793
819
  oj_tv_sec_id = rb_intern("tv_sec");
794
820
  oj_tv_usec_id = rb_intern("tv_usec");
821
+ oj_write_id = rb_intern("write");
795
822
 
796
823
  oj_bag_class = rb_const_get_at(Oj, rb_intern("Bag"));
797
824
  oj_struct_class = rb_const_get(rb_cObject, rb_intern("Struct"));
798
825
  oj_time_class = rb_const_get(rb_cObject, rb_intern("Time"));
799
- oj_date_class = rb_const_get(rb_cObject, rb_intern("Date"));
826
+ oj_bigdecimal_class = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
800
827
  oj_stringio_class = rb_const_get(rb_cObject, rb_intern("StringIO"));
801
828
 
802
829
  ascii_only_sym = ID2SYM(rb_intern("ascii_only")); rb_gc_register_address(&ascii_only_sym);
@@ -821,6 +848,51 @@ void Init_oj() {
821
848
  oj_cache_new(&oj_class_cache);
822
849
  oj_cache_new(&oj_attr_cache);
823
850
 
851
+ odd = odds;
852
+ // Rational
853
+ idp = odd->attrs;
854
+ odd->clas = rb_const_get(rb_cObject, rb_intern("Rational"));
855
+ odd->create_obj = rb_cObject;
856
+ odd->create_op = rb_intern("Rational");
857
+ odd->attr_cnt = 2;
858
+ *idp++ = rb_intern("numerator");
859
+ *idp++ = rb_intern("denominator");
860
+ *idp++ = 0;
861
+ // Date
862
+ odd++;
863
+ idp = odd->attrs;
864
+ odd->clas = rb_const_get(rb_cObject, rb_intern("Date"));
865
+ odd->create_obj = odd->clas;
866
+ odd->create_op = oj_new_id;
867
+ odd->attr_cnt = 4;
868
+ *idp++ = rb_intern("year");
869
+ *idp++ = rb_intern("month");
870
+ *idp++ = rb_intern("day");
871
+ *idp++ = rb_intern("start");
872
+ *idp++ = 0;
873
+ // DateTime
874
+ odd++;
875
+ idp = odd->attrs;
876
+ odd->clas = rb_const_get(rb_cObject, rb_intern("DateTime"));
877
+ odd->create_obj = odd->clas;
878
+ odd->create_op = oj_new_id;
879
+ odd->attr_cnt = 8;
880
+ *idp++ = rb_intern("year");
881
+ *idp++ = rb_intern("month");
882
+ *idp++ = rb_intern("day");
883
+ *idp++ = rb_intern("hour");
884
+ *idp++ = rb_intern("min");
885
+ *idp++ = rb_intern("sec");
886
+ *idp++ = rb_intern("offset");
887
+ *idp++ = rb_intern("start");
888
+ *idp++ = 0;
889
+ odd++;
890
+ // The end. bump up the size of odds if a new class is added.
891
+ odd->clas = Qundef;
892
+
893
+ #ifdef SAFE_CACHE
894
+ pthread_mutex_init(&oj_cache_mutex, 0);
895
+ #endif
824
896
  oj_init_doc();
825
897
  }
826
898
 
@@ -46,6 +46,7 @@ extern "C" {
46
46
  #endif
47
47
 
48
48
  #include "stdint.h"
49
+ #include <pthread.h> // for SAFE_CACHE
49
50
 
50
51
  #include "cache.h"
51
52
 
@@ -64,6 +65,8 @@ enum st_retval {ST_CONTINUE = 0, ST_STOP = 1, ST_DELETE = 2, ST_CHECK};
64
65
 
65
66
  #define raise_error(msg, xml, current) _oj_raise_error(msg, xml, current, __FILE__, __LINE__)
66
67
 
68
+ #define MAX_ODD_ARGS 10
69
+
67
70
  typedef enum {
68
71
  Yes = 'y',
69
72
  No = 'n',
@@ -101,6 +104,14 @@ typedef struct _Options {
101
104
  DumpOpts dump_opts;
102
105
  } *Options;
103
106
 
107
+ typedef struct _Odd {
108
+ VALUE clas; // Ruby class
109
+ VALUE create_obj;
110
+ ID create_op;
111
+ int attr_cnt;
112
+ ID attrs[MAX_ODD_ARGS]; // 0 terminated attr IDs
113
+ } *Odd;
114
+
104
115
  enum {
105
116
  STR_VAL = 0x00,
106
117
  COL_VAL = 0x01,
@@ -133,6 +144,8 @@ extern void _oj_raise_error(const char *msg, const char *xml, const char *curren
133
144
 
134
145
  extern void oj_init_doc(void);
135
146
 
147
+ extern Odd oj_get_odd(VALUE clas);
148
+
136
149
  extern VALUE Oj;
137
150
  extern struct _Options oj_default_options;
138
151
  #if HAS_ENCODING_SUPPORT
@@ -140,7 +153,7 @@ extern rb_encoding *oj_utf8_encoding;
140
153
  #endif
141
154
 
142
155
  extern VALUE oj_bag_class;
143
- extern VALUE oj_date_class;
156
+ extern VALUE oj_bigdecimal_class;
144
157
  extern VALUE oj_doc_class;
145
158
  extern VALUE oj_stringio_class;
146
159
  extern VALUE oj_struct_class;
@@ -151,10 +164,13 @@ extern VALUE oj_slash_string;
151
164
  extern ID oj_as_json_id;
152
165
  extern ID oj_instance_variables_id;
153
166
  extern ID oj_json_create_id;
167
+ extern ID oj_new_id;
154
168
  extern ID oj_string_id;
155
169
  extern ID oj_to_hash_id;
156
170
  extern ID oj_to_json_id;
171
+ extern ID oj_to_s_id;
157
172
  extern ID oj_to_sym_id;
173
+ extern ID oj_to_time_id;
158
174
  extern ID oj_tv_nsec_id;
159
175
  extern ID oj_tv_sec_id;
160
176
  extern ID oj_tv_usec_id;
@@ -162,6 +178,8 @@ extern ID oj_tv_usec_id;
162
178
  extern Cache oj_class_cache;
163
179
  extern Cache oj_attr_cache;
164
180
 
181
+ extern pthread_mutex_t oj_cache_mutex;
182
+
165
183
  #if defined(__cplusplus)
166
184
  #if 0
167
185
  { /* satisfy cc-mode */
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '1.2.9'
4
+ VERSION = '1.2.10'
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,18 @@
1
+
2
+ $: << File.join(File.dirname(__FILE__), "../lib")
3
+ $: << File.join(File.dirname(__FILE__), "../ext")
4
+
5
+ require 'oj'
6
+ require 'bigdecimal'
7
+
8
+ stuff = [
9
+ BigDecimal.new('10'),
10
+ Date.today,
11
+ Time.now,
12
+ DateTime.now
13
+ ]
14
+
15
+ puts Oj.dump(stuff, :mode => :strict)
16
+ puts Oj.dump(stuff, :mode => :compat)
17
+ puts Oj.dump(stuff, :mode => :object)
18
+
@@ -15,19 +15,6 @@ opts = OptionParser.new
15
15
  opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
16
16
  files = opts.parse(ARGV)
17
17
 
18
- class Foo
19
- def initialize()
20
- @x = true
21
- @y = 58
22
- end
23
- def to_json()
24
- %{{"x":#{@x},"y":#{@y}}}
25
- end
26
- def to_hash()
27
- { 'x' => @x, 'y' => @y }
28
- end
29
- end
30
-
31
18
  iter = 100000
32
19
  s = %{
33
20
  { "class": "Foo::Bar",
@@ -36,41 +23,36 @@ s = %{
36
23
  }
37
24
  }
38
25
 
39
- obj = Oj.load(s)
40
- obj["foo"] = Foo.new()
41
-
42
- Oj.default_options = { :indent => 0, :effort => :internal }
43
-
44
- puts
45
-
46
26
  start = Time.now
47
27
  iter.times do
48
28
  Oj.load(s)
49
29
  end
50
- 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]
30
+ oj_dt = Time.now - start
31
+ puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/msec" % [iter, oj_dt, iter/oj_dt/1000.0]
52
32
 
53
33
  start = Time.now
54
34
  iter.times do
55
35
  Yajl::Parser.parse(s)
56
36
  end
57
- 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]
37
+ yajl_dt = Time.now - start
38
+ puts "%d Yajl::Parser.parse()s in %0.3f seconds or %0.1f parses/msec" % [iter, yajl_dt, iter/yajl_dt/1000.0]
59
39
 
60
- puts
40
+ puts "Oj is %0.1f times faster than YAJL at parsing." % [yajl_dt / oj_dt]
61
41
 
42
+
43
+ obj = Oj.load(s)
62
44
  start = Time.now
63
45
  iter.times do
64
46
  Oj.dump(obj)
65
47
  end
66
- 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]
48
+ oj_dt = Time.now - start
49
+ puts "%d Oj.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter, oj_dt, iter/oj_dt/1000.0]
68
50
 
69
51
  start = Time.now
70
52
  iter.times do
71
53
  Yajl::Encoder.encode(obj)
72
54
  end
73
- 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]
55
+ yajl_dt = Time.now - start
56
+ puts "%d Yajl::Encoder.encode()s in %0.3f seconds or %0.1f encodes/msec" % [iter, yajl_dt, iter/yajl_dt/1000.0]
75
57
 
76
- puts
58
+ puts "Oj is %0.1f times faster than YAJL at dumping." % [yajl_dt / oj_dt]
@@ -6,6 +6,8 @@ $: << File.join(File.dirname(__FILE__), "../ext")
6
6
 
7
7
  require 'test/unit'
8
8
  require 'stringio'
9
+ require 'date'
10
+ require 'bigdecimal'
9
11
  require 'oj'
10
12
 
11
13
  $ruby = RUBY_DESCRIPTION.split(' ')[0]
@@ -210,6 +212,7 @@ class Juice < ::Test::Unit::TestCase
210
212
  def test_symbol_strict
211
213
  begin
212
214
  json = Oj.dump(:abc, :mode => :strict)
215
+ assert(false)
213
216
  rescue Exception => e
214
217
  assert(true)
215
218
  end
@@ -234,6 +237,7 @@ class Juice < ::Test::Unit::TestCase
234
237
  t = Time.local(2012, 1, 5, 23, 58, 7)
235
238
  begin
236
239
  json = Oj.dump(t, :mode => :strict)
240
+ assert(false)
237
241
  rescue Exception => e
238
242
  assert(true)
239
243
  end
@@ -254,10 +258,11 @@ class Juice < ::Test::Unit::TestCase
254
258
  dump_and_load(t, false)
255
259
  end
256
260
 
257
- # Class
261
+ # Class
258
262
  def test_class_strict
259
263
  begin
260
264
  json = Oj.dump(Juice, :mode => :strict)
265
+ assert(false)
261
266
  rescue Exception => e
262
267
  assert(true)
263
268
  end
@@ -275,7 +280,7 @@ class Juice < ::Test::Unit::TestCase
275
280
  dump_and_load(Juice, false)
276
281
  end
277
282
 
278
- # Hash
283
+ # Hash
279
284
  def test_hash
280
285
  Oj.default_options = { :mode => :strict }
281
286
  dump_and_load({}, false)
@@ -285,6 +290,7 @@ class Juice < ::Test::Unit::TestCase
285
290
  def test_non_str_hash_strict
286
291
  begin
287
292
  json = Oj.dump({ 1 => true, 0 => false }, :mode => :strict)
293
+ assert(false)
288
294
  rescue Exception => e
289
295
  assert(true)
290
296
  end
@@ -292,6 +298,7 @@ class Juice < ::Test::Unit::TestCase
292
298
  def test_non_str_hash_null
293
299
  begin
294
300
  json = Oj.dump({ 1 => true, 0 => false }, :mode => :null)
301
+ assert(false)
295
302
  rescue Exception => e
296
303
  assert(true)
297
304
  end
@@ -299,6 +306,7 @@ class Juice < ::Test::Unit::TestCase
299
306
  def test_non_str_hash_compat
300
307
  begin
301
308
  json = Oj.dump({ 1 => true, 0 => false }, :mode => :compat)
309
+ assert(false)
302
310
  rescue Exception => e
303
311
  assert(e.message.include?('Fixnum'))
304
312
  assert(true)
@@ -326,6 +334,7 @@ class Juice < ::Test::Unit::TestCase
326
334
  obj = Jeez.new(true, 58)
327
335
  begin
328
336
  json = Oj.dump(obj, :mode => :strict)
337
+ assert(false)
329
338
  rescue Exception => e
330
339
  assert(true)
331
340
  end
@@ -371,6 +380,7 @@ class Juice < ::Test::Unit::TestCase
371
380
  obj = Jazz.new(true, 58)
372
381
  begin
373
382
  json = Oj.dump(obj, :mode => :strict)
383
+ assert(false)
374
384
  rescue Exception => e
375
385
  assert(true)
376
386
  end
@@ -406,6 +416,7 @@ class Juice < ::Test::Unit::TestCase
406
416
  obj = Orange.new(true, 58)
407
417
  begin
408
418
  json = Oj.dump(obj, :mode => :strict)
419
+ assert(false)
409
420
  rescue Exception => e
410
421
  assert(true)
411
422
  end
@@ -457,6 +468,7 @@ class Juice < ::Test::Unit::TestCase
457
468
  obj = Jam.new(true, 58)
458
469
  begin
459
470
  json = Oj.dump(obj, :mode => :strict)
471
+ assert(false)
460
472
  rescue Exception => e
461
473
  assert(true)
462
474
  end
@@ -496,6 +508,7 @@ class Juice < ::Test::Unit::TestCase
496
508
  err = nil
497
509
  begin
498
510
  raise StandardError.new('A Message')
511
+ assert(false)
499
512
  rescue Exception => e
500
513
  err = e
501
514
  end
@@ -515,6 +528,7 @@ class Juice < ::Test::Unit::TestCase
515
528
  def test_range_strict
516
529
  begin
517
530
  json = Oj.dump(1..7, :mode => :strict)
531
+ assert(false)
518
532
  rescue Exception => e
519
533
  assert(true)
520
534
  end
@@ -547,6 +561,112 @@ class Juice < ::Test::Unit::TestCase
547
561
  end
548
562
  end
549
563
 
564
+ # BigNum
565
+ def test_bignum_strict
566
+ json = Oj.dump(7 ** 55, :mode => :strict)
567
+ assert_equal('30226801971775055948247051683954096612865741943', json)
568
+ end
569
+ def test_bignum_null
570
+ json = Oj.dump(7 ** 55, :mode => :null)
571
+ assert_equal('30226801971775055948247051683954096612865741943', json)
572
+ end
573
+ def test_bignum_compat
574
+ json = Oj.dump(7 ** 55, :mode => :compat)
575
+ b = Oj.load(json, :mode => :strict)
576
+ assert_equal(30226801971775055948247051683954096612865741943, b)
577
+ end
578
+ def test_bignum_object
579
+ dump_and_load(7 ** 55, false)
580
+ end
581
+
582
+ # BigDecimal
583
+ def test_bigdecimal_strict
584
+ begin
585
+ json = Oj.dump(BigDecimal.new('3.14159265358979323846'), :mode => :strict)
586
+ assert(false)
587
+ rescue Exception => e
588
+ assert(true)
589
+ end
590
+ end
591
+ def test_bigdecimal_null
592
+ json = Oj.dump(BigDecimal.new('3.14159265358979323846'), :mode => :null)
593
+ assert_equal('null', json)
594
+ end
595
+ def test_bigdecimal_compat
596
+ orig = BigDecimal.new('3.14159265358979323846')
597
+ json = Oj.dump(orig, :mode => :compat)
598
+ bg = Oj.load(json, :mode => :compat)
599
+ assert_equal(orig, bg)
600
+ end
601
+ def test_bigdecimal_object
602
+ dump_and_load(BigDecimal.new('3.14159265358979323846'), false)
603
+ # Infinity is the same for Float and BigDecimal
604
+ json = Oj.dump(BigDecimal.new('Infinity'), :mode => :compat)
605
+ assert_equal('Infinity', json)
606
+ json = Oj.dump(BigDecimal.new('-Infinity'), :mode => :compat)
607
+ assert_equal('-Infinity', json)
608
+ end
609
+
610
+ # Date
611
+ def test_date_strict
612
+ begin
613
+ json = Oj.dump(Date.new(2012, 6, 19), :mode => :strict)
614
+ assert(false)
615
+ rescue Exception => e
616
+ assert(true)
617
+ end
618
+ end
619
+ def test_date_null
620
+ json = Oj.dump(Date.new(2012, 6, 19), :mode => :null)
621
+ assert_equal('null', json)
622
+ end
623
+ def test_date_compat
624
+ orig = Date.new(2012, 6, 19)
625
+ json = Oj.dump(orig, :mode => :compat)
626
+ x = Oj.load(json, :mode => :compat)
627
+ # Some Rubies implement Date as data and some as a real Object. Either are
628
+ # okay for the test.
629
+ if x.is_a?(String)
630
+ assert_equal(orig.to_s, x)
631
+ else # better be a Hash
632
+ assert_equal({"year" => orig.year, "month" => orig.month, "day" => orig.day, "start" => orig.start}, x)
633
+ end
634
+ end
635
+ def test_date_object
636
+ dump_and_load(Date.new(2012, 6, 19), false)
637
+ end
638
+
639
+ # DateTime
640
+ def test_datetime_strict
641
+ begin
642
+ json = Oj.dump(DateTime.new(2012, 6, 19, 20, 19, 27), :mode => :strict)
643
+ assert(false)
644
+ rescue Exception => e
645
+ assert(true)
646
+ end
647
+ end
648
+ def test_datetime_null
649
+ json = Oj.dump(DateTime.new(2012, 6, 19, 20, 19, 27), :mode => :null)
650
+ assert_equal('null', json)
651
+ end
652
+ def test_datetime_compat
653
+ orig = DateTime.new(2012, 6, 19, 20, 19, 27)
654
+ json = Oj.dump(orig, :mode => :compat)
655
+ x = Oj.load(json, :mode => :compat)
656
+ # Some Rubies implement Date as data and some as a real Object. Either are
657
+ # okay for the test.
658
+ if x.is_a?(String)
659
+ assert_equal(orig.to_s, x)
660
+ else # better be a Hash
661
+ assert_equal({ "year" => orig.year, "month" => orig.month, "day" => orig.day,
662
+ "hour" => orig.hour, "min" => orig.min, "sec" => orig.sec,
663
+ "offset" => orig.offset, "start" => orig.start}, x)
664
+ end
665
+ end
666
+ def test_datetime_object
667
+ dump_and_load(DateTime.new(2012, 6, 19), false)
668
+ end
669
+
550
670
  # autodefine Oj::Bag
551
671
  def test_bag
552
672
  json = %{{