oj 3.8.1 → 3.10.1
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 +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
|