oj 3.16.3 → 3.16.9
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/CHANGELOG.md +28 -0
- data/ext/oj/dump.c +34 -14
- data/ext/oj/extconf.rb +1 -2
- data/ext/oj/fast.c +3 -3
- data/ext/oj/mimic_json.c +8 -2
- data/ext/oj/oj.c +2 -0
- data/ext/oj/oj.h +1 -0
- data/ext/oj/parse.c +16 -14
- data/ext/oj/parser.c +6 -3
- data/ext/oj/parser.h +2 -2
- data/ext/oj/rails.c +2 -0
- data/ext/oj/reader.c +1 -1
- data/ext/oj/saj.c +2 -2
- data/ext/oj/stream_writer.c +2 -6
- data/ext/oj/string_writer.c +4 -4
- data/ext/oj/usual.c +19 -30
- data/lib/oj/mimic.rb +1 -5
- data/lib/oj/schandler.rb +5 -4
- data/lib/oj/version.rb +1 -1
- data/test/activesupport6/encoding_test.rb +63 -28
- data/test/activesupport7/abstract_unit.rb +4 -1
- data/test/activesupport7/encoding_test.rb +72 -22
- data/test/foo.rb +16 -4
- data/test/test_compat.rb +1 -1
- data/test/test_parser_usual.rb +28 -0
- data/test/test_writer.rb +16 -0
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d3e57c02a1fe6782596953f34b8e2a2b729a09b5d8e7128dd4633d430ca7aa0c
|
4
|
+
data.tar.gz: 7698f8c0203459d62f4421f11a9c3637b04b5b808ecf87ce4ca057e2fd073762
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 417ada5b645a6ba48e81b52bb72cec97bb4a64595a61252989346a975c1026b3cbc039cbf7cef166b5dbfbdd79554d5c9e5786da3299ce1fd3f2ec70d3ef479f
|
7
|
+
data.tar.gz: ceffb29c6732b107d42091bc8754e8b4174e26e6d8eb9c4162ed8a12a65d37aa2450f9f5398d39242d92fabd46d63be5fc14e0dc003774378e4e6211b02e3f0d
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,33 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 3.16.9 - 2024-12-28
|
4
|
+
|
5
|
+
- Fixed `Oj::Parser` create_id size issue #931.
|
6
|
+
|
7
|
+
- Changed parser to be more optimized (PR from @Watson1978)
|
8
|
+
|
9
|
+
## 3.16.8 - 2024-12-14
|
10
|
+
|
11
|
+
- Fixed StreamWriter to write to non-file IO thanks to @jscheid.
|
12
|
+
|
13
|
+
## 3.16.7 - 2024-11-01
|
14
|
+
|
15
|
+
- Changed string_writer_as_json to allow multiple arguments.
|
16
|
+
|
17
|
+
- Fixed Global variable registration added to mimic_json and rails code thanks to @byroot.
|
18
|
+
|
19
|
+
## 3.16.6 - 2024-09-09
|
20
|
+
|
21
|
+
- Fixed issue with Rails 7.2 that changed the order of calls to to_json and as_json.
|
22
|
+
|
23
|
+
## 3.16.5 - 2024-08-07
|
24
|
+
|
25
|
+
- Fixed Oj::Parser so that block procedures work correctly.
|
26
|
+
|
27
|
+
## 3.16.4 - 2024-06-08
|
28
|
+
|
29
|
+
- Fixed Oj::Parse EOF issue on larger stream input.
|
30
|
+
|
3
31
|
## 3.16.3 - 2023-12-11
|
4
32
|
|
5
33
|
- Fixed the gemspec to allow earlier versions of the bigdecimal gem.
|
data/ext/oj/dump.c
CHANGED
@@ -198,7 +198,18 @@ inline static long rails_xss_friendly_size(const uint8_t *str, size_t len) {
|
|
198
198
|
}
|
199
199
|
|
200
200
|
inline static size_t rails_friendly_size(const uint8_t *str, size_t len) {
|
201
|
-
|
201
|
+
long size = 0;
|
202
|
+
size_t i = len;
|
203
|
+
uint8_t hi = 0;
|
204
|
+
|
205
|
+
for (; 0 < i; str++, i--) {
|
206
|
+
size += rails_friendly_chars[*str];
|
207
|
+
hi |= *str & 0x80;
|
208
|
+
}
|
209
|
+
if (0 == hi) {
|
210
|
+
return size - len * (size_t)'0';
|
211
|
+
}
|
212
|
+
return -(size - len * (size_t)'0');
|
202
213
|
}
|
203
214
|
|
204
215
|
const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp) {
|
@@ -750,8 +761,9 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
|
|
750
761
|
void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out) {
|
751
762
|
size_t size;
|
752
763
|
char *cmap;
|
753
|
-
const char *orig
|
754
|
-
bool has_hi
|
764
|
+
const char *orig = str;
|
765
|
+
bool has_hi = false;
|
766
|
+
bool do_unicode_validation = false;
|
755
767
|
|
756
768
|
switch (out->opts->escape_mode) {
|
757
769
|
case NLEsc:
|
@@ -772,8 +784,9 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
772
784
|
size = xss_friendly_size((uint8_t *)str, cnt);
|
773
785
|
break;
|
774
786
|
case JXEsc:
|
775
|
-
cmap
|
776
|
-
size
|
787
|
+
cmap = hixss_friendly_chars;
|
788
|
+
size = hixss_friendly_size((uint8_t *)str, cnt);
|
789
|
+
do_unicode_validation = true;
|
777
790
|
break;
|
778
791
|
case RailsXEsc: {
|
779
792
|
long sz;
|
@@ -786,12 +799,22 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
786
799
|
} else {
|
787
800
|
size = (size_t)sz;
|
788
801
|
}
|
802
|
+
do_unicode_validation = true;
|
789
803
|
break;
|
790
804
|
}
|
791
|
-
case RailsEsc:
|
805
|
+
case RailsEsc: {
|
806
|
+
long sz;
|
792
807
|
cmap = rails_friendly_chars;
|
793
|
-
|
808
|
+
sz = rails_friendly_size((uint8_t *)str, cnt);
|
809
|
+
if (sz < 0) {
|
810
|
+
has_hi = true;
|
811
|
+
size = (size_t)-sz;
|
812
|
+
} else {
|
813
|
+
size = (size_t)sz;
|
814
|
+
}
|
815
|
+
do_unicode_validation = true;
|
794
816
|
break;
|
817
|
+
}
|
795
818
|
case JSONEsc:
|
796
819
|
default: cmap = hibit_friendly_chars; size = hibit_friendly_size((uint8_t *)str, cnt);
|
797
820
|
}
|
@@ -822,7 +845,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
822
845
|
for (; str < end; str++) {
|
823
846
|
switch (cmap[(uint8_t)*str]) {
|
824
847
|
case '1':
|
825
|
-
if (
|
848
|
+
if (do_unicode_validation && check_start <= str) {
|
826
849
|
if (0 != (0x80 & (uint8_t)*str)) {
|
827
850
|
if (0xC0 == (0xC0 & (uint8_t)*str)) {
|
828
851
|
check_start = check_unicode(str, end, orig);
|
@@ -846,8 +869,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
846
869
|
}
|
847
870
|
break;
|
848
871
|
case '3': // Unicode
|
849
|
-
if (0xe2 == (uint8_t)*str &&
|
850
|
-
2 <= end - str) {
|
872
|
+
if (0xe2 == (uint8_t)*str && do_unicode_validation && 2 <= end - str) {
|
851
873
|
if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
852
874
|
str = dump_unicode(str, end, out, orig);
|
853
875
|
} else {
|
@@ -866,8 +888,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
866
888
|
APPEND_CHARS(out->cur, "\\u00", 4);
|
867
889
|
dump_hex((uint8_t)*str, out);
|
868
890
|
} else {
|
869
|
-
if (0xe2 == (uint8_t)*str &&
|
870
|
-
(JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && 2 <= end - str) {
|
891
|
+
if (0xe2 == (uint8_t)*str && do_unicode_validation && 2 <= end - str) {
|
871
892
|
if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
872
893
|
str = dump_unicode(str, end, out, orig);
|
873
894
|
} else {
|
@@ -884,8 +905,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
884
905
|
}
|
885
906
|
*out->cur++ = '"';
|
886
907
|
}
|
887
|
-
if (
|
888
|
-
0 != (0x80 & *(str - 1))) {
|
908
|
+
if (do_unicode_validation && 0 < str - orig && 0 != (0x80 & *(str - 1))) {
|
889
909
|
uint8_t c = (uint8_t) * (str - 1);
|
890
910
|
int i;
|
891
911
|
int scnt = (int)(str - orig);
|
data/ext/oj/extconf.rb
CHANGED
@@ -29,10 +29,9 @@ dflags = {
|
|
29
29
|
have_func('rb_gc_mark_movable')
|
30
30
|
have_func('stpcpy')
|
31
31
|
have_func('pthread_mutex_init')
|
32
|
+
have_func('getrlimit', 'sys/resource.h')
|
32
33
|
have_func('rb_enc_interned_str')
|
33
34
|
have_func('rb_ext_ractor_safe', 'ruby.h')
|
34
|
-
# rb_hash_bulk_insert is deep down in a header not included in normal build and that seems to fool have_func.
|
35
|
-
have_func('rb_hash_bulk_insert', 'ruby.h') unless '2' == version[0] && '6' == version[1]
|
36
35
|
|
37
36
|
dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
|
38
37
|
|
data/ext/oj/fast.c
CHANGED
@@ -40,7 +40,7 @@ typedef struct _doc {
|
|
40
40
|
Leaf *where; // points to current location
|
41
41
|
Leaf where_path[MAX_STACK]; // points to head of path
|
42
42
|
char *json;
|
43
|
-
unsigned long size;
|
43
|
+
unsigned long size; // number of leaves/branches in the doc
|
44
44
|
VALUE self;
|
45
45
|
Batch batches;
|
46
46
|
struct _batch batch0;
|
@@ -573,7 +573,7 @@ static char *read_quoted_value(ParseInfo pi) {
|
|
573
573
|
char *h = pi->s; // head
|
574
574
|
char *t = h; // tail
|
575
575
|
|
576
|
-
h++;
|
576
|
+
h++; // skip quote character
|
577
577
|
t++;
|
578
578
|
value = h;
|
579
579
|
for (; '"' != *h; h++, t++) {
|
@@ -765,7 +765,7 @@ static VALUE parse_json(VALUE clas, char *json, bool given) {
|
|
765
765
|
pi.s = pi.str;
|
766
766
|
doc_init(doc);
|
767
767
|
pi.doc = doc;
|
768
|
-
#if IS_WINDOWS
|
768
|
+
#if IS_WINDOWS || !defined(HAVE_GETRLIMIT)
|
769
769
|
// assume a 1M stack and give half to ruby
|
770
770
|
pi.stack_min = (void *)((char *)&pi - (512L * 1024L));
|
771
771
|
#else
|
data/ext/oj/mimic_json.c
CHANGED
@@ -837,11 +837,15 @@ void oj_mimic_json_methods(VALUE json) {
|
|
837
837
|
} else {
|
838
838
|
json_error = rb_define_class_under(json, "JSONError", rb_eStandardError);
|
839
839
|
}
|
840
|
+
|
841
|
+
rb_global_variable(&oj_json_parser_error_class);
|
840
842
|
if (rb_const_defined_at(json, rb_intern("ParserError"))) {
|
841
843
|
oj_json_parser_error_class = rb_const_get(json, rb_intern("ParserError"));
|
842
844
|
} else {
|
843
845
|
oj_json_parser_error_class = rb_define_class_under(json, "ParserError", json_error);
|
844
846
|
}
|
847
|
+
|
848
|
+
rb_global_variable(&oj_json_generator_error_class);
|
845
849
|
if (rb_const_defined_at(json, rb_intern("GeneratorError"))) {
|
846
850
|
oj_json_generator_error_class = rb_const_get(json, rb_intern("GeneratorError"));
|
847
851
|
} else {
|
@@ -867,8 +871,8 @@ void oj_mimic_json_methods(VALUE json) {
|
|
867
871
|
rb_require("oj/state");
|
868
872
|
}
|
869
873
|
// Pull in the JSON::State mimic file.
|
874
|
+
rb_global_variable(&state_class);
|
870
875
|
state_class = rb_const_get_at(generator, rb_intern("State"));
|
871
|
-
rb_gc_register_mark_object(state_class);
|
872
876
|
}
|
873
877
|
|
874
878
|
/* Document-module: JSON
|
@@ -905,7 +909,9 @@ oj_define_mimic_json(int argc, VALUE *argv, VALUE self) {
|
|
905
909
|
}
|
906
910
|
oj_mimic_json_methods(json);
|
907
911
|
|
908
|
-
|
912
|
+
if (!rb_const_defined(rb_cObject, rb_intern("ActiveSupport"))) {
|
913
|
+
rb_define_method(rb_cObject, "to_json", mimic_object_to_json, -1);
|
914
|
+
}
|
909
915
|
|
910
916
|
rb_gv_set("$VERBOSE", verbose);
|
911
917
|
|
data/ext/oj/oj.c
CHANGED
@@ -36,6 +36,7 @@ ID oj_as_json_id;
|
|
36
36
|
ID oj_begin_id;
|
37
37
|
ID oj_bigdecimal_id;
|
38
38
|
ID oj_end_id;
|
39
|
+
ID oj_eofq_id;
|
39
40
|
ID oj_exclude_end_id;
|
40
41
|
ID oj_error_id;
|
41
42
|
ID oj_file_id;
|
@@ -1849,6 +1850,7 @@ void Init_oj(void) {
|
|
1849
1850
|
oj_begin_id = rb_intern("begin");
|
1850
1851
|
oj_bigdecimal_id = rb_intern("BigDecimal");
|
1851
1852
|
oj_end_id = rb_intern("end");
|
1853
|
+
oj_eofq_id = rb_intern("eof?");
|
1852
1854
|
oj_error_id = rb_intern("error");
|
1853
1855
|
oj_exclude_end_id = rb_intern("exclude_end?");
|
1854
1856
|
oj_file_id = rb_intern("file?");
|
data/ext/oj/oj.h
CHANGED
data/ext/oj/parse.c
CHANGED
@@ -681,7 +681,7 @@ void oj_parse2(ParseInfo pi) {
|
|
681
681
|
pi->cur = pi->json;
|
682
682
|
err_init(&pi->err);
|
683
683
|
while (1) {
|
684
|
-
if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) {
|
684
|
+
if (RB_UNLIKELY(0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1)) {
|
685
685
|
VALUE err_clas = oj_get_json_err_class("NestingError");
|
686
686
|
|
687
687
|
oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested.");
|
@@ -689,18 +689,20 @@ void oj_parse2(ParseInfo pi) {
|
|
689
689
|
return;
|
690
690
|
}
|
691
691
|
next_non_white(pi);
|
692
|
-
if (
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
}
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
692
|
+
if (first) {
|
693
|
+
// If no tokens are consumed (i.e. empty string), throw a parse error
|
694
|
+
// this is the behavior of JSON.parse in both Ruby and JS.
|
695
|
+
if (RB_UNLIKELY('\0' == *pi->cur && No == pi->options.empty_string)) {
|
696
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
697
|
+
}
|
698
|
+
} else {
|
699
|
+
if (RB_UNLIKELY('\0' != *pi->cur)) {
|
700
|
+
oj_set_error_at(pi,
|
701
|
+
oj_parse_error_class,
|
702
|
+
__FILE__,
|
703
|
+
__LINE__,
|
704
|
+
"unexpected characters after the JSON document");
|
705
|
+
}
|
704
706
|
}
|
705
707
|
|
706
708
|
switch (*pi->cur++) {
|
@@ -761,7 +763,7 @@ void oj_parse2(ParseInfo pi) {
|
|
761
763
|
case '\0': pi->cur--; return;
|
762
764
|
default: oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); return;
|
763
765
|
}
|
764
|
-
if (err_has(&pi->err)) {
|
766
|
+
if (RB_UNLIKELY(err_has(&pi->err))) {
|
765
767
|
return;
|
766
768
|
}
|
767
769
|
if (stack_empty(&pi->stack)) {
|
data/ext/oj/parser.c
CHANGED
@@ -1114,9 +1114,6 @@ static void parse(ojParser p, const byte *json) {
|
|
1114
1114
|
p->map = trail_map;
|
1115
1115
|
}
|
1116
1116
|
}
|
1117
|
-
if (0 < p->depth) {
|
1118
|
-
parse_error(p, "parse error, not closed");
|
1119
|
-
}
|
1120
1117
|
if (0 == p->depth) {
|
1121
1118
|
switch (p->map[256]) {
|
1122
1119
|
case '0':
|
@@ -1394,6 +1391,12 @@ static VALUE load(VALUE self) {
|
|
1394
1391
|
if (0 < RSTRING_LEN(rbuf)) {
|
1395
1392
|
parse(p, (byte *)StringValuePtr(rbuf));
|
1396
1393
|
}
|
1394
|
+
if (Qtrue == rb_funcall(p->reader, oj_eofq_id, 0)) {
|
1395
|
+
if (0 < p->depth) {
|
1396
|
+
parse_error(p, "parse error, not closed");
|
1397
|
+
}
|
1398
|
+
break;
|
1399
|
+
}
|
1397
1400
|
}
|
1398
1401
|
return Qtrue;
|
1399
1402
|
}
|
data/ext/oj/parser.h
CHANGED
@@ -32,9 +32,9 @@ typedef struct _num {
|
|
32
32
|
long double dub;
|
33
33
|
int64_t fixnum; // holds all digits
|
34
34
|
uint32_t len;
|
35
|
-
int16_t div;
|
35
|
+
int16_t div; // 10^div
|
36
36
|
int16_t exp;
|
37
|
-
uint8_t shift;
|
37
|
+
uint8_t shift; // shift of fixnum to get decimal
|
38
38
|
bool neg;
|
39
39
|
bool exp_neg;
|
40
40
|
// for numbers as strings, reuse buf
|
data/ext/oj/rails.c
CHANGED
@@ -1101,6 +1101,8 @@ static VALUE rails_set_decoder(VALUE self) {
|
|
1101
1101
|
} else {
|
1102
1102
|
json_error = rb_define_class_under(json, "JSONError", rb_eStandardError);
|
1103
1103
|
}
|
1104
|
+
|
1105
|
+
rb_global_variable(&oj_json_parser_error_class);
|
1104
1106
|
if (rb_const_defined_at(json, rb_intern("ParserError"))) {
|
1105
1107
|
oj_json_parser_error_class = rb_const_get(json, rb_intern("ParserError"));
|
1106
1108
|
} else {
|
data/ext/oj/reader.c
CHANGED
@@ -101,7 +101,7 @@ int oj_reader_read(Reader reader) {
|
|
101
101
|
} else {
|
102
102
|
shift = reader->pro - reader->head - 1; // leave one character so we can backup one
|
103
103
|
}
|
104
|
-
if (0 >= shift) {
|
104
|
+
if (0 >= shift) { /* no space left so allocate more */
|
105
105
|
const char *old = reader->head;
|
106
106
|
size_t size = reader->end - reader->head + BUF_PAD;
|
107
107
|
|
data/ext/oj/saj.c
CHANGED
@@ -578,7 +578,7 @@ static void saj_parse(VALUE handler, char *json) {
|
|
578
578
|
/* initialize parse info */
|
579
579
|
pi.str = json;
|
580
580
|
pi.s = json;
|
581
|
-
#if IS_WINDOWS
|
581
|
+
#if IS_WINDOWS || !defined(HAVE_GETRLIMIT)
|
582
582
|
pi.stack_min = (void *)((char *)&obj - (512L * 1024L)); /* assume a 1M stack and give half to ruby */
|
583
583
|
#else
|
584
584
|
{
|
@@ -587,7 +587,7 @@ static void saj_parse(VALUE handler, char *json) {
|
|
587
587
|
if (0 == getrlimit(RLIMIT_STACK, &lim) && RLIM_INFINITY != lim.rlim_cur) {
|
588
588
|
pi.stack_min = (void *)((char *)&obj - (lim.rlim_cur / 4 * 3)); /* let 3/4ths of the stack be used only */
|
589
589
|
} else {
|
590
|
-
pi.stack_min = 0;
|
590
|
+
pi.stack_min = 0; /* indicates not to check stack limit */
|
591
591
|
}
|
592
592
|
}
|
593
593
|
#endif
|
data/ext/oj/stream_writer.c
CHANGED
@@ -42,7 +42,8 @@ static void stream_writer_write(StreamWriter sw) {
|
|
42
42
|
|
43
43
|
switch (sw->type) {
|
44
44
|
case STRING_IO:
|
45
|
-
case STREAM_IO:
|
45
|
+
case STREAM_IO:
|
46
|
+
case FILE_IO: {
|
46
47
|
volatile VALUE rs = rb_str_new(sw->sw.out.buf, size);
|
47
48
|
|
48
49
|
// Oddly enough, when pushing ASCII characters with UTF-8 encoding or
|
@@ -53,11 +54,6 @@ static void stream_writer_write(StreamWriter sw) {
|
|
53
54
|
rb_funcall(sw->stream, oj_write_id, 1, rs);
|
54
55
|
break;
|
55
56
|
}
|
56
|
-
case FILE_IO:
|
57
|
-
if (size != write(sw->fd, sw->sw.out.buf, size)) {
|
58
|
-
rb_raise(rb_eIOError, "Write failed. [_%d_:%s]\n", errno, strerror(errno));
|
59
|
-
}
|
60
|
-
break;
|
61
57
|
default: rb_raise(rb_eArgError, "expected an IO Object.");
|
62
58
|
}
|
63
59
|
stream_writer_reset_buf(sw);
|
data/ext/oj/string_writer.c
CHANGED
@@ -475,16 +475,16 @@ static VALUE str_writer_to_s(VALUE self) {
|
|
475
475
|
}
|
476
476
|
|
477
477
|
/* Document-method: as_json
|
478
|
-
* call-seq: as_json()
|
478
|
+
* call-seq: as_json(*)
|
479
479
|
*
|
480
480
|
* Returns the contents of the writer as a JSON element. If called from inside
|
481
481
|
* an array or hash by Oj the raw buffer will be used othersize a more
|
482
482
|
* inefficient parse of the contents and a return of the result is
|
483
|
-
* completed. The parse uses the strict mode.
|
483
|
+
* completed. The parse uses the strict mode. Optional arguments are ignored.
|
484
484
|
*
|
485
485
|
* *return* [_Hash_|_Array_|_String_|_Integer_|_Float_|_True_|_False_|_nil|)
|
486
486
|
*/
|
487
|
-
static VALUE str_writer_as_json(VALUE self) {
|
487
|
+
static VALUE str_writer_as_json(int argc, VALUE *argv, VALUE self) {
|
488
488
|
if (string_writer_optimized) {
|
489
489
|
return self;
|
490
490
|
}
|
@@ -515,5 +515,5 @@ void oj_string_writer_init(void) {
|
|
515
515
|
rb_define_method(oj_string_writer_class, "reset", str_writer_reset, 0);
|
516
516
|
rb_define_method(oj_string_writer_class, "to_s", str_writer_to_s, 0);
|
517
517
|
rb_define_method(oj_string_writer_class, "raw_json", str_writer_to_s, 0);
|
518
|
-
rb_define_method(oj_string_writer_class, "as_json", str_writer_as_json,
|
518
|
+
rb_define_method(oj_string_writer_class, "as_json", str_writer_as_json, -1);
|
519
519
|
}
|
data/ext/oj/usual.c
CHANGED
@@ -281,7 +281,6 @@ static void close_object(ojParser p) {
|
|
281
281
|
VALUE *head = d->vhead + c->vi + 1;
|
282
282
|
volatile VALUE obj = rb_hash_new();
|
283
283
|
|
284
|
-
#if HAVE_RB_HASH_BULK_INSERT
|
285
284
|
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
286
285
|
*vp = d->get_key(p, kp);
|
287
286
|
if (sizeof(kp->buf) <= (size_t)kp->len) {
|
@@ -289,18 +288,15 @@ static void close_object(ojParser p) {
|
|
289
288
|
}
|
290
289
|
}
|
291
290
|
rb_hash_bulk_insert(d->vtail - head, head, obj);
|
292
|
-
#else
|
293
|
-
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
294
|
-
rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
|
295
|
-
if (sizeof(kp->buf) <= (size_t)kp->len) {
|
296
|
-
OJ_R_FREE(kp->key);
|
297
|
-
}
|
298
|
-
}
|
299
|
-
#endif
|
300
291
|
d->ktail = d->khead + c->ki;
|
292
|
+
|
301
293
|
d->vtail = head;
|
302
294
|
head--;
|
303
295
|
*head = obj;
|
296
|
+
if (1 == d->vtail - d->vhead && rb_block_given_p()) {
|
297
|
+
d->vtail = d->vhead;
|
298
|
+
rb_yield(obj);
|
299
|
+
}
|
304
300
|
}
|
305
301
|
|
306
302
|
static void close_object_class(ojParser p) {
|
@@ -341,7 +337,6 @@ static void close_object_create(ojParser p) {
|
|
341
337
|
head++;
|
342
338
|
if (Qnil == d->hash_class) {
|
343
339
|
obj = rb_hash_new();
|
344
|
-
#if HAVE_RB_HASH_BULK_INSERT
|
345
340
|
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
346
341
|
*vp = d->get_key(p, kp);
|
347
342
|
if (sizeof(kp->buf) <= (size_t)kp->len) {
|
@@ -349,14 +344,6 @@ static void close_object_create(ojParser p) {
|
|
349
344
|
}
|
350
345
|
}
|
351
346
|
rb_hash_bulk_insert(d->vtail - head, head, obj);
|
352
|
-
#else
|
353
|
-
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
354
|
-
rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
|
355
|
-
if (sizeof(kp->buf) <= (size_t)kp->len) {
|
356
|
-
OJ_R_FREE(kp->key);
|
357
|
-
}
|
358
|
-
}
|
359
|
-
#endif
|
360
347
|
} else {
|
361
348
|
obj = rb_class_new_instance(0, NULL, d->hash_class);
|
362
349
|
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
@@ -373,7 +360,6 @@ static void close_object_create(ojParser p) {
|
|
373
360
|
if (!d->ignore_json_create && rb_respond_to(clas, oj_json_create_id)) {
|
374
361
|
volatile VALUE arg = rb_hash_new();
|
375
362
|
|
376
|
-
#if HAVE_RB_HASH_BULK_INSERT
|
377
363
|
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
378
364
|
*vp = d->get_key(p, kp);
|
379
365
|
if (sizeof(kp->buf) <= (size_t)kp->len) {
|
@@ -381,14 +367,6 @@ static void close_object_create(ojParser p) {
|
|
381
367
|
}
|
382
368
|
}
|
383
369
|
rb_hash_bulk_insert(d->vtail - head, head, arg);
|
384
|
-
#else
|
385
|
-
for (vp = head; kp < d->ktail; kp++, vp += 2) {
|
386
|
-
rb_hash_aset(arg, d->get_key(p, kp), *(vp + 1));
|
387
|
-
if (sizeof(kp->buf) <= (size_t)kp->len) {
|
388
|
-
OJ_R_FREE(kp->key);
|
389
|
-
}
|
390
|
-
}
|
391
|
-
#endif
|
392
370
|
obj = rb_funcall(clas, oj_json_create_id, 1, arg);
|
393
371
|
} else {
|
394
372
|
obj = rb_class_new_instance(0, NULL, clas);
|
@@ -599,7 +577,18 @@ static VALUE result(ojParser p) {
|
|
599
577
|
Usual d = (Usual)p->ctx;
|
600
578
|
|
601
579
|
if (d->vhead < d->vtail) {
|
602
|
-
|
580
|
+
long cnt = d->vtail - d->vhead;
|
581
|
+
volatile VALUE ary;
|
582
|
+
volatile VALUE *vp;
|
583
|
+
|
584
|
+
if (1 == cnt) {
|
585
|
+
return *d->vhead;
|
586
|
+
}
|
587
|
+
ary = rb_ary_new();
|
588
|
+
for (vp = d->vhead; vp < d->vtail; vp++) {
|
589
|
+
rb_ary_push(ary, *vp);
|
590
|
+
}
|
591
|
+
return ary;
|
603
592
|
}
|
604
593
|
if (d->raise_on_empty) {
|
605
594
|
rb_raise(oj_parse_error_class, "empty string");
|
@@ -845,8 +834,8 @@ static VALUE opt_create_id_set(ojParser p, VALUE value) {
|
|
845
834
|
rb_check_type(value, T_STRING);
|
846
835
|
size_t len = RSTRING_LEN(value);
|
847
836
|
|
848
|
-
if (1 << sizeof(d->create_id_len) <= len) {
|
849
|
-
rb_raise(rb_eArgError, "The create_id values is limited to %d bytes.", 1 << sizeof(d->create_id_len));
|
837
|
+
if (1 << (8 * sizeof(d->create_id_len)) <= len) {
|
838
|
+
rb_raise(rb_eArgError, "The create_id values is limited to %d bytes.", 1 << (8 * sizeof(d->create_id_len)));
|
850
839
|
}
|
851
840
|
d->create_id_len = (uint8_t)len;
|
852
841
|
d->create_id = str_dup(RSTRING_PTR(value), len);
|
data/lib/oj/mimic.rb
CHANGED
data/lib/oj/schandler.rb
CHANGED
@@ -64,13 +64,14 @@ module Oj
|
|
64
64
|
#
|
65
65
|
# hash_end
|
66
66
|
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
# the key-value pair that follows.
|
67
|
+
# At the end of a JSON object element the hash_end() callback is called if
|
68
|
+
# public.
|
70
69
|
#
|
71
70
|
# hash_key
|
72
71
|
#
|
73
|
-
#
|
72
|
+
# When a hash key is encountered the hash_key() method is called with the
|
73
|
+
# parsed hash value key. The return value from the call is then used as the
|
74
|
+
# key in the key-value pair that follows.
|
74
75
|
#
|
75
76
|
# hash_set
|
76
77
|
#
|
data/lib/oj/version.rb
CHANGED
@@ -74,42 +74,77 @@ class TestJSONEncoding < ActiveSupport::TestCase
|
|
74
74
|
ActiveSupport.escape_html_entities_in_json = false
|
75
75
|
end
|
76
76
|
|
77
|
-
def
|
78
|
-
|
79
|
-
# ActiveSupport.escape_html_entities_in_json reverts to true even after
|
80
|
-
# being set to false. I haven't been able to figure that out so the value is
|
81
|
-
# set to true, the default, before running the test. This might be wrong but
|
82
|
-
# for now it will have to do.
|
83
|
-
ActiveSupport.escape_html_entities_in_json = true
|
84
|
-
result = ActiveSupport::JSON.encode("€2.99")
|
85
|
-
assert_equal '"€2.99"', result
|
86
|
-
assert_equal(Encoding::UTF_8, result.encoding)
|
87
|
-
|
88
|
-
result = ActiveSupport::JSON.encode("✎☺")
|
89
|
-
assert_equal '"✎☺"', result
|
90
|
-
assert_equal(Encoding::UTF_8, result.encoding)
|
77
|
+
def test_hash_keys_encoding_without_escaping
|
78
|
+
assert_equal "{\"<>\":\"<>\"}", ActiveSupport::JSON.encode("<>" => "<>")
|
91
79
|
end
|
92
80
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
81
|
+
module UnicodeTests
|
82
|
+
def test_utf8_string_encoded_properly
|
83
|
+
result = ActiveSupport::JSON.encode("€2.99")
|
84
|
+
assert_equal '"€2.99"', result
|
85
|
+
assert_equal(Encoding::UTF_8, result.encoding)
|
86
|
+
|
87
|
+
result = ActiveSupport::JSON.encode("✎☺")
|
88
|
+
assert_equal '"✎☺"', result
|
89
|
+
assert_equal(Encoding::UTF_8, result.encoding)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_non_utf8_string_transcodes
|
93
|
+
s = "二".encode("Shift_JIS")
|
94
|
+
result = ActiveSupport::JSON.encode(s)
|
95
|
+
assert_equal '"二"', result
|
96
|
+
assert_equal Encoding::UTF_8, result.encoding
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_wide_utf8_chars
|
100
|
+
w = "𠜎"
|
101
|
+
result = ActiveSupport::JSON.encode(w)
|
102
|
+
assert_equal '"𠜎"', result
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_wide_utf8_roundtrip
|
106
|
+
hash = { string: "𐒑" }
|
107
|
+
json = ActiveSupport::JSON.encode(hash)
|
108
|
+
decoded_hash = ActiveSupport::JSON.decode(json)
|
109
|
+
assert_equal "𐒑", decoded_hash["string"]
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_invalid_encoding_raises
|
113
|
+
s = "\xAE\xFF\x9F"
|
114
|
+
refute s.valid_encoding?
|
115
|
+
|
116
|
+
# n.b. this raises EncodingError, because we didn't call Oj.mimic_JSON in the test setup; but,
|
117
|
+
# if you do that (even indirectly through Oj.optimize_rails), then this raises a
|
118
|
+
# JSON::GeneratorError instead of an EncodingError.
|
119
|
+
assert_raises(EncodingError) do
|
120
|
+
ActiveSupport::JSON.encode([s])
|
121
|
+
end
|
122
|
+
end
|
98
123
|
end
|
99
124
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
125
|
+
module UnicodeTestsWithEscapingOn
|
126
|
+
def setup
|
127
|
+
ActiveSupport.escape_html_entities_in_json = true
|
128
|
+
end
|
129
|
+
|
130
|
+
def teardown
|
131
|
+
ActiveSupport.escape_html_entities_in_json = false
|
132
|
+
end
|
133
|
+
|
134
|
+
include UnicodeTests
|
104
135
|
end
|
105
136
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
137
|
+
module UnicodeTestsWithEscapingOff
|
138
|
+
def setup
|
139
|
+
ActiveSupport.escape_html_entities_in_json = false
|
140
|
+
end
|
141
|
+
|
142
|
+
include UnicodeTests
|
111
143
|
end
|
112
144
|
|
145
|
+
include UnicodeTestsWithEscapingOn
|
146
|
+
include UnicodeTestsWithEscapingOff
|
147
|
+
|
113
148
|
def test_hash_key_identifiers_are_always_quoted
|
114
149
|
values = { 0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B" }
|
115
150
|
assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(ActiveSupport::JSON.encode(values))
|
@@ -19,7 +19,10 @@ require "active_support"
|
|
19
19
|
Thread.abort_on_exception = true
|
20
20
|
|
21
21
|
# Show backtraces for deprecated behavior for quicker cleanup.
|
22
|
-
ActiveSupport::Deprecation.debug
|
22
|
+
if ActiveSupport::Deprecation.respond_to?(:debug)
|
23
|
+
# Rails 7.2 does not have ActiveSupport::Deprecation.debug
|
24
|
+
ActiveSupport::Deprecation.debug = true
|
25
|
+
end
|
23
26
|
|
24
27
|
# Default to old to_time behavior but allow running tests with new behavior
|
25
28
|
ActiveSupport.to_time_preserves_timezone = ENV["PRESERVE_TIMEZONES"] == "1"
|
@@ -8,9 +8,18 @@ require "active_support/time"
|
|
8
8
|
require_relative "time_zone_test_helpers"
|
9
9
|
require_relative "encoding_test_cases"
|
10
10
|
|
11
|
+
require 'oj'
|
12
|
+
# Sets the ActiveSupport encoder to be Oj and also wraps the setting of globals.
|
13
|
+
Oj::Rails.set_encoder()
|
14
|
+
Oj::Rails.optimize()
|
15
|
+
|
11
16
|
class TestJSONEncoding < ActiveSupport::TestCase
|
12
17
|
include TimeZoneTestHelpers
|
13
18
|
|
19
|
+
def test_is_actually_oj
|
20
|
+
assert_equal Oj::Rails::Encoder, ActiveSupport.json_encoder
|
21
|
+
end
|
22
|
+
|
14
23
|
def sorted_json(json)
|
15
24
|
if json.start_with?("{") && json.end_with?("}")
|
16
25
|
"{" + json[1..-2].split(",").sort.join(",") + "}"
|
@@ -61,36 +70,77 @@ class TestJSONEncoding < ActiveSupport::TestCase
|
|
61
70
|
ActiveSupport.escape_html_entities_in_json = false
|
62
71
|
end
|
63
72
|
|
64
|
-
def
|
65
|
-
|
66
|
-
assert_equal '"€2.99"', result
|
67
|
-
assert_equal(Encoding::UTF_8, result.encoding)
|
68
|
-
|
69
|
-
result = ActiveSupport::JSON.encode("✎☺")
|
70
|
-
assert_equal '"✎☺"', result
|
71
|
-
assert_equal(Encoding::UTF_8, result.encoding)
|
73
|
+
def test_hash_keys_encoding_without_escaping
|
74
|
+
assert_equal "{\"<>\":\"<>\"}", ActiveSupport::JSON.encode("<>" => "<>")
|
72
75
|
end
|
73
76
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
77
|
+
module UnicodeTests
|
78
|
+
def test_utf8_string_encoded_properly
|
79
|
+
result = ActiveSupport::JSON.encode("€2.99")
|
80
|
+
assert_equal '"€2.99"', result
|
81
|
+
assert_equal(Encoding::UTF_8, result.encoding)
|
82
|
+
|
83
|
+
result = ActiveSupport::JSON.encode("✎☺")
|
84
|
+
assert_equal '"✎☺"', result
|
85
|
+
assert_equal(Encoding::UTF_8, result.encoding)
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_non_utf8_string_transcodes
|
89
|
+
s = "二".encode("Shift_JIS")
|
90
|
+
result = ActiveSupport::JSON.encode(s)
|
91
|
+
assert_equal '"二"', result
|
92
|
+
assert_equal Encoding::UTF_8, result.encoding
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_wide_utf8_chars
|
96
|
+
w = "𠜎"
|
97
|
+
result = ActiveSupport::JSON.encode(w)
|
98
|
+
assert_equal '"𠜎"', result
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_wide_utf8_roundtrip
|
102
|
+
hash = { string: "𐒑" }
|
103
|
+
json = ActiveSupport::JSON.encode(hash)
|
104
|
+
decoded_hash = ActiveSupport::JSON.decode(json)
|
105
|
+
assert_equal "𐒑", decoded_hash["string"]
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_invalid_encoding_raises
|
109
|
+
s = "\xAE\xFF\x9F"
|
110
|
+
refute s.valid_encoding?
|
111
|
+
|
112
|
+
# n.b. this raises EncodingError, because we didn't call Oj.mimic_JSON in the test setup; but,
|
113
|
+
# if you do that (even indirectly through Oj.optimize_rails), then this raises a
|
114
|
+
# JSON::GeneratorError instead of an EncodingError.
|
115
|
+
assert_raises(EncodingError) do
|
116
|
+
ActiveSupport::JSON.encode([s])
|
117
|
+
end
|
118
|
+
end
|
79
119
|
end
|
80
120
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
121
|
+
module UnicodeTestsWithEscapingOn
|
122
|
+
def setup
|
123
|
+
ActiveSupport.escape_html_entities_in_json = true
|
124
|
+
end
|
125
|
+
|
126
|
+
def teardown
|
127
|
+
ActiveSupport.escape_html_entities_in_json = false
|
128
|
+
end
|
129
|
+
|
130
|
+
include UnicodeTests
|
85
131
|
end
|
86
132
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
133
|
+
module UnicodeTestsWithEscapingOff
|
134
|
+
def setup
|
135
|
+
ActiveSupport.escape_html_entities_in_json = false
|
136
|
+
end
|
137
|
+
|
138
|
+
include UnicodeTests
|
92
139
|
end
|
93
140
|
|
141
|
+
include UnicodeTestsWithEscapingOn
|
142
|
+
include UnicodeTestsWithEscapingOff
|
143
|
+
|
94
144
|
def test_hash_key_identifiers_are_always_quoted
|
95
145
|
values = { 0 => 0, 1 => 1, :_ => :_, "$" => "$", "a" => "a", :A => :A, :A0 => :A0, "A0B" => "A0B" }
|
96
146
|
assert_equal %w( "$" "A" "A0" "A0B" "_" "a" "0" "1" ).sort, object_keys(ActiveSupport::JSON.encode(values))
|
data/test/foo.rb
CHANGED
@@ -5,10 +5,22 @@ $LOAD_PATH << '.'
|
|
5
5
|
$LOAD_PATH << File.join(__dir__, '../lib')
|
6
6
|
$LOAD_PATH << File.join(__dir__, '../ext')
|
7
7
|
|
8
|
-
require 'json'
|
9
8
|
require 'oj'
|
10
|
-
require 'oj/json'
|
11
9
|
|
12
|
-
|
10
|
+
reader, writer = IO.pipe
|
13
11
|
|
14
|
-
|
12
|
+
thread =
|
13
|
+
Thread.new do
|
14
|
+
5.times do |id|
|
15
|
+
Oj.to_stream(writer, { "id" => id })
|
16
|
+
sleep(1)
|
17
|
+
end
|
18
|
+
|
19
|
+
writer.close
|
20
|
+
end
|
21
|
+
|
22
|
+
p = Oj::Parser.new(:usual)
|
23
|
+
p.load(reader) { |data| puts "#{Time.now} -- ID: #{data["id"]}" }
|
24
|
+
|
25
|
+
reader.close
|
26
|
+
thread.join
|
data/test/test_compat.rb
CHANGED
@@ -468,7 +468,7 @@ class CompatJuice < Minitest::Test
|
|
468
468
|
|
469
469
|
def test_arg_passing
|
470
470
|
json = Oj.to_json(Argy.new(), :max_nesting => 40)
|
471
|
-
|
471
|
+
assert_match(/.*max_nesting.*40.*/, json)
|
472
472
|
end
|
473
473
|
|
474
474
|
def test_max_nesting
|
data/test/test_parser_usual.rb
CHANGED
@@ -114,6 +114,30 @@ class UsualTest < Minitest::Test
|
|
114
114
|
assert_equal(Float, doc.class)
|
115
115
|
end
|
116
116
|
|
117
|
+
def test_multi_parse
|
118
|
+
p = Oj::Parser.new(:usual)
|
119
|
+
out = []
|
120
|
+
p.parse('{"a":1}{"b":{"x":2}} {"c":3}') { |j| out.push(j) }
|
121
|
+
assert_equal([{'a'=>1}, {'b'=>{'x'=>2}},{'c'=>3}], out)
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_multi_load
|
125
|
+
p = Oj::Parser.new(:usual)
|
126
|
+
out = []
|
127
|
+
r, w = IO.pipe
|
128
|
+
thread = Thread.new do
|
129
|
+
['{"a":1}', '{"b":{"x"', ':2}}{"c":', '3}'].each { |seg|
|
130
|
+
w.write(seg)
|
131
|
+
sleep(0.1)
|
132
|
+
}
|
133
|
+
w.close
|
134
|
+
end
|
135
|
+
p.load(r) { |j| out.push(j) }
|
136
|
+
r.close
|
137
|
+
thread.join
|
138
|
+
assert_equal([{'a'=>1}, {'b'=>{'x'=>2}},{'c'=>3}], out)
|
139
|
+
end
|
140
|
+
|
117
141
|
def test_omit_null
|
118
142
|
p = Oj::Parser.new(:usual)
|
119
143
|
p.omit_null = true
|
@@ -193,6 +217,10 @@ class UsualTest < Minitest::Test
|
|
193
217
|
|
194
218
|
doc = p.parse('{"a":true,"^":"UsualTest::MyClass","b":false}')
|
195
219
|
assert_equal('UsualTest::MyClass{a: true b: false}', doc.to_s)
|
220
|
+
|
221
|
+
p.create_id = 'class'
|
222
|
+
doc = p.parse('{"a":true,"class":"UsualTest::MyClass","b":false}')
|
223
|
+
assert_equal('UsualTest::MyClass{a: true b: false}', doc.to_s)
|
196
224
|
end
|
197
225
|
|
198
226
|
def test_missing_class
|
data/test/test_writer.rb
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
$LOAD_PATH << __dir__
|
5
5
|
|
6
6
|
require 'helper'
|
7
|
+
require 'open3'
|
7
8
|
|
8
9
|
class OjWriter < Minitest::Test
|
9
10
|
|
@@ -377,4 +378,19 @@ class OjWriter < Minitest::Test
|
|
377
378
|
w.pop()
|
378
379
|
assert_equal(%|{"nothing":null}\n|, output.string())
|
379
380
|
end
|
381
|
+
|
382
|
+
def test_stream_writer_subprocess
|
383
|
+
skip if RbConfig::CONFIG['host_os'] =~ /(mingw|mswin)/
|
384
|
+
|
385
|
+
Open3.popen3("/bin/bash", "-c", "cat > /dev/null") do |stdin, _stdout, _stderr, _wait_thr|
|
386
|
+
w = Oj::StreamWriter.new(stdin, :indent => 0)
|
387
|
+
w.push_array()
|
388
|
+
chunk = "{\"foo\":\"#{"bar"*1000}\"}"
|
389
|
+
1000.times do |_|
|
390
|
+
w.push_json(chunk)
|
391
|
+
end
|
392
|
+
w.pop()
|
393
|
+
stdin.close
|
394
|
+
end
|
395
|
+
end
|
380
396
|
end # OjWriter
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oj
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.16.
|
4
|
+
version: 3.16.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Ohler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bigdecimal
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: ostruct
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.2'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: minitest
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -308,7 +322,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
308
322
|
- !ruby/object:Gem::Version
|
309
323
|
version: '0'
|
310
324
|
requirements: []
|
311
|
-
rubygems_version: 3.
|
325
|
+
rubygems_version: 3.5.11
|
312
326
|
signing_key:
|
313
327
|
specification_version: 4
|
314
328
|
summary: A fast JSON parser and serializer.
|