oj 3.9.0 → 3.10.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/ext/oj/compat.c +5 -5
- data/ext/oj/custom.c +7 -3
- data/ext/oj/dump.c +9 -12
- data/ext/oj/dump_compat.c +8 -10
- data/ext/oj/dump_object.c +18 -11
- data/ext/oj/dump_strict.c +6 -5
- data/ext/oj/extconf.rb +5 -0
- data/ext/oj/mimic_json.c +15 -3
- data/ext/oj/object.c +6 -2
- data/ext/oj/oj.c +47 -28
- data/ext/oj/oj.h +4 -2
- data/ext/oj/parse.c +22 -3
- data/ext/oj/parse.h +1 -0
- data/ext/oj/rails.c +38 -4
- data/ext/oj/sparse.c +5 -0
- data/ext/oj/util.c +5 -5
- data/ext/oj/wab.c +9 -9
- data/lib/oj/version.rb +1 -1
- data/pages/Rails.md +59 -21
- data/test/activesupport5/abstract_unit.rb +45 -0
- data/test/activesupport5/decoding_test.rb +68 -60
- data/test/activesupport5/encoding_test.rb +111 -96
- data/test/activesupport5/encoding_test_cases.rb +33 -25
- data/test/activesupport5/test_helper.rb +43 -21
- data/test/activesupport5/time_zone_test_helpers.rb +18 -3
- data/test/activesupport6/abstract_unit.rb +44 -0
- data/test/activesupport6/decoding_test.rb +133 -0
- data/test/activesupport6/encoding_test.rb +507 -0
- data/test/activesupport6/encoding_test_cases.rb +98 -0
- data/test/activesupport6/test_common.rb +17 -0
- data/test/activesupport6/test_helper.rb +163 -0
- data/test/activesupport6/time_zone_test_helpers.rb +39 -0
- data/test/bar.rb +8 -11
- data/test/baz.rb +16 -0
- data/test/foo.rb +39 -8
- data/test/test_compat.rb +0 -7
- data/test/test_custom.rb +25 -6
- data/test/test_integer_range.rb +1 -2
- data/test/test_object.rb +12 -3
- data/test/test_rails.rb +26 -0
- data/test/test_strict.rb +24 -1
- data/test/test_various.rb +41 -62
- data/test/tests.rb +1 -0
- metadata +23 -3
data/ext/oj/oj.h
CHANGED
@@ -149,8 +149,10 @@ typedef struct _options {
|
|
149
149
|
char allow_nan; // YEsyNo for parsing only
|
150
150
|
char trace; // YesNo
|
151
151
|
char safe; // YesNo
|
152
|
-
|
153
|
-
|
152
|
+
char sec_prec_set; // boolean (0 or 1)
|
153
|
+
char ignore_under; // YesNo - ignore attrs starting with _ if true in object and custom modes
|
154
|
+
int64_t int_range_min; // dump numbers below as string
|
155
|
+
int64_t int_range_max; // dump numbers above as string
|
154
156
|
const char *create_id; // 0 or string
|
155
157
|
size_t create_id_len; // length of create_id
|
156
158
|
int sec_prec; // second precision when dumping time
|
data/ext/oj/parse.c
CHANGED
@@ -400,6 +400,10 @@ read_num(ParseInfo pi) {
|
|
400
400
|
pi->cur++;
|
401
401
|
ni.neg = 1;
|
402
402
|
} else if ('+' == *pi->cur) {
|
403
|
+
if (StrictMode == pi->options.mode) {
|
404
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
405
|
+
return;
|
406
|
+
}
|
403
407
|
pi->cur++;
|
404
408
|
}
|
405
409
|
if ('I' == *pi->cur) {
|
@@ -446,8 +450,13 @@ read_num(ParseInfo pi) {
|
|
446
450
|
if ('.' == *pi->cur) {
|
447
451
|
pi->cur++;
|
448
452
|
// A trailing . is not a valid decimal but if encountered allow it
|
449
|
-
// except when mimicing the JSON gem.
|
450
|
-
if (CompatMode == pi->options.mode) {
|
453
|
+
// except when mimicing the JSON gem or in strict mode.
|
454
|
+
if (StrictMode == pi->options.mode || CompatMode == pi->options.mode) {
|
455
|
+
int pos = (int)(pi->cur - ni.str);
|
456
|
+
if (1 == pos || (2 == pos && ni.neg)) {
|
457
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
|
458
|
+
return;
|
459
|
+
}
|
451
460
|
if (*pi->cur < '0' || '9' < *pi->cur) {
|
452
461
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
|
453
462
|
return;
|
@@ -731,7 +740,7 @@ oj_parse2(ParseInfo pi) {
|
|
731
740
|
}
|
732
741
|
|
733
742
|
static VALUE
|
734
|
-
rescue_big_decimal(VALUE str) {
|
743
|
+
rescue_big_decimal(VALUE str, VALUE ignore) {
|
735
744
|
rb_raise(oj_parse_error_class, "Invalid value for BigDecimal()");
|
736
745
|
return Qnil;
|
737
746
|
}
|
@@ -1032,6 +1041,12 @@ CLEANUP:
|
|
1032
1041
|
if (pi->str_rx.head != oj_default_options.str_rx.head) {
|
1033
1042
|
oj_rxclass_cleanup(&pi->str_rx);
|
1034
1043
|
}
|
1044
|
+
// TBD if validate only then (Qundef == result ??)
|
1045
|
+
// if pi->err or 0 != line
|
1046
|
+
// rb_get_errinfo();??
|
1047
|
+
// rb_set_errinfo(Qnil);
|
1048
|
+
// return nil or error
|
1049
|
+
|
1035
1050
|
if (err_has(&pi->err)) {
|
1036
1051
|
rb_set_errinfo(Qnil);
|
1037
1052
|
if (Qnil != pi->err_class) {
|
@@ -1049,6 +1064,10 @@ CLEANUP:
|
|
1049
1064
|
msg = rb_str_append(msg, oj_encode(rb_str_new2(pi->json)));
|
1050
1065
|
}
|
1051
1066
|
args[0] = msg;
|
1067
|
+
if (pi->err.clas == oj_parse_error_class) {
|
1068
|
+
// The error was an Oj::ParseError so change to a JSON::ParserError.
|
1069
|
+
pi->err.clas = oj_json_parser_error_class;
|
1070
|
+
}
|
1052
1071
|
rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
|
1053
1072
|
} else {
|
1054
1073
|
oj_err_raise(&pi->err);
|
data/ext/oj/parse.h
CHANGED
@@ -80,6 +80,7 @@ extern VALUE oj_num_as_value(NumInfo ni);
|
|
80
80
|
extern void oj_set_strict_callbacks(ParseInfo pi);
|
81
81
|
extern void oj_set_object_callbacks(ParseInfo pi);
|
82
82
|
extern void oj_set_compat_callbacks(ParseInfo pi);
|
83
|
+
extern void oj_set_custom_callbacks(ParseInfo pi);
|
83
84
|
extern void oj_set_wab_callbacks(ParseInfo pi);
|
84
85
|
|
85
86
|
extern void oj_sparse2(ParseInfo pi);
|
data/ext/oj/rails.c
CHANGED
@@ -87,7 +87,8 @@ copy_opts(ROptTable src, ROptTable dest) {
|
|
87
87
|
}
|
88
88
|
|
89
89
|
static int
|
90
|
-
dump_attr_cb(ID key, VALUE value,
|
90
|
+
dump_attr_cb(ID key, VALUE value, VALUE ov) {
|
91
|
+
Out out = (Out)ov;
|
91
92
|
int depth = out->depth;
|
92
93
|
size_t size = depth * out->indent + 1;
|
93
94
|
const char *attr = rb_id2name(key);
|
@@ -214,6 +215,8 @@ dump_bigdecimal(VALUE obj, int depth, Out out, bool as_ok) {
|
|
214
215
|
|
215
216
|
if ('I' == *str || 'N' == *str || ('-' == *str && 'I' == str[1])) {
|
216
217
|
oj_dump_nil(Qnil, depth, out, false);
|
218
|
+
} else if (out->opts->int_range_max != 0 || out->opts->int_range_min != 0) {
|
219
|
+
oj_dump_cstr(str, (int)RSTRING_LEN(rstr), 0, 0, out);
|
217
220
|
} else if (Yes == out->opts->bigdec_as_num) {
|
218
221
|
oj_dump_raw(str, (int)RSTRING_LEN(rstr), out);
|
219
222
|
} else {
|
@@ -1009,9 +1012,11 @@ rails_encode(int argc, VALUE *argv, VALUE self) {
|
|
1009
1012
|
}
|
1010
1013
|
}
|
1011
1014
|
|
1015
|
+
// TBD provide a get function as well
|
1012
1016
|
static VALUE
|
1013
1017
|
rails_use_standard_json_time_format(VALUE self, VALUE state) {
|
1014
1018
|
if (Qtrue == state || Qfalse == state) {
|
1019
|
+
// no change needed
|
1015
1020
|
} else if (Qnil == state) {
|
1016
1021
|
state = Qfalse;
|
1017
1022
|
} else {
|
@@ -1023,6 +1028,11 @@ rails_use_standard_json_time_format(VALUE self, VALUE state) {
|
|
1023
1028
|
return state;
|
1024
1029
|
}
|
1025
1030
|
|
1031
|
+
static VALUE
|
1032
|
+
rails_use_standard_json_time_format_get(VALUE self) {
|
1033
|
+
return xml_time ? Qtrue : Qfalse;
|
1034
|
+
}
|
1035
|
+
|
1026
1036
|
static VALUE
|
1027
1037
|
rails_escape_html_entities_in_json(VALUE self, VALUE state) {
|
1028
1038
|
rb_iv_set(self, "@escape_html_entities_in_json", state);
|
@@ -1031,10 +1041,16 @@ rails_escape_html_entities_in_json(VALUE self, VALUE state) {
|
|
1031
1041
|
return state;
|
1032
1042
|
}
|
1033
1043
|
|
1044
|
+
static VALUE
|
1045
|
+
rails_escape_html_entities_in_json_get(VALUE self) {
|
1046
|
+
return escape_html ? Qtrue : Qfalse;
|
1047
|
+
}
|
1048
|
+
|
1034
1049
|
static VALUE
|
1035
1050
|
rails_time_precision(VALUE self, VALUE prec) {
|
1036
1051
|
rb_iv_set(self, "@time_precision", prec);
|
1037
1052
|
oj_default_options.sec_prec = NUM2INT(prec);
|
1053
|
+
oj_default_options.sec_prec_set = true;
|
1038
1054
|
|
1039
1055
|
return prec;
|
1040
1056
|
}
|
@@ -1053,7 +1069,12 @@ rails_set_encoder(VALUE self) {
|
|
1053
1069
|
VALUE encoding;
|
1054
1070
|
VALUE pv;
|
1055
1071
|
VALUE verbose;
|
1072
|
+
VALUE enc = resolve_classpath("ActiveSupport::JSON::Encoding");
|
1056
1073
|
|
1074
|
+
if (Qnil != enc) {
|
1075
|
+
escape_html = Qtrue == rb_iv_get(self, "@escape_html_entities_in_json");
|
1076
|
+
xml_time = Qtrue == rb_iv_get(enc, "@use_standard_json_time_format");
|
1077
|
+
}
|
1057
1078
|
if (rb_const_defined_at(rb_cObject, rb_intern("ActiveSupport"))) {
|
1058
1079
|
active = rb_const_get_at(rb_cObject, rb_intern("ActiveSupport"));
|
1059
1080
|
} else {
|
@@ -1070,14 +1091,19 @@ rails_set_encoder(VALUE self) {
|
|
1070
1091
|
rb_gv_set("$VERBOSE", Qfalse);
|
1071
1092
|
rb_undef_method(encoding, "use_standard_json_time_format=");
|
1072
1093
|
rb_define_module_function(encoding, "use_standard_json_time_format=", rails_use_standard_json_time_format, 1);
|
1094
|
+
rb_undef_method(encoding, "use_standard_json_time_format");
|
1095
|
+
rb_define_module_function(encoding, "use_standard_json_time_format", rails_use_standard_json_time_format_get, 0);
|
1073
1096
|
|
1074
1097
|
pv = rb_iv_get(encoding, "@escape_html_entities_in_json");
|
1075
1098
|
escape_html = Qtrue == pv;
|
1076
1099
|
rb_undef_method(encoding, "escape_html_entities_in_json=");
|
1077
1100
|
rb_define_module_function(encoding, "escape_html_entities_in_json=", rails_escape_html_entities_in_json, 1);
|
1101
|
+
rb_undef_method(encoding, "escape_html_entities_in_json");
|
1102
|
+
rb_define_module_function(encoding, "escape_html_entities_in_json", rails_escape_html_entities_in_json_get, 0);
|
1078
1103
|
|
1079
1104
|
pv = rb_iv_get(encoding, "@time_precision");
|
1080
1105
|
oj_default_options.sec_prec = NUM2INT(pv);
|
1106
|
+
oj_default_options.sec_prec_set = true;
|
1081
1107
|
rb_undef_method(encoding, "time_precision=");
|
1082
1108
|
rb_define_module_function(encoding, "time_precision=", rails_time_precision, 1);
|
1083
1109
|
rb_gv_set("$VERBOSE", verbose);
|
@@ -1285,7 +1311,8 @@ dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
1285
1311
|
}
|
1286
1312
|
|
1287
1313
|
static int
|
1288
|
-
hash_cb(VALUE key, VALUE value,
|
1314
|
+
hash_cb(VALUE key, VALUE value, VALUE ov) {
|
1315
|
+
Out out = (Out)ov;
|
1289
1316
|
int depth = out->depth;
|
1290
1317
|
long size;
|
1291
1318
|
int rtype = rb_type(key);
|
@@ -1398,14 +1425,17 @@ dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1398
1425
|
|
1399
1426
|
static void
|
1400
1427
|
dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
1428
|
+
VALUE clas;
|
1429
|
+
|
1401
1430
|
if (oj_code_dump(oj_compat_codes, obj, depth, out)) {
|
1402
1431
|
out->argc = 0;
|
1403
1432
|
return;
|
1404
1433
|
}
|
1434
|
+
clas = rb_obj_class(obj);
|
1405
1435
|
if (as_ok) {
|
1406
1436
|
ROpt ro;
|
1407
1437
|
|
1408
|
-
if (NULL != (ro = oj_rails_get_opt(out->ropts,
|
1438
|
+
if (NULL != (ro = oj_rails_get_opt(out->ropts, clas)) && ro->on) {
|
1409
1439
|
ro->dump(obj, depth, out, as_ok);
|
1410
1440
|
} else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
|
1411
1441
|
oj_dump_raw_json(obj, depth, out);
|
@@ -1413,6 +1443,8 @@ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1413
1443
|
dump_as_json(obj, depth, out, true);
|
1414
1444
|
} else if (rb_respond_to(obj, oj_to_hash_id)) {
|
1415
1445
|
dump_to_hash(obj, depth, out);
|
1446
|
+
} else if (oj_bigdecimal_class == clas) {
|
1447
|
+
dump_bigdecimal(obj, depth, out, false);
|
1416
1448
|
} else {
|
1417
1449
|
oj_dump_obj_to_s(obj, out);
|
1418
1450
|
}
|
@@ -1421,6 +1453,8 @@ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1421
1453
|
} else if (rb_respond_to(obj, oj_to_hash_id)) {
|
1422
1454
|
// Always attempt to_hash.
|
1423
1455
|
dump_to_hash(obj, depth, out);
|
1456
|
+
} else if (oj_bigdecimal_class == clas) {
|
1457
|
+
dump_bigdecimal(obj, depth, out, false);
|
1424
1458
|
} else {
|
1425
1459
|
oj_dump_obj_to_s(obj, out);
|
1426
1460
|
}
|
@@ -1439,7 +1473,7 @@ static DumpFunc rails_funcs[] = {
|
|
1439
1473
|
dump_hash, // RUBY_T_HASH = 0x08,
|
1440
1474
|
dump_obj, // RUBY_T_STRUCT = 0x09,
|
1441
1475
|
oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
|
1442
|
-
|
1476
|
+
dump_as_string, // RUBY_T_FILE = 0x0b,
|
1443
1477
|
dump_obj, // RUBY_T_DATA = 0x0c,
|
1444
1478
|
NULL, // RUBY_T_MATCH = 0x0d,
|
1445
1479
|
// Rails raises a stack error on Complex and Rational. It also corrupts
|
data/ext/oj/sparse.c
CHANGED
@@ -773,6 +773,7 @@ oj_sparse2(ParseInfo pi) {
|
|
773
773
|
first = 0;
|
774
774
|
}
|
775
775
|
start = pi->rd.pos;
|
776
|
+
// TBD break if option set to allow that
|
776
777
|
}
|
777
778
|
}
|
778
779
|
}
|
@@ -898,6 +899,10 @@ CLEANUP:
|
|
898
899
|
// idea.
|
899
900
|
VALUE args[] = { oj_encode(rb_str_new2(pi->err.msg)) };
|
900
901
|
|
902
|
+
if (pi->err.clas == oj_parse_error_class) {
|
903
|
+
// The error was an Oj::ParseError so change to a JSON::ParserError.
|
904
|
+
pi->err.clas = oj_json_parser_error_class;
|
905
|
+
}
|
901
906
|
rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
|
902
907
|
} else {
|
903
908
|
oj_err_raise(&pi->err);
|
data/ext/oj/util.c
CHANGED
@@ -110,7 +110,7 @@ sec_as_time(int64_t secs, TimeInfo ti) {
|
|
110
110
|
}
|
111
111
|
}
|
112
112
|
}
|
113
|
-
ti->year = (qc - shift) * 400 + c * 100 + qy * 4 + y;
|
113
|
+
ti->year = (int)((qc - (int64_t)shift) * 400 + c * 100 + qy * 4 + y);
|
114
114
|
if (leap) {
|
115
115
|
ms = eom_leap_secs;
|
116
116
|
} else {
|
@@ -125,12 +125,12 @@ sec_as_time(int64_t secs, TimeInfo ti) {
|
|
125
125
|
break;
|
126
126
|
}
|
127
127
|
}
|
128
|
-
ti->day = secs / 86400LL;
|
128
|
+
ti->day = (int)(secs / 86400LL);
|
129
129
|
secs = secs - (int64_t)ti->day * 86400LL;
|
130
130
|
ti->day++;
|
131
|
-
ti->hour = secs / 3600LL;
|
131
|
+
ti->hour = (int)(secs / 3600LL);
|
132
132
|
secs = secs - (int64_t)ti->hour * 3600LL;
|
133
|
-
ti->min = secs / 60LL;
|
133
|
+
ti->min = (int)(secs / 60LL);
|
134
134
|
secs = secs - (int64_t)ti->min * 60LL;
|
135
|
-
ti->sec = secs;
|
135
|
+
ti->sec = (int)secs;
|
136
136
|
}
|
data/ext/oj/wab.c
CHANGED
@@ -148,11 +148,12 @@ dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
148
148
|
}
|
149
149
|
|
150
150
|
static int
|
151
|
-
hash_cb(VALUE key, VALUE value,
|
151
|
+
hash_cb(VALUE key, VALUE value, VALUE ov) {
|
152
|
+
Out out = (Out)ov;
|
152
153
|
int depth = out->depth;
|
153
154
|
long size;
|
154
155
|
int rtype = rb_type(key);
|
155
|
-
|
156
|
+
|
156
157
|
if (rtype != T_SYMBOL) {
|
157
158
|
rb_raise(rb_eTypeError, "In :wab mode all Hash keys must be Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));
|
158
159
|
}
|
@@ -270,7 +271,7 @@ static DumpFunc wab_funcs[] = {
|
|
270
271
|
void
|
271
272
|
oj_dump_wab_val(VALUE obj, int depth, Out out) {
|
272
273
|
int type = rb_type(obj);
|
273
|
-
|
274
|
+
|
274
275
|
if (Yes == out->opts->trace) {
|
275
276
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
276
277
|
}
|
@@ -324,7 +325,7 @@ add_value(ParseInfo pi, VALUE val) {
|
|
324
325
|
static bool
|
325
326
|
uuid_check(const char *str, int len) {
|
326
327
|
int i;
|
327
|
-
|
328
|
+
|
328
329
|
for (i = 0; i < 8; i++, str++) {
|
329
330
|
if ('x' != hex_chars[*(uint8_t*)str]) {
|
330
331
|
return false;
|
@@ -380,7 +381,7 @@ time_parse(const char *s, int len) {
|
|
380
381
|
long nsecs = 0;
|
381
382
|
int i;
|
382
383
|
time_t secs;
|
383
|
-
|
384
|
+
|
384
385
|
memset(&tm, 0, sizeof(tm));
|
385
386
|
if ('-' == *s) {
|
386
387
|
s++;
|
@@ -444,7 +445,7 @@ protect_uri(VALUE rstr) {
|
|
444
445
|
static VALUE
|
445
446
|
cstr_to_rstr(const char *str, size_t len) {
|
446
447
|
volatile VALUE v = Qnil;
|
447
|
-
|
448
|
+
|
448
449
|
if (30 == len && '-' == str[4] && '-' == str[7] && 'T' == str[10] && ':' == str[13] && ':' == str[16] && '.' == str[19] && 'Z' == str[29]) {
|
449
450
|
if (Qnil != (v = time_parse(str, (int)len))) {
|
450
451
|
return v;
|
@@ -521,7 +522,7 @@ hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char
|
|
521
522
|
static void
|
522
523
|
hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
|
523
524
|
volatile VALUE rval = Qnil;
|
524
|
-
|
525
|
+
|
525
526
|
if (ni->infinity || ni->nan) {
|
526
527
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
527
528
|
}
|
@@ -551,7 +552,7 @@ start_array(ParseInfo pi) {
|
|
551
552
|
static void
|
552
553
|
array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
553
554
|
volatile VALUE rval = cstr_to_rstr(str, len);
|
554
|
-
|
555
|
+
|
555
556
|
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
556
557
|
if (Yes == pi->options.trace) {
|
557
558
|
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, rval);
|
@@ -628,4 +629,3 @@ oj_wab_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
|
628
629
|
|
629
630
|
return oj_pi_parse(argc, argv, &pi, json, len, true);
|
630
631
|
}
|
631
|
-
|
data/lib/oj/version.rb
CHANGED
data/pages/Rails.md
CHANGED
@@ -26,44 +26,44 @@ directly. If Rails mode is also desired then use the `Oj.default_options` to
|
|
26
26
|
change the default mode.
|
27
27
|
|
28
28
|
Some of the Oj options are supported as arguments to the encoder if called
|
29
|
-
from Oj::Rails.encode() but when using the Oj::Rails::Encoder class the
|
30
|
-
encode() method does not support optional arguments as required by the
|
29
|
+
from `Oj::Rails.encode()` but when using the `Oj::Rails::Encoder` class the
|
30
|
+
`encode()` method does not support optional arguments as required by the
|
31
31
|
ActiveSupport compliance guidelines. The general approach Rails takes for
|
32
32
|
configuring encoding options is to either set global values or to create a new
|
33
33
|
instance of the Encoder class and provide options in the initializer.
|
34
34
|
|
35
35
|
The globals that ActiveSupport uses for encoding are:
|
36
36
|
|
37
|
-
* ActiveSupport::JSON::Encoding.use_standard_json_time_format
|
38
|
-
* ActiveSupport::JSON::Encoding.escape_html_entities_in_json
|
39
|
-
* ActiveSupport::JSON::Encoding.time_precision
|
40
|
-
* ActiveSupport::JSON::Encoding.json_encoder
|
37
|
+
* `ActiveSupport::JSON::Encoding.use_standard_json_time_format`
|
38
|
+
* `ActiveSupport::JSON::Encoding.escape_html_entities_in_json`
|
39
|
+
* `ActiveSupport::JSON::Encoding.time_precision`
|
40
|
+
* `ActiveSupport::JSON::Encoding.json_encoder`
|
41
41
|
|
42
42
|
Those globals are aliased to also be accessed from the ActiveSupport module
|
43
|
-
directly so ActiveSupport::JSON::Encoding.time_precision can also be accessed
|
44
|
-
from ActiveSupport.time_precision
|
45
|
-
Rails after the Oj::Rails.set_encode() method is called. That also sets the
|
46
|
-
ActiveSupport.json_encoder to the Oj::Rails::Encoder class.
|
43
|
+
directly so `ActiveSupport::JSON::Encoding.time_precision` can also be accessed
|
44
|
+
from `ActiveSupport.time_precision`. Oj makes use of these globals in mimicing
|
45
|
+
Rails after the `Oj::Rails.set_encode()` method is called. That also sets the
|
46
|
+
`ActiveSupport.json_encoder` to the `Oj::Rails::Encoder` class.
|
47
47
|
|
48
|
-
Options passed into a call to to_json() are passed to the as_json()
|
48
|
+
Options passed into a call to `to_json()` are passed to the `as_json()`
|
49
49
|
methods. These are mostly ignored by Oj and simply passed on without
|
50
50
|
modifications as per the guidelines. The exception to this are the options
|
51
|
-
specific to Oj such as the
|
51
|
+
specific to Oj such as the `:circular` option which it used to detect circular
|
52
52
|
references while encoding.
|
53
53
|
|
54
54
|
By default Oj acts like the ActiveSupport encoder and honors any changes in
|
55
|
-
the as_json() methods. There are some optimized Oj encoders for some
|
56
|
-
classes. When the optimized encoder it toggled the as_json() methods will not
|
55
|
+
the `as_json()` methods. There are some optimized Oj encoders for some
|
56
|
+
classes. When the optimized encoder it toggled the `as_json()` methods will not
|
57
57
|
be called for that class but instead the optimized version will be called. The
|
58
58
|
optimized version is the same as the ActiveSupport default encoding for a
|
59
|
-
given class. The optimized versions are toggled with the optimize() and
|
60
|
-
deoptimize() methods. There is a default optimized version for every class
|
59
|
+
given class. The optimized versions are toggled with the `optimize()` and
|
60
|
+
`deoptimize()` methods. There is a default optimized version for every class
|
61
61
|
that takes the visible attributes and encodes them but that may not be the
|
62
62
|
same as what Rails uses. Trial and error is the best approach for classes not
|
63
63
|
listed here.
|
64
64
|
|
65
65
|
The classes that can be put in optimized mode and are optimized when
|
66
|
-
Oj::Rails.optimize is called with no arguments are:
|
66
|
+
`Oj::Rails.optimize` is called with no arguments are:
|
67
67
|
|
68
68
|
* Array
|
69
69
|
* BigDecimal
|
@@ -77,8 +77,46 @@ Oj::Rails.optimize is called with no arguments are:
|
|
77
77
|
* any class inheriting from ActiveRecord::Base
|
78
78
|
* any other class where all attributes should be dumped
|
79
79
|
|
80
|
-
The ActiveSupport decoder is the JSON.parse() method. Calling the
|
81
|
-
Oj::Rails.set_decoder() method replaces that method with the Oj equivalent.
|
80
|
+
The ActiveSupport decoder is the `JSON.parse()` method. Calling the
|
81
|
+
`Oj::Rails.set_decoder()` method replaces that method with the Oj equivalent.
|
82
|
+
|
83
|
+
### Usage in Rails 3
|
84
|
+
|
85
|
+
To support Rails 3 you can create a new module mixin to prepend to controllers:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
require 'oj'
|
89
|
+
|
90
|
+
module OjJsonEncoder
|
91
|
+
def render(options = nil, extra_options = {}, &block)
|
92
|
+
if options && options[:json]
|
93
|
+
obj = options.delete(:json)
|
94
|
+
options[:text] = Oj.dump(obj, :mode => :rails)
|
95
|
+
options[:content_type] = 'application/json'
|
96
|
+
end
|
97
|
+
super
|
98
|
+
end
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
102
|
+
Usage:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
class MyController < ApplicationController
|
106
|
+
prepend OjJsonEncoder
|
107
|
+
def index
|
108
|
+
render :json => { :hello => 'world' }
|
109
|
+
end
|
110
|
+
end
|
111
|
+
```
|
112
|
+
|
113
|
+
### Older Ruby Version Support (Pre 2.3.0)
|
114
|
+
|
115
|
+
If you are using an older version of Ruby, you can pin `oj` to an earlier version in your Gemfile:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
gem 'oj', '3.7.12'
|
119
|
+
```
|
82
120
|
|
83
121
|
### Notes:
|
84
122
|
|
@@ -87,8 +125,8 @@ Oj::Rails.set_decoder() method replaces that method with the Oj equivalent.
|
|
87
125
|
significant digits which can be either 16 or 17 depending on the value.
|
88
126
|
|
89
127
|
2. Optimized Hashs do not collapse keys that become the same in the output. As
|
90
|
-
an example, a non-String object that has a to_s() method will become the
|
91
|
-
return value of the to_s() method in the output without checking to see if
|
128
|
+
an example, a non-String object that has a `to_s()` method will become the
|
129
|
+
return value of the `to_s()` method in the output without checking to see if
|
92
130
|
that has already been used. This could occur is a mix of String and Symbols
|
93
131
|
are used as keys or if a other non-String objects such as Numerics are mixed
|
94
132
|
with numbers as Strings.
|