oj 1.2.13 → 1.3.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.

data/README.md CHANGED
@@ -32,15 +32,9 @@ A fast JSON parser and Object marshaller as a Ruby gem.
32
32
 
33
33
  ## <a name="release">Release Notes</a>
34
34
 
35
- ### Release 1.2.13
35
+ ### Release 1.3.0
36
36
 
37
- - Fixed double free bug in Oj::Doc that showed up for larger documents.
38
-
39
- ### Release 1.2.12
40
-
41
- - Fixed GC bug in Oj::Doc, the fast parser.
42
-
43
- - Serialization of Exceptions in Ruby 1.8.7 now includes message and backtrace.
37
+ - Added an option to control the time format output when in :compat mode.
44
38
 
45
39
  ## <a name="description">Description</a>
46
40
 
@@ -82,6 +82,8 @@ static int hash_cb_compat(VALUE key, VALUE value, Out out);
82
82
  static int hash_cb_object(VALUE key, VALUE value, Out out);
83
83
  static void dump_hash(VALUE obj, int depth, int mode, Out out);
84
84
  static void dump_time(VALUE obj, Out out);
85
+ static void dump_ruby_time(VALUE obj, Out out);
86
+ static void dump_xml_time(VALUE obj, Out out);
85
87
  static void dump_data_comp(VALUE obj, Out out);
86
88
  static void dump_data_obj(VALUE obj, int depth, Out out);
87
89
  static void dump_obj_comp(VALUE obj, int depth, Out out);
@@ -945,12 +947,63 @@ dump_time(VALUE obj, Out out) {
945
947
  *out->cur = '\0';
946
948
  }
947
949
 
