oj 2.0.4 → 2.0.5
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 +5 -6
- data/ext/oj/dump.c +59 -17
- data/ext/oj/oj.c +17 -5
- data/ext/oj/oj.h +3 -0
- data/lib/oj/version.rb +1 -1
- data/test/tests.rb +16 -9
- metadata +2 -2
data/README.md
CHANGED
@@ -32,15 +32,14 @@ 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 2.0.
|
35
|
+
### Release 2.0.5
|
36
36
|
|
37
|
-
-
|
37
|
+
- DateTimes are now output the same in compat mode for both 1.8.7 and 1.9.3 even though they are implemented differently in each Ruby.
|
38
38
|
|
39
|
-
-
|
39
|
+
- Objects implemented as data structs can now change the encoding by implemented either to_json(), as_json(), or to_hash().
|
40
40
|
|
41
|
-
- Added
|
42
|
-
|
43
|
-
course. See the section on the <a href="#proper_use">proper use of Oj</a> in a public exposure.
|
41
|
+
- Added an option to allow BigDecimals to be dumped as either a string or as a number. There was no agreement on which
|
42
|
+
was the best or correct so both are possible with the correct option setting.
|
44
43
|
|
45
44
|
## <a name="description">Description</a>
|
46
45
|
|
data/ext/oj/dump.c
CHANGED
@@ -93,7 +93,7 @@ static void dump_ruby_time(VALUE obj, Out out);
|
|
93
93
|
static void dump_xml_time(VALUE obj, Out out);
|
94
94
|
static void dump_data_strict(VALUE obj, Out out);
|
95
95
|
static void dump_data_null(VALUE obj, Out out);
|
96
|
-
static void dump_data_comp(VALUE obj, Out out);
|
96
|
+
static void dump_data_comp(VALUE obj, int depth, Out out);
|
97
97
|
static void dump_data_obj(VALUE obj, int depth, Out out);
|
98
98
|
static void dump_obj_comp(VALUE obj, int depth, Out out);
|
99
99
|
static void dump_obj_obj(VALUE obj, int depth, Out out);
|
@@ -1116,21 +1116,51 @@ dump_data_null(VALUE obj, Out out) {
|
|
1116
1116
|
}
|
1117
1117
|
|
1118
1118
|
static void
|
1119
|
-
dump_data_comp(VALUE obj, Out out) {
|
1120
|
-
|
1119
|
+
dump_data_comp(VALUE obj, int depth, Out out) {
|
1120
|
+
if (rb_respond_to(obj, oj_to_hash_id)) {
|
1121
|
+
VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
|
1122
|
+
|
1123
|
+
if (T_HASH != rb_type(h)) {
|
1124
|
+
rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
|
1125
|
+
}
|
1126
|
+
dump_hash(h, depth, out->opts->mode, out);
|
1127
|
+
} else if (rb_respond_to(obj, oj_as_json_id)) {
|
1128
|
+
dump_val(rb_funcall(obj, oj_as_json_id, 0), depth, out);
|
1129
|
+
} else if (rb_respond_to(obj, oj_to_json_id)) {
|
1130
|
+
VALUE rs = rb_funcall(obj, oj_to_json_id, 0);
|
1131
|
+
const char *s = StringValuePtr(rs);
|
1132
|
+
int len = (int)RSTRING_LEN(rs);
|
1121
1133
|
|
1122
|
-
|
1123
|
-
|
1124
|
-
case RubyTime: dump_ruby_time(obj, out); break;
|
1125
|
-
case XmlTime: dump_xml_time(obj, out); break;
|
1126
|
-
case UnixTime:
|
1127
|
-
default: dump_time(obj, out); break;
|
1134
|
+
if (out->end - out->cur <= len + 1) {
|
1135
|
+
grow(out, len);
|
1128
1136
|
}
|
1137
|
+
memcpy(out->cur, s, len);
|
1138
|
+
out->cur += len;
|
1139
|
+
*out->cur = '\0';
|
1129
1140
|
} else {
|
1130
|
-
VALUE
|
1141
|
+
VALUE clas = rb_obj_class(obj);
|
1131
1142
|
|
1132
|
-
|
1133
|
-
|
1143
|
+
if (rb_cTime == clas) {
|
1144
|
+
switch (out->opts->time_format) {
|
1145
|
+
case RubyTime: dump_ruby_time(obj, out); break;
|
1146
|
+
case XmlTime: dump_xml_time(obj, out); break;
|
1147
|
+
case UnixTime:
|
1148
|
+
default: dump_time(obj, out); break;
|
1149
|
+
}
|
1150
|
+
} else if (oj_bigdecimal_class == clas) {
|
1151
|
+
VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1152
|
+
|
1153
|
+
if (Yes == out->opts->bigdec_as_num) {
|
1154
|
+
dump_raw(StringValuePtr(rstr), RSTRING_LEN(rstr), out);
|
1155
|
+
} else {
|
1156
|
+
dump_cstr(StringValuePtr(rstr), RSTRING_LEN(rstr), 0, 0, out);
|
1157
|
+
}
|
1158
|
+
} else {
|
1159
|
+
VALUE rstr;
|
1160
|
+
|
1161
|
+
rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1162
|
+
dump_cstr(StringValuePtr(rstr), RSTRING_LEN(rstr), 0, 0, out);
|
1163
|
+
}
|
1134
1164
|
}
|
1135
1165
|
}
|
1136
1166
|
|
@@ -1157,8 +1187,12 @@ dump_data_obj(VALUE obj, int depth, Out out) {
|
|
1157
1187
|
if (0 == odd) {
|
1158
1188
|
if (oj_bigdecimal_class == clas) {
|
1159
1189
|
VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1160
|
-
|
1161
|
-
|
1190
|
+
|
1191
|
+
if (Yes == out->opts->bigdec_as_num) {
|
1192
|
+
dump_raw(StringValuePtr(rstr), RSTRING_LEN(rstr), out);
|
1193
|
+
} else {
|
1194
|
+
dump_cstr(StringValuePtr(rstr), RSTRING_LEN(rstr), 0, 0, out);
|
1195
|
+
}
|
1162
1196
|
} else {
|
1163
1197
|
dump_nil(out);
|
1164
1198
|
}
|
@@ -1184,18 +1218,26 @@ dump_obj_comp(VALUE obj, int depth, Out out) {
|
|
1184
1218
|
const char *s = StringValuePtr(rs);
|
1185
1219
|
int len = (int)RSTRING_LEN(rs);
|
1186
1220
|
|
1187
|
-
if (out->end - out->cur <= len) {
|
1221
|
+
if (out->end - out->cur <= len + 1) {
|
1188
1222
|
grow(out, len);
|
1189
1223
|
}
|
1190
1224
|
memcpy(out->cur, s, len);
|
1191
1225
|
out->cur += len;
|
1226
|
+
*out->cur = '\0';
|
1192
1227
|
} else {
|
1193
1228
|
VALUE clas = rb_obj_class(obj);
|
1194
1229
|
|
1195
1230
|
if (oj_bigdecimal_class == clas) {
|
1196
1231
|
VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1197
1232
|
|
1198
|
-
|
1233
|
+
if (Yes == out->opts->bigdec_as_num) {
|
1234
|
+
dump_raw(StringValuePtr(rstr), RSTRING_LEN(rstr), out);
|
1235
|
+
} else {
|
1236
|
+
dump_cstr(StringValuePtr(rstr), RSTRING_LEN(rstr), 0, 0, out);
|
1237
|
+
}
|
1238
|
+
} else if (oj_datetime_class == clas || oj_date_class == clas) {
|
1239
|
+
VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1240
|
+
|
1199
1241
|
dump_cstr(StringValuePtr(rstr), RSTRING_LEN(rstr), 0, 0, out);
|
1200
1242
|
} else {
|
1201
1243
|
Odd odd = oj_get_odd(clas);
|
@@ -1572,7 +1614,7 @@ dump_val(VALUE obj, int depth, Out out) {
|
|
1572
1614
|
switch (out->opts->mode) {
|
1573
1615
|
case StrictMode: dump_data_strict(obj, out); break;
|
1574
1616
|
case NullMode: dump_data_null(obj, out); break;
|
1575
|
-
case CompatMode: dump_data_comp(obj, out);
|
1617
|
+
case CompatMode: dump_data_comp(obj, depth, out);break;
|
1576
1618
|
case ObjectMode:
|
1577
1619
|
default: dump_data_obj(obj, depth, out); break;
|
1578
1620
|
}
|
data/ext/oj/oj.c
CHANGED
@@ -72,8 +72,10 @@ ID oj_utc_offset_id;
|
|
72
72
|
ID oj_write_id;
|
73
73
|
|
74
74
|
VALUE oj_bag_class;
|
75
|
-
VALUE oj_parse_error_class;
|
76
75
|
VALUE oj_bigdecimal_class;
|
76
|
+
VALUE oj_date_class;
|
77
|
+
VALUE oj_datetime_class;
|
78
|
+
VALUE oj_parse_error_class;
|
77
79
|
VALUE oj_stringio_class;
|
78
80
|
VALUE oj_struct_class;
|
79
81
|
VALUE oj_time_class;
|
@@ -82,6 +84,7 @@ VALUE oj_slash_string;
|
|
82
84
|
|
83
85
|
static VALUE ascii_only_sym;
|
84
86
|
static VALUE auto_define_sym;
|
87
|
+
static VALUE bigdecimal_as_decimal_sym;
|
85
88
|
static VALUE circular_sym;
|
86
89
|
static VALUE compat_sym;
|
87
90
|
static VALUE create_id_sym;
|
@@ -127,6 +130,7 @@ struct _Options oj_default_options = {
|
|
127
130
|
No, // ascii_only
|
128
131
|
ObjectMode, // mode
|
129
132
|
UnixTime, // time_format
|
133
|
+
Yes, // bigdec_as_num
|
130
134
|
json_class, // create_id
|
131
135
|
65536, // max_stack
|
132
136
|
9, // sec_prec
|
@@ -157,6 +161,7 @@ oj_get_odd(VALUE clas) {
|
|
157
161
|
* - symbol_keys: [true|false|nil] use symbols instead of strings for hash keys
|
158
162
|
* - mode: [:object|:strict|:compat|:null] load and dump modes to use for JSON
|
159
163
|
* - time_format: [:unix|:xmlschema|:ruby] time format when dumping in :compat mode
|
164
|
+
* - bigdecimal_as_decimal: [true|false|nil] dump BigDecimal as a decimal number or as a String
|
160
165
|
* - create_id: [String|nil] create id for json compatible object encoding, default is 'json_create'
|
161
166
|
* - max_stack: [Fixnum|nil] maximum json size to allocate on the stack, default is 65536
|
162
167
|
* - second_precision: [Fixnum|nil] number of digits after the decimal when dumping the seconds portion of time
|
@@ -173,6 +178,7 @@ get_def_opts(VALUE self) {
|
|
173
178
|
rb_hash_aset(opts, auto_define_sym, (Yes == oj_default_options.auto_define) ? Qtrue : ((No == oj_default_options.auto_define) ? Qfalse : Qnil));
|
174
179
|
rb_hash_aset(opts, ascii_only_sym, (Yes == oj_default_options.ascii_only) ? Qtrue : ((No == oj_default_options.ascii_only) ? Qfalse : Qnil));
|
175
180
|
rb_hash_aset(opts, symbol_keys_sym, (Yes == oj_default_options.sym_key) ? Qtrue : ((No == oj_default_options.sym_key) ? Qfalse : Qnil));
|
181
|
+
rb_hash_aset(opts, bigdecimal_as_decimal_sym, (Yes == oj_default_options.bigdec_as_num) ? Qtrue : ((No == oj_default_options.bigdec_as_num) ? Qfalse : Qnil));
|
176
182
|
switch (oj_default_options.mode) {
|
177
183
|
case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break;
|
178
184
|
case CompatMode: rb_hash_aset(opts, mode_sym, compat_sym); break;
|
@@ -200,6 +206,7 @@ get_def_opts(VALUE self) {
|
|
200
206
|
* @param [true|false|nil] :auto_define automatically define classes if they do not exist
|
201
207
|
* @param [true|false|nil] :symbol_keys convert hash keys to symbols
|
202
208
|
* @param [true|false|nil] :ascii_only encode all high-bit characters as escaped sequences if true
|
209
|
+
* @param [true|false|nil] :bigdecimal_as_decimal dump BigDecimal as a decimal number or as a String
|
203
210
|
* @param [:object|:strict|:compat|:null] load and dump mode to use for JSON
|
204
211
|
* :strict raises an exception when a non-supported Object is
|
205
212
|
* encountered. :compat attempts to extract variable values from an
|
@@ -224,6 +231,7 @@ set_def_opts(VALUE self, VALUE opts) {
|
|
224
231
|
{ auto_define_sym, &oj_default_options.auto_define },
|
225
232
|
{ symbol_keys_sym, &oj_default_options.sym_key },
|
226
233
|
{ ascii_only_sym, &oj_default_options.ascii_only },
|
234
|
+
{ bigdecimal_as_decimal_sym, &oj_default_options.bigdec_as_num },
|
227
235
|
{ Qnil, 0 }
|
228
236
|
};
|
229
237
|
YesNoOpt o;
|
@@ -328,6 +336,7 @@ parse_options(VALUE ropts, Options copts) {
|
|
328
336
|
{ auto_define_sym, &copts->auto_define },
|
329
337
|
{ symbol_keys_sym, &copts->sym_key },
|
330
338
|
{ ascii_only_sym, &copts->ascii_only },
|
339
|
+
{ bigdecimal_as_decimal_sym, &copts->bigdec_as_num },
|
331
340
|
{ Qnil, 0 }
|
332
341
|
};
|
333
342
|
YesNoOpt o;
|
@@ -1043,14 +1052,17 @@ void Init_oj() {
|
|
1043
1052
|
oj_write_id = rb_intern("write");
|
1044
1053
|
|
1045
1054
|
oj_bag_class = rb_const_get_at(Oj, rb_intern("Bag"));
|
1055
|
+
oj_bigdecimal_class = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
|
1056
|
+
oj_date_class = rb_const_get(rb_cObject, rb_intern("Date"));
|
1057
|
+
oj_datetime_class = rb_const_get(rb_cObject, rb_intern("DateTime"));
|
1046
1058
|
oj_parse_error_class = rb_const_get_at(Oj, rb_intern("ParseError"));
|
1059
|
+
oj_stringio_class = rb_const_get(rb_cObject, rb_intern("StringIO"));
|
1047
1060
|
oj_struct_class = rb_const_get(rb_cObject, rb_intern("Struct"));
|
1048
1061
|
oj_time_class = rb_const_get(rb_cObject, rb_intern("Time"));
|
1049
|
-
oj_bigdecimal_class = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
|
1050
|
-
oj_stringio_class = rb_const_get(rb_cObject, rb_intern("StringIO"));
|
1051
1062
|
|
1052
1063
|
ascii_only_sym = ID2SYM(rb_intern("ascii_only")); rb_gc_register_address(&ascii_only_sym);
|
1053
1064
|
auto_define_sym = ID2SYM(rb_intern("auto_define")); rb_gc_register_address(&auto_define_sym);
|
1065
|
+
bigdecimal_as_decimal_sym = ID2SYM(rb_intern("bigdecimal_as_decimal"));rb_gc_register_address(&bigdecimal_as_decimal_sym);
|
1054
1066
|
circular_sym = ID2SYM(rb_intern("circular")); rb_gc_register_address(&circular_sym);
|
1055
1067
|
compat_sym = ID2SYM(rb_intern("compat")); rb_gc_register_address(&compat_sym);
|
1056
1068
|
create_id_sym = ID2SYM(rb_intern("create_id")); rb_gc_register_address(&create_id_sym);
|
@@ -1090,7 +1102,7 @@ void Init_oj() {
|
|
1090
1102
|
// Date
|
1091
1103
|
odd++;
|
1092
1104
|
idp = odd->attrs;
|
1093
|
-
odd->clas =
|
1105
|
+
odd->clas = oj_date_class;
|
1094
1106
|
odd->create_obj = odd->clas;
|
1095
1107
|
odd->create_op = oj_new_id;
|
1096
1108
|
odd->attr_cnt = 4;
|
@@ -1102,7 +1114,7 @@ void Init_oj() {
|
|
1102
1114
|
// DateTime
|
1103
1115
|
odd++;
|
1104
1116
|
idp = odd->attrs;
|
1105
|
-
odd->clas =
|
1117
|
+
odd->clas = oj_datetime_class;
|
1106
1118
|
odd->create_obj = odd->clas;
|
1107
1119
|
odd->create_op = oj_new_id;
|
1108
1120
|
odd->attr_cnt = 8;
|
data/ext/oj/oj.h
CHANGED
@@ -108,6 +108,7 @@ typedef struct _Options {
|
|
108
108
|
char ascii_only; // YesNo
|
109
109
|
char mode; // Mode
|
110
110
|
char time_format; // TimeFormat
|
111
|
+
char bigdec_as_num; // YesNo
|
111
112
|
const char *create_id; // 0 or string
|
112
113
|
size_t max_stack; // max size to allocate on the stack
|
113
114
|
int sec_prec; // second precision when dumping time
|
@@ -166,6 +167,8 @@ extern rb_encoding *oj_utf8_encoding;
|
|
166
167
|
|
167
168
|
extern VALUE oj_bag_class;
|
168
169
|
extern VALUE oj_bigdecimal_class;
|
170
|
+
extern VALUE oj_date_class;
|
171
|
+
extern VALUE oj_datetime_class;
|
169
172
|
extern VALUE oj_doc_class;
|
170
173
|
extern VALUE oj_parse_error_class;
|
171
174
|
extern VALUE oj_stringio_class;
|
data/lib/oj/version.rb
CHANGED
data/test/tests.rb
CHANGED
@@ -117,6 +117,7 @@ class Juice < ::Test::Unit::TestCase
|
|
117
117
|
:ascii_only=>false,
|
118
118
|
:mode=>:object,
|
119
119
|
:time_format=>:unix,
|
120
|
+
:bigdecimal_as_decimal=>true,
|
120
121
|
:max_stack=>65536,
|
121
122
|
:create_id=>'json_class'}, opts)
|
122
123
|
end
|
@@ -131,6 +132,7 @@ class Juice < ::Test::Unit::TestCase
|
|
131
132
|
:ascii_only=>false,
|
132
133
|
:mode=>:object,
|
133
134
|
:time_format=>:unix,
|
135
|
+
:bigdecimal_as_decimal=>true,
|
134
136
|
:max_stack=>65536,
|
135
137
|
:create_id=>'json_class'}
|
136
138
|
o2 = {
|
@@ -142,6 +144,7 @@ class Juice < ::Test::Unit::TestCase
|
|
142
144
|
:ascii_only=>true,
|
143
145
|
:mode=>:compat,
|
144
146
|
:time_format=>:ruby,
|
147
|
+
:bigdecimal_as_decimal=>false,
|
145
148
|
:max_stack=>4000,
|
146
149
|
:create_id=>nil}
|
147
150
|
o3 = { :indent => 4 }
|
@@ -732,14 +735,24 @@ class Juice < ::Test::Unit::TestCase
|
|
732
735
|
end
|
733
736
|
def test_bigdecimal_compat
|
734
737
|
orig = BigDecimal.new('80.51')
|
735
|
-
json = Oj.dump(orig, :mode => :compat)
|
738
|
+
json = Oj.dump(orig, :mode => :compat, :bigdecimal_as_decimal => false)
|
736
739
|
bg = Oj.load(json, :mode => :compat)
|
737
740
|
assert_equal(orig.to_s, bg)
|
738
741
|
orig = BigDecimal.new('3.14159265358979323846')
|
739
|
-
json = Oj.dump(orig, :mode => :compat)
|
742
|
+
json = Oj.dump(orig, :mode => :compat, :bigdecimal_as_decimal => false)
|
740
743
|
bg = Oj.load(json, :mode => :compat)
|
741
744
|
assert_equal(orig.to_s, bg)
|
742
745
|
end
|
746
|
+
def test_bigdecimal_compat_to_json
|
747
|
+
orig = BigDecimal.new('80.51')
|
748
|
+
BigDecimal.send(:define_method, :to_json) do
|
749
|
+
%{"this is big"}
|
750
|
+
end
|
751
|
+
json = Oj.dump(orig, :mode => :compat)
|
752
|
+
bg = Oj.load(json, :mode => :compat)
|
753
|
+
assert_equal("this is big", bg)
|
754
|
+
BigDecimal.send(:remove_method, :to_json) # cleanup
|
755
|
+
end
|
743
756
|
def test_bigdecimal_object
|
744
757
|
mode = Oj.default_options[:mode]
|
745
758
|
Oj.default_options = {:mode => :object}
|
@@ -800,13 +813,7 @@ class Juice < ::Test::Unit::TestCase
|
|
800
813
|
x = Oj.load(json, :mode => :compat)
|
801
814
|
# Some Rubies implement Date as data and some as a real Object. Either are
|
802
815
|
# okay for the test.
|
803
|
-
|
804
|
-
assert_equal(orig.to_s, x)
|
805
|
-
else # better be a Hash
|
806
|
-
assert_equal({ "year" => orig.year, "month" => orig.month, "day" => orig.day,
|
807
|
-
"hour" => orig.hour, "min" => orig.min, "sec" => orig.sec,
|
808
|
-
"offset" => orig.offset, "start" => orig.start}, x)
|
809
|
-
end
|
816
|
+
assert_equal(orig.to_s, x)
|
810
817
|
end
|
811
818
|
def test_datetime_object
|
812
819
|
dump_and_load(DateTime.new(2012, 6, 19), false)
|
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: 2.0.
|
4
|
+
version: 2.0.5
|
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: 2013-02-
|
12
|
+
date: 2013-02-16 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! 'The fastest JSON parser and object serializer. '
|
15
15
|
email: peter@ohler.com
|