oj 3.8.1 → 3.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/ext/oj/compat.c +5 -5
- data/ext/oj/custom.c +65 -38
- 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 +6 -0
- data/ext/oj/mimic_json.c +15 -3
- data/ext/oj/object.c +8 -5
- data/ext/oj/oj.c +50 -31
- data/ext/oj/oj.h +6 -4
- data/ext/oj/parse.c +16 -3
- data/ext/oj/parse.h +1 -0
- data/ext/oj/rails.c +40 -4
- data/ext/oj/resolve.c +3 -3
- data/ext/oj/sparse.c +5 -0
- data/ext/oj/util.c +5 -5
- data/ext/oj/val_stack.c +9 -9
- data/ext/oj/val_stack.h +9 -9
- data/ext/oj/wab.c +9 -9
- data/lib/oj/version.rb +1 -1
- data/pages/Options.md +4 -0
- data/pages/Rails.md +21 -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 +42 -157
- 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 +4 -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 +22 -2
data/ext/oj/extconf.rb
CHANGED
@@ -28,6 +28,7 @@ have_func('rb_ivar_count')
|
|
28
28
|
have_func('rb_ivar_foreach')
|
29
29
|
have_func('stpcpy')
|
30
30
|
have_func('rb_data_object_wrap')
|
31
|
+
have_func('pthread_mutex_init')
|
31
32
|
|
32
33
|
dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
|
33
34
|
|
@@ -41,6 +42,11 @@ end
|
|
41
42
|
|
42
43
|
$CPPFLAGS += ' -Wall'
|
43
44
|
#puts "*** $CPPFLAGS: #{$CPPFLAGS}"
|
45
|
+
# Adding the __attribute__ flag only works with gcc compilers and even then it
|
46
|
+
# does not work to check args with varargs so just remove the check.
|
47
|
+
CONFIG['warnflags'].slice!(/ -Wsuggest-attribute=format/)
|
48
|
+
CONFIG['warnflags'].slice!(/ -Wdeclaration-after-statement/)
|
49
|
+
CONFIG['warnflags'].slice!(/ -Wmissing-noreturn/)
|
44
50
|
|
45
51
|
create_makefile(File.join(extension_name, extension_name))
|
46
52
|
|
data/ext/oj/mimic_json.c
CHANGED
@@ -199,6 +199,7 @@ mimic_dump(int argc, VALUE *argv, VALUE self) {
|
|
199
199
|
struct _out out;
|
200
200
|
struct _options copts = oj_default_options;
|
201
201
|
VALUE rstr;
|
202
|
+
VALUE active_hack[1];
|
202
203
|
|
203
204
|
copts.str_rx.head = NULL;
|
204
205
|
copts.str_rx.tail = NULL;
|
@@ -216,6 +217,7 @@ mimic_dump(int argc, VALUE *argv, VALUE self) {
|
|
216
217
|
*/
|
217
218
|
copts.dump_opts.max_depth = MAX_DEPTH; // when using dump there is no limit
|
218
219
|
out.omit_nil = copts.dump_opts.omit_nil;
|
220
|
+
|
219
221
|
if (2 <= argc) {
|
220
222
|
int limit;
|
221
223
|
|
@@ -230,7 +232,15 @@ mimic_dump(int argc, VALUE *argv, VALUE self) {
|
|
230
232
|
copts.dump_opts.max_depth = limit;
|
231
233
|
}
|
232
234
|
}
|
233
|
-
|
235
|
+
// ActiveSupport in active_support/core_ext/object/json.rb check the
|
236
|
+
// optional argument type to to_json and it the argument is a
|
237
|
+
// ::JSON::State it calls the JSON gem code otherwise it calls the active
|
238
|
+
// support encoder code. To make sure the desired branch is called a
|
239
|
+
// default ::JSON::State argument is passed in. Basically a hack to get
|
240
|
+
// around the active support hack so two wrongs make a right this time.
|
241
|
+
active_hack[0] = rb_funcall(state_class, oj_new_id, 0);
|
242
|
+
oj_dump_obj_to_json_using_params(*argv, &copts, &out, 1, active_hack);
|
243
|
+
|
234
244
|
if (0 == out.buf) {
|
235
245
|
rb_raise(rb_eNoMemError, "Not enough memory.");
|
236
246
|
}
|
@@ -690,8 +700,10 @@ static struct _options mimic_object_to_json_options = {
|
|
690
700
|
No, // allow_nan
|
691
701
|
No, // trace
|
692
702
|
No, // safe
|
693
|
-
|
694
|
-
|
703
|
+
false, // sec_prec_set
|
704
|
+
No, // ignore_under
|
705
|
+
0, // int_range_min
|
706
|
+
0, // int_range_max
|
695
707
|
oj_json_class,// create_id
|
696
708
|
10, // create_id_len
|
697
709
|
3, // sec_prec
|
data/ext/oj/object.c
CHANGED
@@ -276,7 +276,10 @@ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
|
276
276
|
if (2 == kval->klen) {
|
277
277
|
switch (kval->key[1]) {
|
278
278
|
case 't': // time as a float
|
279
|
-
{
|
279
|
+
if (0 == ni->div || 9 < ni->di) {
|
280
|
+
rb_raise(rb_eArgError, "Invalid time decimal representation.");
|
281
|
+
//parent->val = rb_time_nano_new(0, 0);
|
282
|
+
} else {
|
280
283
|
int64_t nsec = ni->num * 1000000000LL / ni->div;
|
281
284
|
|
282
285
|
if (ni->neg) {
|
@@ -407,7 +410,7 @@ oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
|
|
407
410
|
ID var_id;
|
408
411
|
ID *slot;
|
409
412
|
|
410
|
-
#
|
413
|
+
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
411
414
|
pthread_mutex_lock(&oj_cache_mutex);
|
412
415
|
#else
|
413
416
|
rb_mutex_lock(oj_cache_mutex);
|
@@ -441,7 +444,7 @@ oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
|
|
441
444
|
}
|
442
445
|
*slot = var_id;
|
443
446
|
}
|
444
|
-
#
|
447
|
+
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
445
448
|
pthread_mutex_unlock(&oj_cache_mutex);
|
446
449
|
#else
|
447
450
|
rb_mutex_unlock(oj_cache_mutex);
|
@@ -665,7 +668,7 @@ end_hash(ParseInfo pi) {
|
|
665
668
|
static void
|
666
669
|
array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
667
670
|
volatile VALUE rval = Qnil;
|
668
|
-
|
671
|
+
|
669
672
|
if (3 <= len && 0 != pi->circ_array) {
|
670
673
|
if ('i' == str[1]) {
|
671
674
|
long i = read_long(str + 2, len - 2);
|
@@ -694,7 +697,7 @@ array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
694
697
|
static void
|
695
698
|
array_append_num(ParseInfo pi, NumInfo ni) {
|
696
699
|
volatile VALUE rval = oj_num_as_value(ni);
|
697
|
-
|
700
|
+
|
698
701
|
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
699
702
|
if (Yes == pi->options.trace) {
|
700
703
|
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
data/ext/oj/oj.c
CHANGED
@@ -119,6 +119,7 @@ static VALUE float_prec_sym;
|
|
119
119
|
static VALUE float_sym;
|
120
120
|
static VALUE huge_sym;
|
121
121
|
static VALUE ignore_sym;
|
122
|
+
static VALUE ignore_under_sym;
|
122
123
|
static VALUE json_sym;
|
123
124
|
static VALUE match_string_sym;
|
124
125
|
static VALUE mode_sym;
|
@@ -149,7 +150,7 @@ static VALUE xss_safe_sym;
|
|
149
150
|
|
150
151
|
rb_encoding *oj_utf8_encoding = 0;
|
151
152
|
|
152
|
-
#
|
153
|
+
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
153
154
|
pthread_mutex_t oj_cache_mutex;
|
154
155
|
#else
|
155
156
|
VALUE oj_cache_mutex = Qnil;
|
@@ -181,8 +182,10 @@ struct _options oj_default_options = {
|
|
181
182
|
Yes, // allow_nan
|
182
183
|
No, // trace
|
183
184
|
No, // safe
|
184
|
-
|
185
|
-
|
185
|
+
false, // sec_prec_set
|
186
|
+
No, // ignore_under
|
187
|
+
0, // int_range_min
|
188
|
+
0, // int_range_max
|
186
189
|
oj_json_class, // create_id
|
187
190
|
10, // create_id_len
|
188
191
|
9, // sec_prec
|
@@ -251,6 +254,7 @@ struct _options oj_default_options = {
|
|
251
254
|
* - *:array_class* [_Class_|_nil_] Class to use instead of Array on load
|
252
255
|
* - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted
|
253
256
|
* - *:ignore* [_nil_|Array] either nil or an Array of classes to ignore when dumping
|
257
|
+
* - *:ignore_under* [Boolean] if true then attributes that start with _ are ignored when dumping in object or custom mode.
|
254
258
|
* - *:integer_range* [_Range_] Dump integers outside range as strings.
|
255
259
|
* - *:trace* [_true,_|_false_] Trace all load and dump calls, default is false (trace is off)
|
256
260
|
* - *:safe* [_true,_|_false_] Safe mimic breaks JSON mimic to be safer, default is false (safe is off)
|
@@ -286,6 +290,7 @@ get_def_opts(VALUE self) {
|
|
286
290
|
rb_hash_aset(opts, oj_trace_sym, (Yes == oj_default_options.trace) ? Qtrue : ((No == oj_default_options.trace) ? Qfalse : Qnil));
|
287
291
|
rb_hash_aset(opts, oj_safe_sym, (Yes == oj_default_options.safe) ? Qtrue : ((No == oj_default_options.safe) ? Qfalse : Qnil));
|
288
292
|
rb_hash_aset(opts, float_prec_sym, INT2FIX(oj_default_options.float_prec));
|
293
|
+
rb_hash_aset(opts, ignore_under_sym, (Yes == oj_default_options.ignore_under) ? Qtrue : ((No == oj_default_options.ignore_under) ? Qfalse : Qnil));
|
289
294
|
switch (oj_default_options.mode) {
|
290
295
|
case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break;
|
291
296
|
case CompatMode: rb_hash_aset(opts, mode_sym, compat_sym); break;
|
@@ -297,16 +302,16 @@ get_def_opts(VALUE self) {
|
|
297
302
|
default: rb_hash_aset(opts, mode_sym, object_sym); break;
|
298
303
|
}
|
299
304
|
|
300
|
-
if (oj_default_options.
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
else {
|
309
|
-
|
305
|
+
if (oj_default_options.int_range_max != 0 || oj_default_options.int_range_min != 0) {
|
306
|
+
VALUE range = rb_obj_alloc(rb_cRange);
|
307
|
+
VALUE min = LONG2FIX(oj_default_options.int_range_min);
|
308
|
+
VALUE max = LONG2FIX(oj_default_options.int_range_max);
|
309
|
+
|
310
|
+
rb_ivar_set(range, oj_begin_id, min);
|
311
|
+
rb_ivar_set(range, oj_end_id, max);
|
312
|
+
rb_hash_aset(opts, integer_range_sym, range);
|
313
|
+
} else {
|
314
|
+
rb_hash_aset(opts, integer_range_sym, Qnil);
|
310
315
|
}
|
311
316
|
switch (oj_default_options.escape_mode) {
|
312
317
|
case NLEsc: rb_hash_aset(opts, escape_mode_sym, newline_sym); break;
|
@@ -329,7 +334,7 @@ get_def_opts(VALUE self) {
|
|
329
334
|
case AutoDec:
|
330
335
|
default: rb_hash_aset(opts, bigdecimal_load_sym, auto_sym); break;
|
331
336
|
}
|
332
|
-
rb_hash_aset(opts, create_id_sym, (
|
337
|
+
rb_hash_aset(opts, create_id_sym, (NULL == oj_default_options.create_id) ? Qnil : rb_str_new2(oj_default_options.create_id));
|
333
338
|
rb_hash_aset(opts, oj_space_sym, (0 == oj_default_options.dump_opts.after_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.after_sep));
|
334
339
|
rb_hash_aset(opts, oj_space_before_sym, (0 == oj_default_options.dump_opts.before_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.before_sep));
|
335
340
|
rb_hash_aset(opts, oj_object_nl_sym, (0 == oj_default_options.dump_opts.hash_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.hash_nl));
|
@@ -398,6 +403,7 @@ get_def_opts(VALUE self) {
|
|
398
403
|
* - *:array_class* [_Class_|_nil_] Class to use instead of Array on load.
|
399
404
|
* - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted.
|
400
405
|
* - *:ignore* [_nil_|Array] either nil or an Array of classes to ignore when dumping
|
406
|
+
* - *:ignore_under* [_Boolean_] if true then attributes that start with _ are ignored when dumping in object or custom mode.
|
401
407
|
* - *:integer_range* [_Range_] Dump integers outside range as strings.
|
402
408
|
* - *:trace* [_Boolean_] turn trace on or off.
|
403
409
|
* - *:safe* [_Boolean_] turn safe mimic on or off.
|
@@ -431,6 +437,7 @@ oj_parse_options(VALUE ropts, Options copts) {
|
|
431
437
|
{ oj_allow_nan_sym, &copts->allow_nan },
|
432
438
|
{ oj_trace_sym, &copts->trace },
|
433
439
|
{ oj_safe_sym, &copts->safe },
|
440
|
+
{ ignore_under_sym, &copts->ignore_under },
|
434
441
|
{ oj_create_additions_sym, &copts->create_ok },
|
435
442
|
{ Qnil, 0 }
|
436
443
|
};
|
@@ -506,8 +513,12 @@ oj_parse_options(VALUE ropts, Options copts) {
|
|
506
513
|
n = NUM2INT(v);
|
507
514
|
if (0 > n) {
|
508
515
|
n = 0;
|
516
|
+
copts->sec_prec_set = false;
|
509
517
|
} else if (9 < n) {
|
510
518
|
n = 9;
|
519
|
+
copts->sec_prec_set = true;
|
520
|
+
} else {
|
521
|
+
copts->sec_prec_set = true;
|
511
522
|
}
|
512
523
|
copts->sec_prec = n;
|
513
524
|
}
|
@@ -738,24 +749,26 @@ oj_parse_options(VALUE ropts, Options copts) {
|
|
738
749
|
}
|
739
750
|
}
|
740
751
|
if (Qnil != (v = rb_hash_lookup(ropts, integer_range_sym))) {
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
752
|
+
if (TYPE(v) == T_STRUCT && rb_obj_class(v) == rb_cRange) {
|
753
|
+
VALUE min = rb_funcall(v, oj_begin_id, 0);
|
754
|
+
VALUE max = rb_funcall(v, oj_end_id, 0);
|
755
|
+
|
756
|
+
if (TYPE(min) != T_FIXNUM || TYPE(max) != T_FIXNUM) {
|
757
|
+
rb_raise(rb_eArgError, ":integer_range range bounds is not Fixnum.");
|
758
|
+
}
|
759
|
+
|
760
|
+
copts->int_range_min = FIX2LONG(min);
|
761
|
+
copts->int_range_max = FIX2LONG(max);
|
762
|
+
} else if (Qfalse != v) {
|
763
|
+
rb_raise(rb_eArgError, ":integer_range must be a range of Fixnum.");
|
764
|
+
}
|
754
765
|
}
|
755
766
|
}
|
756
767
|
|
757
768
|
static int
|
758
|
-
match_string_cb(VALUE key, VALUE value,
|
769
|
+
match_string_cb(VALUE key, VALUE value, VALUE rx) {
|
770
|
+
RxClass rc = (RxClass)rx;
|
771
|
+
|
759
772
|
if (T_CLASS != rb_type(value)) {
|
760
773
|
rb_raise(rb_eArgError, "for :match_string, the hash values must be a Class.");
|
761
774
|
}
|
@@ -954,11 +967,13 @@ load_file(int argc, VALUE *argv, VALUE self) {
|
|
954
967
|
}
|
955
968
|
switch (mode) {
|
956
969
|
case StrictMode:
|
970
|
+
case NullMode:
|
957
971
|
oj_set_strict_callbacks(&pi);
|
958
972
|
return oj_pi_sparse(argc, argv, &pi, fd);
|
959
|
-
case NullMode:
|
960
|
-
case CompatMode:
|
961
973
|
case CustomMode:
|
974
|
+
oj_set_custom_callbacks(&pi);
|
975
|
+
return oj_pi_sparse(argc, argv, &pi, fd);
|
976
|
+
case CompatMode:
|
962
977
|
case RailsMode:
|
963
978
|
oj_set_compat_callbacks(&pi);
|
964
979
|
return oj_pi_sparse(argc, argv, &pi, fd);
|
@@ -1052,6 +1067,9 @@ dump(int argc, VALUE *argv, VALUE self) {
|
|
1052
1067
|
if (2 == argc) {
|
1053
1068
|
oj_parse_options(argv[1], &copts);
|
1054
1069
|
}
|
1070
|
+
if (CompatMode == copts.mode && copts.escape_mode != ASCIIEsc) {
|
1071
|
+
copts.escape_mode = JSONEsc;
|
1072
|
+
}
|
1055
1073
|
out.buf = buf;
|
1056
1074
|
out.end = buf + sizeof(buf) - 10;
|
1057
1075
|
out.allocated = false;
|
@@ -1640,6 +1658,7 @@ Init_oj() {
|
|
1640
1658
|
float_sym = ID2SYM(rb_intern("float")); rb_gc_register_address(&float_sym);
|
1641
1659
|
huge_sym = ID2SYM(rb_intern("huge")); rb_gc_register_address(&huge_sym);
|
1642
1660
|
ignore_sym = ID2SYM(rb_intern("ignore")); rb_gc_register_address(&ignore_sym);
|
1661
|
+
ignore_under_sym = ID2SYM(rb_intern("ignore_under")); rb_gc_register_address(&ignore_under_sym);
|
1643
1662
|
json_sym = ID2SYM(rb_intern("json")); rb_gc_register_address(&json_sym);
|
1644
1663
|
match_string_sym = ID2SYM(rb_intern("match_string")); rb_gc_register_address(&match_string_sym);
|
1645
1664
|
mode_sym = ID2SYM(rb_intern("mode")); rb_gc_register_address(&mode_sym);
|
@@ -1692,7 +1711,7 @@ Init_oj() {
|
|
1692
1711
|
oj_odd_init();
|
1693
1712
|
oj_mimic_rails_init();
|
1694
1713
|
|
1695
|
-
#
|
1714
|
+
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
1696
1715
|
if (0 != (err = pthread_mutex_init(&oj_cache_mutex, 0))) {
|
1697
1716
|
rb_raise(rb_eException, "failed to initialize a mutex. %s", strerror(err));
|
1698
1717
|
}
|
data/ext/oj/oj.h
CHANGED
@@ -21,7 +21,7 @@ extern "C" {
|
|
21
21
|
#include <stdint.h>
|
22
22
|
#include <stdbool.h>
|
23
23
|
|
24
|
-
#
|
24
|
+
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
25
25
|
#include <pthread.h>
|
26
26
|
#endif
|
27
27
|
#include "cache8.h"
|
@@ -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
|
@@ -370,7 +372,7 @@ extern bool oj_use_hash_alt;
|
|
370
372
|
extern bool oj_use_array_alt;
|
371
373
|
extern bool string_writer_optimized;
|
372
374
|
|
373
|
-
#
|
375
|
+
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
374
376
|
extern pthread_mutex_t oj_cache_mutex;
|
375
377
|
#else
|
376
378
|
extern VALUE oj_cache_mutex;
|
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
|
}
|
@@ -1049,6 +1058,10 @@ CLEANUP:
|
|
1049
1058
|
msg = rb_str_append(msg, oj_encode(rb_str_new2(pi->json)));
|
1050
1059
|
}
|
1051
1060
|
args[0] = msg;
|
1061
|
+
if (pi->err.clas == oj_parse_error_class) {
|
1062
|
+
// The error was an Oj::ParseError so change to a JSON::ParserError.
|
1063
|
+
pi->err.clas = oj_json_parser_error_class;
|
1064
|
+
}
|
1052
1065
|
rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
|
1053
1066
|
} else {
|
1054
1067
|
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,12 +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
|
|
1097
|
+
pv = rb_iv_get(encoding, "@escape_html_entities_in_json");
|
1098
|
+
escape_html = Qtrue == pv;
|
1074
1099
|
rb_undef_method(encoding, "escape_html_entities_in_json=");
|
1075
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);
|
1076
1103
|
|
1077
1104
|
pv = rb_iv_get(encoding, "@time_precision");
|
1078
1105
|
oj_default_options.sec_prec = NUM2INT(pv);
|
1106
|
+
oj_default_options.sec_prec_set = true;
|
1079
1107
|
rb_undef_method(encoding, "time_precision=");
|
1080
1108
|
rb_define_module_function(encoding, "time_precision=", rails_time_precision, 1);
|
1081
1109
|
rb_gv_set("$VERBOSE", verbose);
|
@@ -1283,7 +1311,8 @@ dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
1283
1311
|
}
|
1284
1312
|
|
1285
1313
|
static int
|
1286
|
-
hash_cb(VALUE key, VALUE value,
|
1314
|
+
hash_cb(VALUE key, VALUE value, VALUE ov) {
|
1315
|
+
Out out = (Out)ov;
|
1287
1316
|
int depth = out->depth;
|
1288
1317
|
long size;
|
1289
1318
|
int rtype = rb_type(key);
|
@@ -1396,14 +1425,17 @@ dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1396
1425
|
|
1397
1426
|
static void
|
1398
1427
|
dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
1428
|
+
VALUE clas;
|
1429
|
+
|
1399
1430
|
if (oj_code_dump(oj_compat_codes, obj, depth, out)) {
|
1400
1431
|
out->argc = 0;
|
1401
1432
|
return;
|
1402
1433
|
}
|
1434
|
+
clas = rb_obj_class(obj);
|
1403
1435
|
if (as_ok) {
|
1404
1436
|
ROpt ro;
|
1405
1437
|
|
1406
|
-
if (NULL != (ro = oj_rails_get_opt(out->ropts,
|
1438
|
+
if (NULL != (ro = oj_rails_get_opt(out->ropts, clas)) && ro->on) {
|
1407
1439
|
ro->dump(obj, depth, out, as_ok);
|
1408
1440
|
} else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
|
1409
1441
|
oj_dump_raw_json(obj, depth, out);
|
@@ -1411,6 +1443,8 @@ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1411
1443
|
dump_as_json(obj, depth, out, true);
|
1412
1444
|
} else if (rb_respond_to(obj, oj_to_hash_id)) {
|
1413
1445
|
dump_to_hash(obj, depth, out);
|
1446
|
+
} else if (oj_bigdecimal_class == clas) {
|
1447
|
+
dump_bigdecimal(obj, depth, out, false);
|
1414
1448
|
} else {
|
1415
1449
|
oj_dump_obj_to_s(obj, out);
|
1416
1450
|
}
|
@@ -1419,6 +1453,8 @@ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1419
1453
|
} else if (rb_respond_to(obj, oj_to_hash_id)) {
|
1420
1454
|
// Always attempt to_hash.
|
1421
1455
|
dump_to_hash(obj, depth, out);
|
1456
|
+
} else if (oj_bigdecimal_class == clas) {
|
1457
|
+
dump_bigdecimal(obj, depth, out, false);
|
1422
1458
|
} else {
|
1423
1459
|
oj_dump_obj_to_s(obj, out);
|
1424
1460
|
}
|
@@ -1437,7 +1473,7 @@ static DumpFunc rails_funcs[] = {
|
|
1437
1473
|
dump_hash, // RUBY_T_HASH = 0x08,
|
1438
1474
|
dump_obj, // RUBY_T_STRUCT = 0x09,
|
1439
1475
|
oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
|
1440
|
-
|
1476
|
+
dump_as_string, // RUBY_T_FILE = 0x0b,
|
1441
1477
|
dump_obj, // RUBY_T_DATA = 0x0c,
|
1442
1478
|
NULL, // RUBY_T_MATCH = 0x0d,
|
1443
1479
|
// Rails raises a stack error on Complex and Rational. It also corrupts
|