oj 3.12.2 → 3.13.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 -3
- data/ext/oj/buf.h +9 -0
- data/ext/oj/cache.c +193 -0
- data/ext/oj/cache.h +20 -0
- data/ext/oj/compat.c +8 -22
- data/ext/oj/custom.c +15 -14
- data/ext/oj/debug.c +132 -0
- data/ext/oj/dump.c +12 -15
- data/ext/oj/dump_compat.c +3 -3
- data/ext/oj/dump_object.c +9 -9
- data/ext/oj/dump_strict.c +3 -3
- data/ext/oj/err.h +19 -0
- data/ext/oj/extconf.rb +4 -0
- data/ext/oj/fast.c +7 -18
- data/ext/oj/intern.c +398 -0
- data/ext/oj/intern.h +27 -0
- data/ext/oj/mimic_json.c +9 -9
- data/ext/oj/object.c +11 -59
- data/ext/oj/odd.c +1 -1
- data/ext/oj/oj.c +167 -109
- data/ext/oj/oj.h +2 -2
- data/ext/oj/parse.c +5 -5
- data/ext/oj/parser.c +1512 -0
- data/ext/oj/parser.h +90 -0
- data/ext/oj/rails.c +5 -5
- data/ext/oj/resolve.c +2 -20
- data/ext/oj/rxclass.c +1 -1
- data/ext/oj/saj.c +1 -1
- data/ext/oj/saj2.c +348 -0
- data/ext/oj/scp.c +1 -1
- data/ext/oj/sparse.c +2 -2
- data/ext/oj/stream_writer.c +4 -4
- data/ext/oj/strict.c +10 -27
- data/ext/oj/string_writer.c +2 -2
- data/ext/oj/usual.c +1228 -0
- data/ext/oj/validate.c +51 -0
- data/ext/oj/wab.c +9 -17
- data/lib/oj/error.rb +1 -1
- data/lib/oj/mimic.rb +1 -1
- data/lib/oj/version.rb +1 -1
- data/pages/Modes.md +2 -0
- data/pages/Options.md +17 -5
- data/pages/Parser.md +309 -0
- data/pages/Rails.md +2 -2
- data/test/json_gem/json_generator_test.rb +1 -1
- data/test/perf_parser.rb +184 -0
- data/test/test_hash.rb +1 -1
- data/test/test_parser.rb +27 -0
- data/test/test_parser_saj.rb +245 -0
- data/test/test_parser_usual.rb +213 -0
- metadata +22 -5
- data/ext/oj/hash.c +0 -168
- data/ext/oj/hash.h +0 -21
- data/ext/oj/hash_test.c +0 -491
data/ext/oj/intern.h
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
// Copyright (c) 2011, 2021 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
3
|
+
|
4
|
+
#ifndef OJ_INTERN_H
|
5
|
+
#define OJ_INTERN_H
|
6
|
+
|
7
|
+
#include <stdbool.h>
|
8
|
+
#include <ruby.h>
|
9
|
+
|
10
|
+
struct _parseInfo;
|
11
|
+
|
12
|
+
extern void oj_hash_init();
|
13
|
+
|
14
|
+
extern VALUE oj_str_intern(const char *key, size_t len);
|
15
|
+
extern VALUE oj_sym_intern(const char *key, size_t len);
|
16
|
+
extern ID oj_attr_intern(const char *key, size_t len);
|
17
|
+
extern VALUE oj_class_intern(const char * key,
|
18
|
+
size_t len,
|
19
|
+
bool safe,
|
20
|
+
struct _parseInfo *pi,
|
21
|
+
int auto_define,
|
22
|
+
VALUE error_class);
|
23
|
+
|
24
|
+
extern void oj_hash_print();
|
25
|
+
extern char *oj_strndup(const char *s, size_t len);
|
26
|
+
|
27
|
+
#endif /* OJ_INTERN_H */
|
data/ext/oj/mimic_json.c
CHANGED
@@ -464,19 +464,19 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
|
|
464
464
|
} else {
|
465
465
|
h = argv[1];
|
466
466
|
}
|
467
|
-
if (
|
467
|
+
if (!oj_hash_has_key(h, oj_indent_sym)) {
|
468
468
|
rb_hash_aset(h, oj_indent_sym, rb_str_new2(" "));
|
469
469
|
}
|
470
|
-
if (
|
470
|
+
if (!oj_hash_has_key(h, oj_space_before_sym)) {
|
471
471
|
rb_hash_aset(h, oj_space_before_sym, rb_str_new2(""));
|
472
472
|
}
|
473
|
-
if (
|
473
|
+
if (!oj_hash_has_key(h, oj_space_sym)) {
|
474
474
|
rb_hash_aset(h, oj_space_sym, rb_str_new2(" "));
|
475
475
|
}
|
476
|
-
if (
|
476
|
+
if (!oj_hash_has_key(h, oj_object_nl_sym)) {
|
477
477
|
rb_hash_aset(h, oj_object_nl_sym, rb_str_new2("\n"));
|
478
478
|
}
|
479
|
-
if (
|
479
|
+
if (!oj_hash_has_key(h, oj_array_nl_sym)) {
|
480
480
|
rb_hash_aset(h, oj_array_nl_sym, rb_str_new2("\n"));
|
481
481
|
}
|
482
482
|
if (Qundef == state_class) {
|
@@ -548,7 +548,7 @@ static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
|
|
548
548
|
pi.options.allow_nan = (Qtrue == v) ? Yes : No;
|
549
549
|
}
|
550
550
|
|
551
|
-
if (
|
551
|
+
if (oj_hash_has_key(ropts, oj_hash_class_sym)) {
|
552
552
|
if (Qnil == (v = rb_hash_lookup(ropts, oj_hash_class_sym))) {
|
553
553
|
pi.options.hash_class = Qnil;
|
554
554
|
} else {
|
@@ -556,7 +556,7 @@ static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
|
|
556
556
|
pi.options.hash_class = v;
|
557
557
|
}
|
558
558
|
}
|
559
|
-
if (
|
559
|
+
if (oj_hash_has_key(ropts, oj_object_class_sym)) {
|
560
560
|
if (Qnil == (v = rb_hash_lookup(ropts, oj_object_class_sym))) {
|
561
561
|
pi.options.hash_class = Qnil;
|
562
562
|
} else {
|
@@ -564,7 +564,7 @@ static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
|
|
564
564
|
pi.options.hash_class = v;
|
565
565
|
}
|
566
566
|
}
|
567
|
-
if (
|
567
|
+
if (oj_hash_has_key(ropts, oj_array_class_sym)) {
|
568
568
|
if (Qnil == (v = rb_hash_lookup(ropts, oj_array_class_sym))) {
|
569
569
|
pi.options.array_class = Qnil;
|
570
570
|
} else {
|
@@ -572,7 +572,7 @@ static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
|
|
572
572
|
pi.options.array_class = v;
|
573
573
|
}
|
574
574
|
}
|
575
|
-
if (
|
575
|
+
if (oj_hash_has_key(ropts, oj_decimal_class_sym)) {
|
576
576
|
pi.options.compat_bigdec = (oj_bigdecimal_class ==
|
577
577
|
rb_hash_lookup(ropts, oj_decimal_class_sym));
|
578
578
|
}
|
data/ext/oj/object.c
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
|
8
8
|
#include "encode.h"
|
9
9
|
#include "err.h"
|
10
|
-
#include "
|
10
|
+
#include "intern.h"
|
11
11
|
#include "odd.h"
|
12
12
|
#include "oj.h"
|
13
13
|
#include "parse.h"
|
@@ -59,17 +59,17 @@ static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) {
|
|
59
59
|
}
|
60
60
|
#else
|
61
61
|
if (':' == k1) {
|
62
|
-
rkey =
|
63
|
-
rkey = oj_encode(rkey);
|
64
|
-
rkey = rb_str_intern(rkey);
|
62
|
+
rkey = ID2SYM(rb_intern3(kval->key + 1, kval->klen - 1, oj_utf8_encoding));
|
65
63
|
} else {
|
66
|
-
rkey = rb_str_new(kval->key, kval->klen);
|
67
|
-
rkey = oj_encode(rkey);
|
68
64
|
if (Yes == pi->options.sym_key) {
|
69
|
-
rkey =
|
65
|
+
rkey = ID2SYM(rb_intern3(kval->key, kval->klen, oj_utf8_encoding));
|
66
|
+
} else {
|
67
|
+
rkey = rb_str_new(kval->key, kval->klen);
|
68
|
+
rkey = oj_encode(rkey);
|
70
69
|
}
|
71
70
|
}
|
72
71
|
#endif
|
72
|
+
OBJ_FREEZE(rkey);
|
73
73
|
return rkey;
|
74
74
|
}
|
75
75
|
|
@@ -77,9 +77,7 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
|
|
77
77
|
volatile VALUE rstr = Qnil;
|
78
78
|
|
79
79
|
if (':' == *orig && 0 < len) {
|
80
|
-
rstr =
|
81
|
-
rstr = oj_encode(rstr);
|
82
|
-
rstr = rb_funcall(rstr, oj_to_sym_id, 0);
|
80
|
+
rstr = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
|
83
81
|
} else if (pi->circ_array && 3 <= len && '^' == *orig && 'r' == orig[1]) {
|
84
82
|
long i = read_long(str + 2, len - 2);
|
85
83
|
|
@@ -258,9 +256,7 @@ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t
|
|
258
256
|
parent->odd_args = oj_odd_alloc_args(odd);
|
259
257
|
} break;
|
260
258
|
case 'm':
|
261
|
-
parent->val =
|
262
|
-
parent->val = oj_encode(parent->val);
|
263
|
-
parent->val = rb_funcall(parent->val, oj_to_sym_id, 0);
|
259
|
+
parent->val = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
|
264
260
|
break;
|
265
261
|
case 's':
|
266
262
|
parent->val = rb_str_new(str, len);
|
@@ -305,7 +301,7 @@ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
|
305
301
|
}
|
306
302
|
if (86400 == ni->exp) { // UTC time
|
307
303
|
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
308
|
-
// Since the ruby C routines
|
304
|
+
// Since the ruby C routines always create local time, the
|
309
305
|
// offset and then a conversion to UTC keeps makes the time
|
310
306
|
// match the expected value.
|
311
307
|
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
|
@@ -416,51 +412,7 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
416
412
|
}
|
417
413
|
|
418
414
|
void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
|
419
|
-
|
420
|
-
int klen = kval->klen;
|
421
|
-
ID var_id;
|
422
|
-
ID * slot;
|
423
|
-
|
424
|
-
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
425
|
-
pthread_mutex_lock(&oj_cache_mutex);
|
426
|
-
#else
|
427
|
-
rb_mutex_lock(oj_cache_mutex);
|
428
|
-
#endif
|
429
|
-
if (0 == (var_id = oj_attr_hash_get(key, klen, &slot))) {
|
430
|
-
char attr[256];
|
431
|
-
|
432
|
-
if ((int)sizeof(attr) <= klen + 2) {
|
433
|
-
char *buf = ALLOC_N(char, klen + 2);
|
434
|
-
|
435
|
-
if ('~' == *key) {
|
436
|
-
memcpy(buf, key + 1, klen - 1);
|
437
|
-
buf[klen - 1] = '\0';
|
438
|
-
} else {
|
439
|
-
*buf = '@';
|
440
|
-
memcpy(buf + 1, key, klen);
|
441
|
-
buf[klen + 1] = '\0';
|
442
|
-
}
|
443
|
-
var_id = rb_intern(buf);
|
444
|
-
xfree(buf);
|
445
|
-
} else {
|
446
|
-
if ('~' == *key) {
|
447
|
-
memcpy(attr, key + 1, klen - 1);
|
448
|
-
attr[klen - 1] = '\0';
|
449
|
-
} else {
|
450
|
-
*attr = '@';
|
451
|
-
memcpy(attr + 1, key, klen);
|
452
|
-
attr[klen + 1] = '\0';
|
453
|
-
}
|
454
|
-
var_id = rb_intern(attr);
|
455
|
-
}
|
456
|
-
*slot = var_id;
|
457
|
-
}
|
458
|
-
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
459
|
-
pthread_mutex_unlock(&oj_cache_mutex);
|
460
|
-
#else
|
461
|
-
rb_mutex_unlock(oj_cache_mutex);
|
462
|
-
#endif
|
463
|
-
rb_ivar_set(parent->val, var_id, value);
|
415
|
+
rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
|
464
416
|
}
|
465
417
|
|
466
418
|
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
data/ext/oj/odd.c
CHANGED
@@ -206,7 +206,7 @@ void oj_reg_odd(VALUE clas,
|
|
206
206
|
*fp = 0;
|
207
207
|
switch (rb_type(*members)) {
|
208
208
|
case T_STRING:
|
209
|
-
if (NULL == (*np = strdup(
|
209
|
+
if (NULL == (*np = strdup(RSTRING_PTR(*members)))) {
|
210
210
|
rb_raise(rb_eNoMemError, "for attribute name.");
|
211
211
|
}
|
212
212
|
break;
|
data/ext/oj/oj.c
CHANGED
@@ -13,7 +13,7 @@
|
|
13
13
|
|
14
14
|
#include "dump.h"
|
15
15
|
#include "encode.h"
|
16
|
-
#include "
|
16
|
+
#include "intern.h"
|
17
17
|
#include "odd.h"
|
18
18
|
#include "parse.h"
|
19
19
|
#include "rails.h"
|
@@ -40,7 +40,6 @@ ID oj_error_id;
|
|
40
40
|
ID oj_file_id;
|
41
41
|
ID oj_fileno_id;
|
42
42
|
ID oj_ftype_id;
|
43
|
-
ID oj_has_key_id;
|
44
43
|
ID oj_hash_end_id;
|
45
44
|
ID oj_hash_key_id;
|
46
45
|
ID oj_hash_set_id;
|
@@ -159,6 +158,8 @@ pthread_mutex_t oj_cache_mutex;
|
|
159
158
|
VALUE oj_cache_mutex = Qnil;
|
160
159
|
#endif
|
161
160
|
|
161
|
+
extern void oj_parser_init();
|
162
|
+
|
162
163
|
const char oj_json_class[] = "json_class";
|
163
164
|
|
164
165
|
struct _options oj_default_options = {
|
@@ -508,7 +509,7 @@ static VALUE get_def_opts(VALUE self) {
|
|
508
509
|
* Sets the default options for load and dump.
|
509
510
|
* - *opts* [_Hash_] options to change
|
510
511
|
* - *:indent* [_Fixnum_|_String_|_nil_] number of spaces to indent each element in a JSON
|
511
|
-
*document or the String to use for
|
512
|
+
*document or the String to use for indentation.
|
512
513
|
* - :circular [_Boolean_|_nil_] support circular references while dumping.
|
513
514
|
* - *:auto_define* [_Boolean_|_nil_] automatically define classes if they do not exist.
|
514
515
|
* - *:symbol_keys* [_Boolean_|_nil_] convert hash keys to symbols.
|
@@ -582,7 +583,16 @@ static VALUE set_def_opts(VALUE self, VALUE opts) {
|
|
582
583
|
return Qnil;
|
583
584
|
}
|
584
585
|
|
585
|
-
|
586
|
+
bool oj_hash_has_key(VALUE hash, VALUE key)
|
587
|
+
{
|
588
|
+
if (Qundef == rb_hash_lookup2(hash, key, Qundef)) {
|
589
|
+
return false;
|
590
|
+
}
|
591
|
+
return true;
|
592
|
+
}
|
593
|
+
|
594
|
+
bool set_yesno_options(VALUE key, VALUE value, Options copts)
|
595
|
+
{
|
586
596
|
struct _yesNoOpt ynos[] = {{circular_sym, &copts->circular},
|
587
597
|
{auto_define_sym, &copts->auto_define},
|
588
598
|
{symbol_keys_sym, &copts->sym_key},
|
@@ -605,15 +615,37 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
605
615
|
{oj_create_additions_sym, &copts->create_ok},
|
606
616
|
{cache_keys_sym, &copts->cache_keys},
|
607
617
|
{Qnil, 0}};
|
608
|
-
YesNoOpt
|
609
|
-
|
610
|
-
|
618
|
+
YesNoOpt o;
|
619
|
+
|
620
|
+
for (o = ynos; 0 != o->attr; o++) {
|
621
|
+
if (key == o->sym) {
|
622
|
+
if (Qnil == value) {
|
623
|
+
*o->attr = NotSet;
|
624
|
+
} else if (Qtrue == value) {
|
625
|
+
*o->attr = Yes;
|
626
|
+
} else if (Qfalse == value) {
|
627
|
+
*o->attr = No;
|
628
|
+
} else {
|
629
|
+
rb_raise(rb_eArgError,
|
630
|
+
"%s must be true, false, or nil.",
|
631
|
+
rb_id2name(key));
|
632
|
+
}
|
633
|
+
return true;
|
634
|
+
}
|
635
|
+
}
|
636
|
+
return false;
|
637
|
+
}
|
611
638
|
|
612
|
-
|
613
|
-
|
639
|
+
static int parse_options_cb(VALUE k, VALUE v, VALUE opts)
|
640
|
+
{
|
641
|
+
Options copts = (Options)opts;
|
642
|
+
size_t len;
|
643
|
+
|
644
|
+
if (set_yesno_options(k, v, copts)) {
|
645
|
+
return ST_CONTINUE;
|
614
646
|
}
|
615
|
-
|
616
|
-
|
647
|
+
|
648
|
+
if (oj_indent_sym == k) {
|
617
649
|
switch (rb_type(v)) {
|
618
650
|
case T_NIL:
|
619
651
|
copts->dump_opts.indent_size = 0;
|
@@ -637,8 +669,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
637
669
|
break;
|
638
670
|
default: rb_raise(rb_eTypeError, "indent must be a Fixnum, String, or nil."); break;
|
639
671
|
}
|
640
|
-
}
|
641
|
-
if (Qnil != (v = rb_hash_lookup(ropts, float_prec_sym))) {
|
672
|
+
} else if (float_prec_sym == k) {
|
642
673
|
int n;
|
643
674
|
|
644
675
|
#ifdef RUBY_INTEGER_UNIFICATION
|
@@ -661,8 +692,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
661
692
|
sprintf(copts->float_fmt, "%%0.%dg", n);
|
662
693
|
copts->float_prec = n;
|
663
694
|
}
|
664
|
-
}
|
665
|
-
if (Qnil != (v = rb_hash_lookup(ropts, cache_str_sym))) {
|
695
|
+
} else if (cache_str_sym == k) {
|
666
696
|
int n;
|
667
697
|
|
668
698
|
#ifdef RUBY_INTEGER_UNIFICATION
|
@@ -683,8 +713,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
683
713
|
}
|
684
714
|
copts->cache_str = (char)n;
|
685
715
|
}
|
686
|
-
}
|
687
|
-
if (Qnil != (v = rb_hash_lookup(ropts, sec_prec_sym))) {
|
716
|
+
} else if (sec_prec_sym == k) {
|
688
717
|
int n;
|
689
718
|
|
690
719
|
#ifdef RUBY_INTEGER_UNIFICATION
|
@@ -707,8 +736,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
707
736
|
copts->sec_prec_set = true;
|
708
737
|
}
|
709
738
|
copts->sec_prec = n;
|
710
|
-
}
|
711
|
-
if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) {
|
739
|
+
} else if (mode_sym == k) {
|
712
740
|
if (wab_sym == v) {
|
713
741
|
copts->mode = WabMode;
|
714
742
|
} else if (object_sym == v) {
|
@@ -727,8 +755,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
727
755
|
rb_raise(rb_eArgError,
|
728
756
|
":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab.");
|
729
757
|
}
|
730
|
-
}
|
731
|
-
if (Qnil != (v = rb_hash_lookup(ropts, time_format_sym))) {
|
758
|
+
} else if (time_format_sym == k) {
|
732
759
|
if (unix_sym == v) {
|
733
760
|
copts->time_format = UnixTime;
|
734
761
|
} else if (unix_zone_sym == v) {
|
@@ -740,8 +767,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
740
767
|
} else {
|
741
768
|
rb_raise(rb_eArgError, ":time_format must be :unix, :unix_zone, :xmlschema, or :ruby.");
|
742
769
|
}
|
743
|
-
}
|
744
|
-
if (Qnil != (v = rb_hash_lookup(ropts, escape_mode_sym))) {
|
770
|
+
} else if (escape_mode_sym == k) {
|
745
771
|
if (newline_sym == v) {
|
746
772
|
copts->escape_mode = NLEsc;
|
747
773
|
} else if (json_sym == v) {
|
@@ -756,8 +782,11 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
756
782
|
rb_raise(rb_eArgError,
|
757
783
|
":encoding must be :newline, :json, :xss_safe, :unicode_xss, or :ascii.");
|
758
784
|
}
|
759
|
-
}
|
760
|
-
|
785
|
+
} else if (bigdecimal_load_sym == k) {
|
786
|
+
if (Qnil == v) {
|
787
|
+
return ST_CONTINUE;
|
788
|
+
}
|
789
|
+
|
761
790
|
if (bigdecimal_sym == v || Qtrue == v) {
|
762
791
|
copts->bigdec_load = BigDec;
|
763
792
|
} else if (float_sym == v) {
|
@@ -769,12 +798,13 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
769
798
|
} else {
|
770
799
|
rb_raise(rb_eArgError, ":bigdecimal_load must be :bigdecimal, :float, or :auto.");
|
771
800
|
}
|
772
|
-
}
|
773
|
-
|
801
|
+
} else if (compat_bigdecimal_sym == k) {
|
802
|
+
if (Qnil == v) {
|
803
|
+
return ST_CONTINUE;
|
804
|
+
}
|
805
|
+
|
774
806
|
copts->compat_bigdec = (Qtrue == v);
|
775
|
-
}
|
776
|
-
if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_decimal_class_sym)) {
|
777
|
-
v = rb_hash_lookup(ropts, oj_decimal_class_sym);
|
807
|
+
} else if (oj_decimal_class_sym == k) {
|
778
808
|
if (rb_cFloat == v) {
|
779
809
|
copts->compat_bigdec = false;
|
780
810
|
} else if (oj_bigdecimal_class == v) {
|
@@ -782,9 +812,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
782
812
|
} else {
|
783
813
|
rb_raise(rb_eArgError, ":decimal_class must be BigDecimal or Float.");
|
784
814
|
}
|
785
|
-
}
|
786
|
-
if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, create_id_sym)) {
|
787
|
-
v = rb_hash_lookup(ropts, create_id_sym);
|
815
|
+
} else if (create_id_sym == k) {
|
788
816
|
if (Qnil == v) {
|
789
817
|
if (oj_json_class != oj_default_options.create_id && NULL != copts->create_id) {
|
790
818
|
xfree((char *)oj_default_options.create_id);
|
@@ -803,25 +831,8 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
803
831
|
} else {
|
804
832
|
rb_raise(rb_eArgError, ":create_id must be string.");
|
805
833
|
}
|
806
|
-
}
|
807
|
-
|
808
|
-
if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, o->sym)) {
|
809
|
-
v = rb_hash_lookup(ropts, o->sym);
|
810
|
-
if (Qnil == v) {
|
811
|
-
*o->attr = NotSet;
|
812
|
-
} else if (Qtrue == v) {
|
813
|
-
*o->attr = Yes;
|
814
|
-
} else if (Qfalse == v) {
|
815
|
-
*o->attr = No;
|
816
|
-
} else {
|
817
|
-
rb_raise(rb_eArgError,
|
818
|
-
"%s must be true, false, or nil.",
|
819
|
-
rb_id2name(SYM2ID(o->sym)));
|
820
|
-
}
|
821
|
-
}
|
822
|
-
}
|
823
|
-
if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_space_sym)) {
|
824
|
-
if (Qnil == (v = rb_hash_lookup(ropts, oj_space_sym))) {
|
834
|
+
} else if (oj_space_sym == k) {
|
835
|
+
if (Qnil == v) {
|
825
836
|
copts->dump_opts.after_size = 0;
|
826
837
|
*copts->dump_opts.after_sep = '\0';
|
827
838
|
} else {
|
@@ -834,9 +845,8 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
834
845
|
strcpy(copts->dump_opts.after_sep, StringValuePtr(v));
|
835
846
|
copts->dump_opts.after_size = (uint8_t)len;
|
836
847
|
}
|
837
|
-
}
|
838
|
-
|
839
|
-
if (Qnil == (v = rb_hash_lookup(ropts, oj_space_before_sym))) {
|
848
|
+
} else if (oj_space_before_sym == k) {
|
849
|
+
if (Qnil == v) {
|
840
850
|
copts->dump_opts.before_size = 0;
|
841
851
|
*copts->dump_opts.before_sep = '\0';
|
842
852
|
} else {
|
@@ -849,9 +859,8 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
849
859
|
strcpy(copts->dump_opts.before_sep, StringValuePtr(v));
|
850
860
|
copts->dump_opts.before_size = (uint8_t)len;
|
851
861
|
}
|
852
|
-
}
|
853
|
-
|
854
|
-
if (Qnil == (v = rb_hash_lookup(ropts, oj_object_nl_sym))) {
|
862
|
+
} else if (oj_object_nl_sym == k) {
|
863
|
+
if (Qnil == v) {
|
855
864
|
copts->dump_opts.hash_size = 0;
|
856
865
|
*copts->dump_opts.hash_nl = '\0';
|
857
866
|
} else {
|
@@ -864,9 +873,8 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
864
873
|
strcpy(copts->dump_opts.hash_nl, StringValuePtr(v));
|
865
874
|
copts->dump_opts.hash_size = (uint8_t)len;
|
866
875
|
}
|
867
|
-
}
|
868
|
-
|
869
|
-
if (Qnil == (v = rb_hash_lookup(ropts, oj_array_nl_sym))) {
|
876
|
+
} else if (oj_array_nl_sym == k) {
|
877
|
+
if (Qnil == v) {
|
870
878
|
copts->dump_opts.array_size = 0;
|
871
879
|
*copts->dump_opts.array_nl = '\0';
|
872
880
|
} else {
|
@@ -879,8 +887,11 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
879
887
|
strcpy(copts->dump_opts.array_nl, StringValuePtr(v));
|
880
888
|
copts->dump_opts.array_size = (uint8_t)len;
|
881
889
|
}
|
882
|
-
}
|
883
|
-
|
890
|
+
} else if (nan_sym == k) {
|
891
|
+
if (Qnil == v) {
|
892
|
+
return ST_CONTINUE;
|
893
|
+
}
|
894
|
+
|
884
895
|
if (null_sym == v) {
|
885
896
|
copts->dump_opts.nan_dump = NullNan;
|
886
897
|
} else if (huge_sym == v) {
|
@@ -894,11 +905,11 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
894
905
|
} else {
|
895
906
|
rb_raise(rb_eArgError, ":nan must be :null, :huge, :word, :raise, or :auto.");
|
896
907
|
}
|
897
|
-
}
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
908
|
+
} else if (omit_nil_sym == k) {
|
909
|
+
if (Qnil == v) {
|
910
|
+
return ST_CONTINUE;
|
911
|
+
}
|
912
|
+
|
902
913
|
if (Qtrue == v) {
|
903
914
|
copts->dump_opts.omit_nil = true;
|
904
915
|
} else if (Qfalse == v) {
|
@@ -906,43 +917,38 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
906
917
|
} else {
|
907
918
|
rb_raise(rb_eArgError, ":omit_nil must be true or false.");
|
908
919
|
}
|
909
|
-
}
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
}
|
917
|
-
|
918
|
-
if (Qnil == (v = rb_hash_lookup(ropts, oj_hash_class_sym))) {
|
920
|
+
} else if(oj_ascii_only_sym == k) {
|
921
|
+
// This is here only for backwards compatibility with the original Oj.
|
922
|
+
if (Qtrue == v) {
|
923
|
+
copts->escape_mode = ASCIIEsc;
|
924
|
+
} else if (Qfalse == v) {
|
925
|
+
copts->escape_mode = JSONEsc;
|
926
|
+
}
|
927
|
+
} else if (oj_hash_class_sym == k) {
|
928
|
+
if (Qnil == v) {
|
919
929
|
copts->hash_class = Qnil;
|
920
930
|
} else {
|
921
931
|
rb_check_type(v, T_CLASS);
|
922
932
|
copts->hash_class = v;
|
923
933
|
}
|
924
|
-
}
|
925
|
-
|
926
|
-
if (Qnil == (v = rb_hash_lookup(ropts, oj_object_class_sym))) {
|
934
|
+
} else if (oj_object_class_sym == k) {
|
935
|
+
if (Qnil == v) {
|
927
936
|
copts->hash_class = Qnil;
|
928
937
|
} else {
|
929
938
|
rb_check_type(v, T_CLASS);
|
930
939
|
copts->hash_class = v;
|
931
940
|
}
|
932
|
-
}
|
933
|
-
|
934
|
-
if (Qnil == (v = rb_hash_lookup(ropts, oj_array_class_sym))) {
|
941
|
+
} else if (oj_array_class_sym == k) {
|
942
|
+
if (Qnil == v) {
|
935
943
|
copts->array_class = Qnil;
|
936
944
|
} else {
|
937
945
|
rb_check_type(v, T_CLASS);
|
938
946
|
copts->array_class = v;
|
939
947
|
}
|
940
|
-
}
|
941
|
-
oj_parse_opt_match_string(&copts->str_rx, ropts);
|
942
|
-
if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, ignore_sym)) {
|
948
|
+
} else if (ignore_sym == k) {
|
943
949
|
xfree(copts->ignore);
|
944
950
|
copts->ignore = NULL;
|
945
|
-
if (Qnil !=
|
951
|
+
if (Qnil != v) {
|
946
952
|
int cnt;
|
947
953
|
|
948
954
|
rb_check_type(v, T_ARRAY);
|
@@ -957,8 +963,11 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
957
963
|
copts->ignore[i] = Qnil;
|
958
964
|
}
|
959
965
|
}
|
960
|
-
}
|
961
|
-
|
966
|
+
} else if (integer_range_sym == k) {
|
967
|
+
if (Qnil == v) {
|
968
|
+
return ST_CONTINUE;
|
969
|
+
}
|
970
|
+
|
962
971
|
if (TYPE(v) == T_STRUCT && rb_obj_class(v) == rb_cRange) {
|
963
972
|
VALUE min = rb_funcall(v, oj_begin_id, 0);
|
964
973
|
VALUE max = rb_funcall(v, oj_end_id, 0);
|
@@ -973,6 +982,22 @@ void oj_parse_options(VALUE ropts, Options copts) {
|
|
973
982
|
rb_raise(rb_eArgError, ":integer_range must be a range of Fixnum.");
|
974
983
|
}
|
975
984
|
}
|
985
|
+
|
986
|
+
return ST_CONTINUE;
|
987
|
+
}
|
988
|
+
|
989
|
+
void oj_parse_options(VALUE ropts, Options copts) {
|
990
|
+
if (T_HASH != rb_type(ropts)) {
|
991
|
+
return;
|
992
|
+
}
|
993
|
+
|
994
|
+
rb_hash_foreach(ropts, parse_options_cb, (VALUE)copts);
|
995
|
+
oj_parse_opt_match_string(&copts->str_rx, ropts);
|
996
|
+
|
997
|
+
copts->dump_opts.use = (0 < copts->dump_opts.indent_size || 0 < copts->dump_opts.after_size ||
|
998
|
+
0 < copts->dump_opts.before_size || 0 < copts->dump_opts.hash_size ||
|
999
|
+
0 < copts->dump_opts.array_size);
|
1000
|
+
return;
|
976
1001
|
}
|
977
1002
|
|
978
1003
|
static int match_string_cb(VALUE key, VALUE value, VALUE rx) {
|
@@ -1237,6 +1262,38 @@ static VALUE safe_load(VALUE self, VALUE doc) {
|
|
1237
1262
|
* - *io* [_IO__|_String_] IO Object to read from
|
1238
1263
|
*/
|
1239
1264
|
|
1265
|
+
struct dump_arg {
|
1266
|
+
struct _out *out;
|
1267
|
+
struct _options *copts;
|
1268
|
+
int argc;
|
1269
|
+
VALUE *argv;
|
1270
|
+
};
|
1271
|
+
|
1272
|
+
static VALUE dump_body(VALUE a)
|
1273
|
+
{
|
1274
|
+
volatile struct dump_arg *arg = (void *)a;
|
1275
|
+
VALUE rstr;
|
1276
|
+
|
1277
|
+
oj_dump_obj_to_json_using_params(*arg->argv, arg->copts, arg->out, arg->argc - 1, arg->argv + 1);
|
1278
|
+
if (0 == arg->out->buf) {
|
1279
|
+
rb_raise(rb_eNoMemError, "Not enough memory.");
|
1280
|
+
}
|
1281
|
+
rstr = rb_str_new2(arg->out->buf);
|
1282
|
+
rstr = oj_encode(rstr);
|
1283
|
+
|
1284
|
+
return rstr;
|
1285
|
+
}
|
1286
|
+
|
1287
|
+
static VALUE dump_ensure(VALUE a)
|
1288
|
+
{
|
1289
|
+
volatile struct dump_arg *arg = (void *)a;
|
1290
|
+
|
1291
|
+
if (arg->out->allocated) {
|
1292
|
+
xfree(arg->out->buf);
|
1293
|
+
}
|
1294
|
+
return Qnil;
|
1295
|
+
}
|
1296
|
+
|
1240
1297
|
/* Document-method: dump
|
1241
1298
|
* call-seq: dump(obj, options={})
|
1242
1299
|
*
|
@@ -1246,9 +1303,9 @@ static VALUE safe_load(VALUE self, VALUE doc) {
|
|
1246
1303
|
*/
|
1247
1304
|
static VALUE dump(int argc, VALUE *argv, VALUE self) {
|
1248
1305
|
char buf[4096];
|
1306
|
+
struct dump_arg arg;
|
1249
1307
|
struct _out out;
|
1250
1308
|
struct _options copts = oj_default_options;
|
1251
|
-
VALUE rstr;
|
1252
1309
|
|
1253
1310
|
if (1 > argc) {
|
1254
1311
|
rb_raise(rb_eArgError, "wrong number of arguments (0 for 1).");
|
@@ -1262,21 +1319,18 @@ static VALUE dump(int argc, VALUE *argv, VALUE self) {
|
|
1262
1319
|
if (CompatMode == copts.mode && copts.escape_mode != ASCIIEsc) {
|
1263
1320
|
copts.escape_mode = JSONEsc;
|
1264
1321
|
}
|
1265
|
-
out
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
xfree(out.buf);
|
1278
|
-
}
|
1279
|
-
return rstr;
|
1322
|
+
arg.out = &out;
|
1323
|
+
arg.copts = &copts;
|
1324
|
+
arg.argc = argc;
|
1325
|
+
arg.argv = argv;
|
1326
|
+
|
1327
|
+
arg.out->buf = buf;
|
1328
|
+
arg.out->end = buf + sizeof(buf) - 10;
|
1329
|
+
arg.out->allocated = false;
|
1330
|
+
arg.out->omit_nil = copts.dump_opts.omit_nil;
|
1331
|
+
arg.out->caller = CALLER_DUMP;
|
1332
|
+
|
1333
|
+
return rb_ensure(dump_body, (VALUE)&arg, dump_ensure, (VALUE)&arg);
|
1280
1334
|
}
|
1281
1335
|
|
1282
1336
|
/* Document-method: to_json
|
@@ -1344,7 +1398,7 @@ static VALUE to_json(int argc, VALUE *argv, VALUE self) {
|
|
1344
1398
|
* Dumps an Object to the specified file.
|
1345
1399
|
* - *file* [_String_] _path file path to write the JSON document to
|
1346
1400
|
* - *obj* [_Object_] Object to serialize as an JSON document String
|
1347
|
-
* - *options* [_Hash_]
|
1401
|
+
* - *options* [_Hash_] formatting options
|
1348
1402
|
* - *:indent* [_Fixnum_] format expected
|
1349
1403
|
* - *:circular* [_Boolean_] allow circular references, default: false
|
1350
1404
|
*/
|
@@ -1366,7 +1420,7 @@ static VALUE to_file(int argc, VALUE *argv, VALUE self) {
|
|
1366
1420
|
* Dumps an Object to the specified IO stream.
|
1367
1421
|
* - *io* [_IO_] IO stream to write the JSON document to
|
1368
1422
|
* - *obj* [_Object_] Object to serialize as an JSON document String
|
1369
|
-
* - *options* [_Hash_]
|
1423
|
+
* - *options* [_Hash_] formatting options
|
1370
1424
|
* - *:indent* [_Fixnum_] format expected
|
1371
1425
|
* - *:circular* [_Boolean_] allow circular references, default: false
|
1372
1426
|
*/
|
@@ -1725,6 +1779,9 @@ static VALUE protect_require(VALUE x) {
|
|
1725
1779
|
void Init_oj() {
|
1726
1780
|
int err = 0;
|
1727
1781
|
|
1782
|
+
#if HAVE_RB_EXT_RACTOR_SAFE
|
1783
|
+
rb_ext_ractor_safe(true);
|
1784
|
+
#endif
|
1728
1785
|
Oj = rb_define_module("Oj");
|
1729
1786
|
|
1730
1787
|
oj_cstack_class = rb_define_class_under(Oj, "CStack", rb_cObject);
|
@@ -1785,7 +1842,6 @@ void Init_oj() {
|
|
1785
1842
|
oj_file_id = rb_intern("file?");
|
1786
1843
|
oj_fileno_id = rb_intern("fileno");
|
1787
1844
|
oj_ftype_id = rb_intern("ftype");
|
1788
|
-
oj_has_key_id = rb_intern("has_key?");
|
1789
1845
|
oj_hash_end_id = rb_intern("hash_end");
|
1790
1846
|
oj_hash_key_id = rb_intern("hash_key");
|
1791
1847
|
oj_hash_set_id = rb_intern("hash_set");
|
@@ -2000,4 +2056,6 @@ void Init_oj() {
|
|
2000
2056
|
rb_gc_register_address(&oj_cache_mutex);
|
2001
2057
|
#endif
|
2002
2058
|
oj_init_doc();
|
2059
|
+
|
2060
|
+
oj_parser_init();
|
2003
2061
|
}
|