oj 1.0.2 → 1.0.3

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,9 +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.0.2
27
+ ### Release 1.0.3
28
28
 
29
- - Added RSTRING_NOT_MODIFIED for Rubinius optimization.
29
+ - Added :symbol_keys option to convert String hash keys into Symbols.
30
+
31
+ - The load() method now supports IO Objects as input as well as Strings.
30
32
 
31
33
  ## <a name="description">Description</a>
32
34
 
@@ -452,7 +452,11 @@ read_obj(ParseInfo pi) {
452
452
  }
453
453
  rb_ivar_set(obj, var_id, val);
454
454
  } else if (T_HASH == obj_type) {
455
- rb_hash_aset(obj, key, val);
455
+ if (Yes == pi->options->sym_key) {
456
+ rb_hash_aset(obj, rb_str_intern(key), val);
457
+ } else {
458
+ rb_hash_aset(obj, key, val);
459
+ }
456
460
  if ((CompatMode == pi->options->mode || ObjectMode == pi->options->mode) &&
457
461
  0 == json_class_name &&
458
462
  0 != ks && 'j' == *ks && 0 == strcmp("json_class", ks) &&
@@ -49,6 +49,8 @@ ID oj_as_json_id;
49
49
  ID oj_at_id;
50
50
  ID oj_instance_variables_id;
51
51
  ID oj_json_create_id;
52
+ ID oj_read_id;
53
+ ID oj_string_id;
52
54
  ID oj_to_hash_id;
53
55
  ID oj_to_json_id;
54
56
  ID oj_to_sym_id;
@@ -57,6 +59,8 @@ ID oj_tv_sec_id;
57
59
  ID oj_tv_usec_id;
58
60
 
59
61
  VALUE oj_bag_class;
62
+ VALUE oj_date_class;
63
+ VALUE oj_stringio_class;
60
64
  VALUE oj_struct_class;
61
65
  VALUE oj_time_class;
62
66
 
@@ -71,6 +75,7 @@ static VALUE mode_sym;
71
75
  static VALUE null_sym;
72
76
  static VALUE object_sym;
73
77
  static VALUE strict_sym;
78
+ static VALUE symbol_keys_sym;
74
79
 
75
80
  Cache oj_class_cache = 0;
76
81
  Cache oj_attr_cache = 0;
@@ -80,6 +85,7 @@ struct _Options oj_default_options = {
80
85
  0, // indent
81
86
  No, // circular
82
87
  Yes, // auto_define
88
+ No, // sym_key
83
89
  ObjectMode, // mode
84
90
  };
85
91
 
@@ -90,6 +96,7 @@ struct _Options oj_default_options = {
90
96
  * - encoding: [String] character encoding for the JSON file
91
97
  * - circular: [true|false|nil] support circular references while dumping
92
98
  * - auto_define: [true|false|nil] automatically define classes if they do not exist
99
+ * - symbol_keys: [true|false|nil] use symbols instead of strings for hash keys
93
100
  * - mode: [:object|:strict|:compat|:null] load and dump modes to use for JSON
94
101
  * @return [Hash] all current option settings.
95
102
  */
@@ -102,6 +109,7 @@ get_def_opts(VALUE self) {
102
109
  rb_hash_aset(opts, indent_sym, INT2FIX(oj_default_options.indent));
103
110
  rb_hash_aset(opts, circular_sym, (Yes == oj_default_options.circular) ? Qtrue : ((No == oj_default_options.circular) ? Qfalse : Qnil));
104
111
  rb_hash_aset(opts, auto_define_sym, (Yes == oj_default_options.auto_define) ? Qtrue : ((No == oj_default_options.auto_define) ? Qfalse : Qnil));
112
+ rb_hash_aset(opts, symbol_keys_sym, (Yes == oj_default_options.sym_key) ? Qtrue : ((No == oj_default_options.sym_key) ? Qfalse : Qnil));
105
113
  switch (oj_default_options.mode) {
106
114
  case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break;
107
115
  case CompatMode: rb_hash_aset(opts, mode_sym, compat_sym); break;
@@ -120,6 +128,7 @@ get_def_opts(VALUE self) {
120
128
  * @param [String] :encoding character encoding for the JSON file
121
129
  * @param [true|false|nil] :circular support circular references while dumping
122
130
  * @param [true|false|nil] :auto_define automatically define classes if they do not exist
131
+ * @param [true|false|nil] :symbol_keys convert hash keys to symbols
123
132
  * @param [:object|:strict|:compat|:null] load and dump mode to use for JSON
124
133
  * :strict raises an exception when a non-supported Object is
125
134
  * encountered. :compat attempts to extract variable values from an
@@ -134,6 +143,7 @@ set_def_opts(VALUE self, VALUE opts) {
134
143
  struct _YesNoOpt ynos[] = {
135
144
  { circular_sym, &oj_default_options.circular },
136
145
  { auto_define_sym, &oj_default_options.auto_define },
146
+ { symbol_keys_sym, &oj_default_options.sym_key },
137
147
  { Qnil, 0 }
138
148
  };
139
149
  YesNoOpt o;
@@ -194,6 +204,7 @@ parse_options(VALUE ropts, Options copts) {
194
204
  struct _YesNoOpt ynos[] = {
195
205
  { circular_sym, &copts->circular },
196
206
  { auto_define_sym, &copts->auto_define },
207
+ { symbol_keys_sym, &copts->sym_key },
197
208
  { Qnil, 0 }
198
209
  };
199
210
  YesNoOpt o;
@@ -268,13 +279,38 @@ static VALUE
268
279
  load_str(int argc, VALUE *argv, VALUE self) {
269
280
  char *json;
270
281
  size_t len;
282
+ VALUE input;
271
283
 
272
- Check_Type(*argv, T_STRING);
273
- // the json string gets modified so make a copy of it
274
- len = RSTRING_LEN(*argv) + 1;
275
- json = ALLOCA_N(char, len);
276
- strcpy(json, StringValuePtr(*argv));
277
-
284
+ if (1 > argc) {
285
+ rb_raise(rb_eArgError, "Wrong number of arguments to load().\n");
286
+ }
287
+ input = *argv;
288
+ if (rb_type(input) == T_STRING) {
289
+ // the json string gets modified so make a copy of it
290
+ len = RSTRING_LEN(*argv) + 1;
291
+ json = ALLOCA_N(char, len);
292
+ strcpy(json, StringValuePtr(*argv));
293
+ } else {
294
+ VALUE clas = rb_obj_class(input);
295
+ VALUE s;
296
+
297
+ if (oj_stringio_class == clas) {
298
+ s = rb_funcall2(input, oj_string_id, 0, 0);
299
+ len = RSTRING_LEN(s) + 1;
300
+ json = ALLOCA_N(char, len);
301
+ strcpy(json, StringValuePtr(s));
302
+
303
+ // TBD else responds to fileno
304
+
305
+ } else if (rb_respond_to(input, oj_read_id)) {
306
+ s = rb_funcall2(input, oj_read_id, 0, 0);
307
+ len = RSTRING_LEN(s) + 1;
308
+ json = ALLOCA_N(char, len);
309
+ strcpy(json, StringValuePtr(s));
310
+ } else {
311
+ rb_raise(rb_eArgError, "load() expected a String or IO Object.\n");
312
+ }
313
+ }
278
314
  return load(json, argc - 1, argv + 1, self);
279
315
  }
280
316
 
@@ -365,6 +401,10 @@ void Init_oj() {
365
401
  Oj = rb_define_module("Oj");
366
402
  keep = rb_cv_get(Oj, "@@keep"); // needed to stop GC from deleting and reusing VALUEs
367
403
 
404
+ rb_require("time");
405
+ rb_require("date");
406
+ rb_require("stringio");
407
+
368
408
  rb_define_module_function(Oj, "default_options", get_def_opts, 0);
369
409
  rb_define_module_function(Oj, "default_options=", set_def_opts, 1);
370
410
 
@@ -377,16 +417,20 @@ void Init_oj() {
377
417
  oj_at_id = rb_intern("at");
378
418
  oj_instance_variables_id = rb_intern("instance_variables");
379
419
  oj_json_create_id = rb_intern("json_create");
420
+ oj_read_id = rb_intern("read");
421
+ oj_string_id = rb_intern("string");
380
422
  oj_to_hash_id = rb_intern("to_hash");
381
423
  oj_to_json_id = rb_intern("to_json");
382
424
  oj_to_sym_id = rb_intern("to_sym");
383
425
  oj_tv_nsec_id = rb_intern("tv_nsec");
384
426
  oj_tv_sec_id = rb_intern("tv_sec");
385
427
  oj_tv_usec_id = rb_intern("tv_usec");
386
-
428
+
387
429
  oj_bag_class = rb_const_get_at(Oj, rb_intern("Bag"));
388
430
  oj_struct_class = rb_const_get(rb_cObject, rb_intern("Struct"));
389
431
  oj_time_class = rb_const_get(rb_cObject, rb_intern("Time"));
432
+ oj_date_class = rb_const_get(rb_cObject, rb_intern("Date"));
433
+ oj_stringio_class = rb_const_get(rb_cObject, rb_intern("StringIO"));
390
434
 
391
435
  auto_define_sym = ID2SYM(rb_intern("auto_define")); rb_ary_push(keep, auto_define_sym);
392
436
  circular_sym = ID2SYM(rb_intern("circular")); rb_ary_push(keep, circular_sym);
@@ -394,6 +438,7 @@ void Init_oj() {
394
438
  encoding_sym = ID2SYM(rb_intern("encoding")); rb_ary_push(keep, encoding_sym);
395
439
  indent_sym = ID2SYM(rb_intern("indent")); rb_ary_push(keep, indent_sym);
396
440
  mode_sym = ID2SYM(rb_intern("mode")); rb_ary_push(keep, mode_sym);
441
+ symbol_keys_sym = ID2SYM(rb_intern("symbol_keys")); rb_ary_push(keep, symbol_keys_sym);
397
442
  null_sym = ID2SYM(rb_intern("null")); rb_ary_push(keep, null_sym);
398
443
  object_sym = ID2SYM(rb_intern("object")); rb_ary_push(keep, object_sym);
399
444
  strict_sym = ID2SYM(rb_intern("strict")); rb_ary_push(keep, strict_sym);
@@ -84,6 +84,7 @@ typedef struct _Options {
84
84
  int indent; // indention for dump, default 2
85
85
  char circular; // YesNo
86
86
  char auto_define; // YesNo
87
+ char sym_key; // YesNo
87
88
  char mode; // Mode
88
89
  } *Options;
89
90
 
@@ -99,7 +100,9 @@ extern VALUE Oj;
99
100
  extern struct _Options oj_default_options;
100
101
 
101
102
  extern VALUE oj_bag_class;
103
+ extern VALUE oj_date_class;
102
104
  extern VALUE oj_doc_class;
105
+ extern VALUE oj_stringio_class;
103
106
  extern VALUE oj_struct_class;
104
107
  extern VALUE oj_time_class;
105
108
 
@@ -109,6 +112,7 @@ extern ID oj_as_json_id;
109
112
  extern ID oj_at_id;
110
113
  extern ID oj_instance_variables_id;
111
114
  extern ID oj_json_create_id;
115
+ extern ID oj_string_id;
112
116
  extern ID oj_to_hash_id;
113
117
  extern ID oj_to_json_id;
114
118
  extern ID oj_to_sym_id;
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '1.0.2'
4
+ VERSION = '1.0.3'
5
5
  end
@@ -54,7 +54,7 @@ class Perf
54
54
  end
55
55
  end
56
56
  puts
57
- puts "Comparison Matrix\n(performance factor, 2.0 row is means twice as fast as column)"
57
+ puts "Comparison Matrix\n(performance factor, 2.0 means row is twice as fast as column)"
58
58
  puts ([' ' * width] + iva.map { |i| "%*s" % [width, i.title] }).join(' ')
59
59
  puts (['-' * width] + iva.map { |i| '-' * width }).join(' ')
60
60
  iva.each do |i|
@@ -5,6 +5,7 @@ $: << File.join(File.dirname(__FILE__), "../lib")
5
5
  $: << File.join(File.dirname(__FILE__), "../ext")
6
6
 
7
7
  require 'test/unit'
8
+ require 'stringio'
8
9
  require 'oj'
9
10
 
10
11
  def hash_eql(h1, h2)
@@ -70,6 +71,7 @@ class Juice < ::Test::Unit::TestCase
70
71
  :indent=>0,
71
72
  :circular=>false,
72
73
  :auto_define=>true,
74
+ :symbol_keys=>false,
73
75
  :mode=>:object}, opts)
74
76
  end
75
77
 
@@ -79,12 +81,14 @@ class Juice < ::Test::Unit::TestCase
79
81
  :indent=>0,
80
82
  :circular=>false,
81
83
  :auto_define=>true,
84
+ :symbol_keys=>false,
82
85
  :mode=>:object}
83
86
  o2 = {
84
87
  :encoding=>"UTF-8",
85
88
  :indent=>4,
86
89
  :circular=>true,
87
90
  :auto_define=>false,
91
+ :symbol_keys=>false,
88
92
  :mode=>:compat}
89
93
  o3 = { :indent => 4 }
90
94
  Oj.default_options = o2
@@ -471,6 +475,30 @@ class Juice < ::Test::Unit::TestCase
471
475
  assert_equal(h['b'].__id__, obj.__id__)
472
476
  end
473
477
 
478
+ # Stream IO
479
+ def test_string_io
480
+ json = %{{
481
+ "x":true,
482
+ "y":58,
483
+ "z": [1,2,3]
484
+ }
485
+ }
486
+ input = StringIO.new(json)
487
+ obj = Oj.load(input, :mode => :strict)
488
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
489
+ end
490
+
491
+ def test_symbol_keys
492
+ json = %{{
493
+ "x":true,
494
+ "y":58,
495
+ "z": [1,2,3]
496
+ }
497
+ }
498
+ obj = Oj.load(json, :mode => :strict, :symbol_keys => true)
499
+ assert_equal({ :x => true, :y => 58, :z => [1, 2, 3]}, obj)
500
+ end
501
+
474
502
  def dump_and_load(obj, trace=false)
475
503
  json = Oj.dump(obj, :indent => 2)
476
504
  puts json if trace
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.0.2
4
+ version: 1.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: