oj 3.9.2 → 3.10.5
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 +6 -2
- data/ext/oj/dump.c +10 -13
- 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 +2 -1
- data/ext/oj/oj.c +47 -28
- data/ext/oj/oj.h +4 -2
- data/ext/oj/parse.c +26 -10
- data/ext/oj/parse.h +1 -0
- data/ext/oj/rails.c +37 -4
- data/ext/oj/sparse.c +2 -1
- data/ext/oj/wab.c +9 -9
- data/lib/oj/version.rb +1 -1
- data/pages/Rails.md +60 -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 +21 -11
- data/test/baz.rb +16 -0
- data/test/foo.rb +39 -8
- data/test/json_gem/json_common_interface_test.rb +2 -2
- 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
|
}
|
@@ -786,13 +795,13 @@ oj_num_as_value(NumInfo ni) {
|
|
786
795
|
}
|
787
796
|
} else {
|
788
797
|
// All these machinations are to get rounding to work better.
|
789
|
-
long double
|
798
|
+
long double ld = (long double)ni->i * (long double)ni->div + (long double)ni->num;
|
790
799
|
int x = (int)((int64_t)ni->exp - ni->di);
|
791
800
|
|
792
801
|
// Rounding sometimes cuts off the last digit even if there are only
|
793
802
|
// 15 digits. This attempts to fix those few cases where this
|
794
803
|
// occurs.
|
795
|
-
if ((long double)INT64_MAX >
|
804
|
+
if ((long double)INT64_MAX > ld && (int64_t)ld != (ni->i * ni->div + ni->num)) {
|
796
805
|
volatile VALUE bd = rb_str_new(ni->str, ni->len);
|
797
806
|
|
798
807
|
rnum = rb_rescue2(parse_big_decimal, bd, rescue_big_decimal, bd, rb_eException, 0);
|
@@ -800,16 +809,23 @@ oj_num_as_value(NumInfo ni) {
|
|
800
809
|
rnum = rb_funcall(rnum, rb_intern("to_f"), 0);
|
801
810
|
}
|
802
811
|
} else {
|
803
|
-
d
|
812
|
+
double d;
|
813
|
+
|
814
|
+
ld = roundl(ld);
|
815
|
+
// You would expect that staying with a long double would be
|
816
|
+
// more accurate but it fails to match what Ruby generates so
|
817
|
+
// drop down to a double.
|
804
818
|
if (0 < x) {
|
805
|
-
d
|
819
|
+
d = (double)ld * pow(10.0, x);
|
806
820
|
} else if (0 > x) {
|
807
|
-
d
|
821
|
+
d = (double)ld / pow(10.0, -x);
|
822
|
+
} else {
|
823
|
+
d = (double)ld;
|
808
824
|
}
|
809
825
|
if (ni->neg) {
|
810
826
|
d = -d;
|
811
827
|
}
|
812
|
-
rnum = rb_float_new(
|
828
|
+
rnum = rb_float_new(d);
|
813
829
|
}
|
814
830
|
}
|
815
831
|
}
|
@@ -1050,7 +1066,7 @@ CLEANUP:
|
|
1050
1066
|
}
|
1051
1067
|
args[0] = msg;
|
1052
1068
|
if (pi->err.clas == oj_parse_error_class) {
|
1053
|
-
// The error was an Oj::ParseError so change to a JSON::
|
1069
|
+
// The error was an Oj::ParseError so change to a JSON::ParserError.
|
1054
1070
|
pi->err.clas = oj_json_parser_error_class;
|
1055
1071
|
}
|
1056
1072
|
rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
|
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 {
|
@@ -1012,6 +1015,7 @@ rails_encode(int argc, VALUE *argv, VALUE self) {
|
|
1012
1015
|
static VALUE
|
1013
1016
|
rails_use_standard_json_time_format(VALUE self, VALUE state) {
|
1014
1017
|
if (Qtrue == state || Qfalse == state) {
|
1018
|
+
// no change needed
|
1015
1019
|
} else if (Qnil == state) {
|
1016
1020
|
state = Qfalse;
|
1017
1021
|
} else {
|
@@ -1023,6 +1027,11 @@ rails_use_standard_json_time_format(VALUE self, VALUE state) {
|
|
1023
1027
|
return state;
|
1024
1028
|
}
|
1025
1029
|
|
1030
|
+
static VALUE
|
1031
|
+
rails_use_standard_json_time_format_get(VALUE self) {
|
1032
|
+
return xml_time ? Qtrue : Qfalse;
|
1033
|
+
}
|
1034
|
+
|
1026
1035
|
static VALUE
|
1027
1036
|
rails_escape_html_entities_in_json(VALUE self, VALUE state) {
|
1028
1037
|
rb_iv_set(self, "@escape_html_entities_in_json", state);
|
@@ -1031,10 +1040,16 @@ rails_escape_html_entities_in_json(VALUE self, VALUE state) {
|
|
1031
1040
|
return state;
|
1032
1041
|
}
|
1033
1042
|
|
1043
|
+
static VALUE
|
1044
|
+
rails_escape_html_entities_in_json_get(VALUE self) {
|
1045
|
+
return escape_html ? Qtrue : Qfalse;
|
1046
|
+
}
|
1047
|
+
|
1034
1048
|
static VALUE
|
1035
1049
|
rails_time_precision(VALUE self, VALUE prec) {
|
1036
1050
|
rb_iv_set(self, "@time_precision", prec);
|
1037
1051
|
oj_default_options.sec_prec = NUM2INT(prec);
|
1052
|
+
oj_default_options.sec_prec_set = true;
|
1038
1053
|
|
1039
1054
|
return prec;
|
1040
1055
|
}
|
@@ -1053,7 +1068,12 @@ rails_set_encoder(VALUE self) {
|
|
1053
1068
|
VALUE encoding;
|
1054
1069
|
VALUE pv;
|
1055
1070
|
VALUE verbose;
|
1071
|
+
VALUE enc = resolve_classpath("ActiveSupport::JSON::Encoding");
|
1056
1072
|
|
1073
|
+
if (Qnil != enc) {
|
1074
|
+
escape_html = Qtrue == rb_iv_get(self, "@escape_html_entities_in_json");
|
1075
|
+
xml_time = Qtrue == rb_iv_get(enc, "@use_standard_json_time_format");
|
1076
|
+
}
|
1057
1077
|
if (rb_const_defined_at(rb_cObject, rb_intern("ActiveSupport"))) {
|
1058
1078
|
active = rb_const_get_at(rb_cObject, rb_intern("ActiveSupport"));
|
1059
1079
|
} else {
|
@@ -1070,14 +1090,19 @@ rails_set_encoder(VALUE self) {
|
|
1070
1090
|
rb_gv_set("$VERBOSE", Qfalse);
|
1071
1091
|
rb_undef_method(encoding, "use_standard_json_time_format=");
|
1072
1092
|
rb_define_module_function(encoding, "use_standard_json_time_format=", rails_use_standard_json_time_format, 1);
|
1093
|
+
rb_undef_method(encoding, "use_standard_json_time_format");
|
1094
|
+
rb_define_module_function(encoding, "use_standard_json_time_format", rails_use_standard_json_time_format_get, 0);
|
1073
1095
|
|
1074
1096
|
pv = rb_iv_get(encoding, "@escape_html_entities_in_json");
|
1075
1097
|
escape_html = Qtrue == pv;
|
1076
1098
|
rb_undef_method(encoding, "escape_html_entities_in_json=");
|
1077
1099
|
rb_define_module_function(encoding, "escape_html_entities_in_json=", rails_escape_html_entities_in_json, 1);
|
1100
|
+
rb_undef_method(encoding, "escape_html_entities_in_json");
|
1101
|
+
rb_define_module_function(encoding, "escape_html_entities_in_json", rails_escape_html_entities_in_json_get, 0);
|
1078
1102
|
|
1079
1103
|
pv = rb_iv_get(encoding, "@time_precision");
|
1080
1104
|
oj_default_options.sec_prec = NUM2INT(pv);
|
1105
|
+
oj_default_options.sec_prec_set = true;
|
1081
1106
|
rb_undef_method(encoding, "time_precision=");
|
1082
1107
|
rb_define_module_function(encoding, "time_precision=", rails_time_precision, 1);
|
1083
1108
|
rb_gv_set("$VERBOSE", verbose);
|
@@ -1285,7 +1310,8 @@ dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
1285
1310
|
}
|
1286
1311
|
|
1287
1312
|
static int
|
1288
|
-
hash_cb(VALUE key, VALUE value,
|
1313
|
+
hash_cb(VALUE key, VALUE value, VALUE ov) {
|
1314
|
+
Out out = (Out)ov;
|
1289
1315
|
int depth = out->depth;
|
1290
1316
|
long size;
|
1291
1317
|
int rtype = rb_type(key);
|
@@ -1398,14 +1424,17 @@ dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1398
1424
|
|
1399
1425
|
static void
|
1400
1426
|
dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
1427
|
+
VALUE clas;
|
1428
|
+
|
1401
1429
|
if (oj_code_dump(oj_compat_codes, obj, depth, out)) {
|
1402
1430
|
out->argc = 0;
|
1403
1431
|
return;
|
1404
1432
|
}
|
1433
|
+
clas = rb_obj_class(obj);
|
1405
1434
|
if (as_ok) {
|
1406
1435
|
ROpt ro;
|
1407
1436
|
|
1408
|
-
if (NULL != (ro = oj_rails_get_opt(out->ropts,
|
1437
|
+
if (NULL != (ro = oj_rails_get_opt(out->ropts, clas)) && ro->on) {
|
1409
1438
|
ro->dump(obj, depth, out, as_ok);
|
1410
1439
|
} else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
|
1411
1440
|
oj_dump_raw_json(obj, depth, out);
|
@@ -1413,6 +1442,8 @@ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1413
1442
|
dump_as_json(obj, depth, out, true);
|
1414
1443
|
} else if (rb_respond_to(obj, oj_to_hash_id)) {
|
1415
1444
|
dump_to_hash(obj, depth, out);
|
1445
|
+
} else if (oj_bigdecimal_class == clas) {
|
1446
|
+
dump_bigdecimal(obj, depth, out, false);
|
1416
1447
|
} else {
|
1417
1448
|
oj_dump_obj_to_s(obj, out);
|
1418
1449
|
}
|
@@ -1421,6 +1452,8 @@ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1421
1452
|
} else if (rb_respond_to(obj, oj_to_hash_id)) {
|
1422
1453
|
// Always attempt to_hash.
|
1423
1454
|
dump_to_hash(obj, depth, out);
|
1455
|
+
} else if (oj_bigdecimal_class == clas) {
|
1456
|
+
dump_bigdecimal(obj, depth, out, false);
|
1424
1457
|
} else {
|
1425
1458
|
oj_dump_obj_to_s(obj, out);
|
1426
1459
|
}
|
@@ -1439,7 +1472,7 @@ static DumpFunc rails_funcs[] = {
|
|
1439
1472
|
dump_hash, // RUBY_T_HASH = 0x08,
|
1440
1473
|
dump_obj, // RUBY_T_STRUCT = 0x09,
|
1441
1474
|
oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
|
1442
|
-
|
1475
|
+
dump_as_string, // RUBY_T_FILE = 0x0b,
|
1443
1476
|
dump_obj, // RUBY_T_DATA = 0x0c,
|
1444
1477
|
NULL, // RUBY_T_MATCH = 0x0d,
|
1445
1478
|
// 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
|
}
|
@@ -899,7 +900,7 @@ CLEANUP:
|
|
899
900
|
VALUE args[] = { oj_encode(rb_str_new2(pi->err.msg)) };
|
900
901
|
|
901
902
|
if (pi->err.clas == oj_parse_error_class) {
|
902
|
-
// The error was an Oj::ParseError so change to a JSON::
|
903
|
+
// The error was an Oj::ParseError so change to a JSON::ParserError.
|
903
904
|
pi->err.clas = oj_json_parser_error_class;
|
904
905
|
}
|
905
906
|
rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
|
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,47 @@ 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.is_a?(Hash) && options[:json]
|
93
|
+
obj = options.delete(:json)
|
94
|
+
obj = Oj.dump(obj, :mode => :rails) unless obj.is_a?(String)
|
95
|
+
options[:text] = obj
|
96
|
+
response.content_type ||= Mime::JSON
|
97
|
+
end
|
98
|
+
super
|
99
|
+
end
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
Usage:
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
class MyController < ApplicationController
|
107
|
+
prepend OjJsonEncoder
|
108
|
+
def index
|
109
|
+
render :json => { :hello => 'world' }
|
110
|
+
end
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
### Older Ruby Version Support (Pre 2.3.0)
|
115
|
+
|
116
|
+
If you are using an older version of Ruby, you can pin `oj` to an earlier version in your Gemfile:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
gem 'oj', '3.7.12'
|
120
|
+
```
|
82
121
|
|
83
122
|
### Notes:
|
84
123
|
|
@@ -87,8 +126,8 @@ Oj::Rails.set_decoder() method replaces that method with the Oj equivalent.
|
|
87
126
|
significant digits which can be either 16 or 17 depending on the value.
|
88
127
|
|
89
128
|
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
|
129
|
+
an example, a non-String object that has a `to_s()` method will become the
|
130
|
+
return value of the `to_s()` method in the output without checking to see if
|
92
131
|
that has already been used. This could occur is a mix of String and Symbols
|
93
132
|
are used as keys or if a other non-String objects such as Numerics are mixed
|
94
133
|
with numbers as Strings.
|