950
+ static void
951
+ dump_ruby_time(VALUE obj, Out out) {
952
+ VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
953
+
954
+ dump_cstr(StringValuePtr(rstr), RSTRING_LEN(rstr), 0, 0, out);
955
+ }
956
+
957
+ static void
958
+ dump_xml_time(VALUE obj, Out out) {
959
+ char buf[64];
960
+ struct tm *tm;
961
+ #if HAS_RB_TIME_TIMESPEC
962
+ struct timespec ts = rb_time_timespec(obj);
963
+ time_t sec = ts.tv_sec;
964
+ long nsec = ts.tv_nsec;
965
+ #else
966
+ time_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
967
+ #if HAS_NANO_TIME
968
+ long nsec = NUM2LONG(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
969
+ #else
970
+ long nsec = NUM2LONG(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
971
+ #endif
972
+ #endif
973
+ int tzhour, tzmin;
974
+ char tzsign = '+';
975
+
976
+ if (out->end - out->cur <= 36) {
977
+ grow(out, 36);
978
+ }
979
+ // 2012-01-05T23:58:07.123456000+09:00
980
+ tm = localtime(&sec);
981
+ if (0 > tm->tm_gmtoff) {
982
+ tzsign = '-';
983
+ tzhour = (int)(tm->tm_gmtoff / -3600);
984
+ tzmin = (int)(tm->tm_gmtoff / -60) - (tzhour * 60);
985
+ } else {
986
+ tzhour = (int)(tm->tm_gmtoff / 3600);
987
+ tzmin = (int)(tm->tm_gmtoff / 60) - (tzhour * 60);
988
+ }
989
+ sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d",
990
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
991
+ tm->tm_hour, tm->tm_min, tm->tm_sec, nsec,
992
+ tzsign, tzhour, tzmin);
993
+ dump_cstr(buf, 35, 0, 0, out);
994
+ }
995
+
948
996
  static void
949
997
  dump_data_comp(VALUE obj, Out out) {
950
998
  VALUE clas = rb_obj_class(obj);
951
999
 
952
1000
  if (rb_cTime == clas) {
953
- dump_time(obj, out);
1001
+ switch (out->opts->time_format) {
1002
+ case RubyTime: dump_ruby_time(obj, out); break;
1003
+ case XmlTime: dump_xml_time(obj, out); break;
1004
+ case UnixTime:
1005
+ default: dump_time(obj, out); break;
1006
+ }
954
1007
  } else {
955
1008
  VALUE rstr;
956
1009
 
@@ -29,7 +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
+ #include <pthread.h>
33
33
  #include <stdlib.h>
34
34
  #include <errno.h>
35
35
  #include <stdio.h>
@@ -84,8 +84,12 @@ static VALUE max_stack_sym;
84
84
  static VALUE mode_sym;
85
85
  static VALUE null_sym;
86
86
  static VALUE object_sym;
87
+ static VALUE ruby_sym;
87
88
  static VALUE strict_sym;
88
89
  static VALUE symbol_keys_sym;
90
+ static VALUE time_format_sym;
91
+ static VALUE unix_sym;
92
+ static VALUE xmlschema_sym;
89
93
 
90
94
  static VALUE array_nl_sym;
91
95
  static VALUE create_additions_sym;
@@ -114,6 +118,7 @@ struct _Options oj_default_options = {
114
118
  No, // sym_key
115
119
  No, // ascii_only
116
120
  ObjectMode, // mode
121
+ UnixTime, // time_format
117
122
  json_class, // create_id
118
123
  65536, // max_stack
119
124
  0, // dump_opts
@@ -143,6 +148,7 @@ oj_get_odd(VALUE clas) {
143
148
  * - auto_define: [true|false|nil] automatically define classes if they do not exist
144
149
  * - symbol_keys: [true|false|nil] use symbols instead of strings for hash keys
145
150
  * - mode: [:object|:strict|:compat|:null] load and dump modes to use for JSON
151
+ * - time_format: [:unix|:xmlschema|:ruby] time format when dumping in :compat mode
146
152
  * - create_id: [String|nil] create id for json compatible object encoding, default is 'json_create'
147
153
  * - max_stack: [Fixnum|nil] maximum json size to allocate on the stack, default is 65536
148
154
  * @return [Hash] all current option settings.
@@ -164,6 +170,12 @@ get_def_opts(VALUE self) {
164
170
  case ObjectMode:
165
171
  default: rb_hash_aset(opts, mode_sym, object_sym); break;
166
172
  }
173
+ switch (oj_default_options.time_format) {
174
+ case XmlTime: rb_hash_aset(opts, time_format_sym, xmlschema_sym); break;
175
+ case RubyTime: rb_hash_aset(opts, time_format_sym, ruby_sym); break;
176
+ case UnixTime:
177
+ default: rb_hash_aset(opts, time_format_sym, unix_sym); break;
178
+ }
167
179
  rb_hash_aset(opts, create_id_sym, (0 == oj_default_options.create_id) ? Qnil : rb_str_new2(oj_default_options.create_id));
168
180
 
169
181
  return opts;
@@ -186,6 +198,10 @@ get_def_opts(VALUE self) {
186
198
  * and to_json() methods and encodes variables using code internal to
187
199
  * the Oj gem. The :null mode ignores non-supported Objects and
188
200
  * replaces them with a null.
201
+ * @param [:unix|:xmlschema|:ruby] time format when dumping in :compat mode
202
+ * :unix decimal number denoting the number of seconds since 1/1/1970,
203
+ * :xmlschema date-time format taken from XML Schema as a String,
204
+ * :ruby Time.to_s formatted String
189
205
  * @param [String|nil] :create_id create id for json compatible object encoding
190
206
  * @param [Fixnum|nil] :max_stack maximum size to allocate on the stack for a JSON String
191
207
  * @return [nil]
@@ -235,6 +251,19 @@ set_def_opts(VALUE self, VALUE opts) {
235
251
  rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.\n");
236
252
  }
237
253
 
254
+ v = rb_hash_lookup(opts, time_format_sym);
255
+ if (Qnil == v) {
256
+ // ignore
257
+ } else if (unix_sym == v) {
258
+ oj_default_options.time_format = UnixTime;
259
+ } else if (xmlschema_sym == v) {
260
+ oj_default_options.time_format = XmlTime;
261
+ } else if (ruby_sym == v) {
262
+ oj_default_options.time_format = RubyTime;
263
+ } else {
264
+ rb_raise(rb_eArgError, ":time_format must be :unix, :xmlschema, or :ruby.\n");
265
+ }
266
+
238
267
  if (Qtrue == rb_funcall(opts, rb_intern("has_key?"), 1, create_id_sym)) {
239
268
  if (0 != oj_default_options.create_id) {
240
269
  if (json_class != oj_default_options.create_id) {
@@ -301,6 +330,17 @@ parse_options(VALUE ropts, Options copts) {
301
330
  rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.\n");
302
331
  }
303
332
  }
333
+ if (Qnil != (v = rb_hash_lookup(ropts, time_format_sym))) {
334
+ if (unix_sym == v) {
335
+ copts->time_format = UnixTime;
336
+ } else if (xmlschema_sym == v) {
337
+ copts->time_format = XmlTime;
338
+ } else if (ruby_sym == v) {
339
+ copts->time_format = RubyTime;
340
+ } else {
341
+ rb_raise(rb_eArgError, ":time_format must be :unix, :xmlschema, or :ruby.\n");
342
+ }
343
+ }
304
344
  for (o = ynos; 0 != o->attr; o++) {
305
345
  if (Qnil != (v = rb_hash_lookup(ropts, o->sym))) {
306
346
  if (Qtrue == v) {
@@ -850,8 +890,12 @@ void Init_oj() {
850
890
  mode_sym = ID2SYM(rb_intern("mode")); rb_gc_register_address(&mode_sym);
851
891
  null_sym = ID2SYM(rb_intern("null")); rb_gc_register_address(&null_sym);
852
892
  object_sym = ID2SYM(rb_intern("object")); rb_gc_register_address(&object_sym);
893
+ ruby_sym = ID2SYM(rb_intern("ruby")); rb_gc_register_address(&ruby_sym);
853
894
  strict_sym = ID2SYM(rb_intern("strict")); rb_gc_register_address(&strict_sym);
854
895
  symbol_keys_sym = ID2SYM(rb_intern("symbol_keys")); rb_gc_register_address(&symbol_keys_sym);
896
+ time_format_sym = ID2SYM(rb_intern("time_format")); rb_gc_register_address(&time_format_sym);
897
+ unix_sym = ID2SYM(rb_intern("unix")); rb_gc_register_address(&unix_sym);
898
+ xmlschema_sym = ID2SYM(rb_intern("xmlschema")); rb_gc_register_address(&xmlschema_sym);
855
899
 
856
900
  oj_slash_string = rb_str_new2("/"); rb_gc_register_address(&oj_slash_string);
857
901
 
@@ -80,6 +80,12 @@ typedef enum {
80
80
  CompatMode = 'c'
81
81
  } Mode;
82
82
 
83
+ typedef enum {
84
+ UnixTime = 'u',
85
+ XmlTime = 'x',
86
+ RubyTime = 'r'
87
+ } TimeFormat;
88
+
83
89
  typedef struct _DumpOpts {
84
90
  const char *indent;
85
91
  const char *before_sep;
@@ -100,6 +106,7 @@ typedef struct _Options {
100
106
  char sym_key; // YesNo
101
107
  char ascii_only; // YesNo
102
108
  char mode; // Mode
109
+ char time_format; // TimeFormat
103
110
  const char *create_id; // 0 or string
104
111
  size_t max_stack; // max size to allocate on the stack
105
112
  DumpOpts dump_opts;
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '1.2.13'
4
+ VERSION = '1.3.0'
5
5
  end
@@ -109,6 +109,7 @@ class Juice < ::Test::Unit::TestCase
109
109
  :symbol_keys=>false,
110
110
  :ascii_only=>false,
111
111
  :mode=>:object,
112
+ :time_format=>:unix,
112
113
  :max_stack=>65536,
113
114
  :create_id=>'json_class'}, opts)
114
115
  end
@@ -121,6 +122,7 @@ class Juice < ::Test::Unit::TestCase
121
122
  :symbol_keys=>false,
122
123
  :ascii_only=>false,
123
124
  :mode=>:object,
125
+ :time_format=>:unix,
124
126
  :max_stack=>65536,
125
127
  :create_id=>'json_class'}
126
128
  o2 = {
@@ -130,6 +132,7 @@ class Juice < ::Test::Unit::TestCase
130
132
  :symbol_keys=>true,
131
133
  :ascii_only=>true,
132
134
  :mode=>:compat,
135
+ :time_format=>:ruby,
133
136
  :max_stack=>4000,
134
137
  :create_id=>nil}
135
138
  o3 = { :indent => 4 }
@@ -250,10 +253,22 @@ class Juice < ::Test::Unit::TestCase
250
253
  json = Oj.dump(t, :mode => :null)
251
254
  assert_equal('null', json)
252
255
  end
253
- def test_time_compat
254
- t = Time.local(2012, 1, 5, 23, 58, 7)
256
+ def test_unix_time_compat
257
+ t = Time.xmlschema("2012-01-05T23:58:07.123456000+09:00")
258
+ #t = Time.local(2012, 1, 5, 23, 58, 7, 123456)
255
259
  json = Oj.dump(t, :mode => :compat)
256
- assert_equal(%{1325775487.000000000}, json)
260
+ assert_equal(%{1325775487.123456000}, json)
261
+ end
262
+ def test_ruby_time_compat
263
+ t = Time.xmlschema("2012-01-05T23:58:07.123456000+09:00")
264
+ json = Oj.dump(t, :mode => :compat, :time_format => :ruby)
265
+ #assert_equal(%{"2012-01-05 23:58:07 +0900"}, json)
266
+ assert_equal(%{"#{t.to_s}"}, json)
267
+ end
268
+ def test_xml_time_compat
269
+ t = Time.xmlschema("2012-01-05T23:58:07.123456000+09:00")
270
+ json = Oj.dump(t, :mode => :compat, :time_format => :xmlschema)
271
+ assert_equal(%{"2012-01-05T23:58:07.123456000+09:00"}, json)
257
272
  end
258
273
  def test_time_object
259
274
  t = Time.now()
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.2.13
4
+ version: 1.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-08 00:00:00.000000000 Z
12
+ date: 2012-07-09 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! 'The fastest JSON parser and object serializer. '
15
15
  email: peter@ohler.com