oj 3.13.5 → 3.13.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 +32 -0
- data/RELEASE_NOTES.md +6 -0
- data/ext/oj/fast.c +6 -2
- data/ext/oj/intern.c +7 -1
- data/ext/oj/mimic_json.c +5 -15
- data/ext/oj/object.c +26 -45
- data/ext/oj/oj.c +108 -152
- data/ext/oj/oj.h +1 -0
- data/ext/oj/parse.c +9 -1
- data/ext/oj/parser.c +76 -28
- data/ext/oj/usual.c +19 -17
- data/lib/oj/version.rb +1 -1
- data/test/bar.rb +9 -28
- data/test/bug.rb +16 -0
- data/test/foo.rb +16 -9
- data/test/test_fast.rb +18 -7
- data/test/test_parser_usual.rb +9 -5
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 646e1253e68f33e284b1efa4ec5f6c3ad9de2e52a1f4ddfbb37435ceb5e23bd0
|
4
|
+
data.tar.gz: 775d9f0169d77a6f06990cf0d1f0e1904a530567d0939471f326e7ec5ee24c37
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f15a8a5dabfece0fb92ebfd2be99d567890441a2774c361646fc0ab03eba1de0070106cdc0addcc6fa75cf797dcd568b2f0129954c5debbe9ffa334ea8aa7fc4
|
7
|
+
data.tar.gz: 9d3d0d399610c5209a6819df7583368c14250311249ff3f42a67c868057b96fb8f89c12657aeaf36f1ef545793038aece84f8a7524f40f77ed8636fe6d9e09f5
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,37 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
|
4
|
+
## 3.13.9 - 2021-10-06
|
5
|
+
|
6
|
+
- Fix mimic JSON load so that it honors the `:symbolize_names` option.
|
7
|
+
|
8
|
+
## 3.13.8 - 2021-09-27
|
9
|
+
|
10
|
+
- Fix `Oj::Doc` behaviour for inexisting path.
|
11
|
+
```ruby
|
12
|
+
Oj::Doc.open('{"foo":1}') do |doc|
|
13
|
+
doc.fetch('/foo/bar') # used to give `1`, now gives `nil`
|
14
|
+
doc.exists?('/foo/bar') # used to give `true`, now gives `false`
|
15
|
+
end
|
16
|
+
```
|
17
|
+
|
18
|
+
- Fix `Oj::Parser` handling of BigDecimal. `snprint()` does not handle `%Lg` correctly but `sprintf()` does.
|
19
|
+
|
20
|
+
## 3.13.7 - 2021-09-16
|
21
|
+
|
22
|
+
- The JSON gem allows invalid unicode so Oj, when mimicing JSON now
|
23
|
+
allows it as well. Use `:allow_invalid_unicode` to change that.
|
24
|
+
|
25
|
+
## 3.13.6 - 2021-09-11
|
26
|
+
|
27
|
+
- Fixed unicode UTF 8 parsing in string values.
|
28
|
+
|
29
|
+
- Fixed hash key allocation issue.
|
30
|
+
|
31
|
+
- The `Oj::Parser.new()` function now allows optional arguments that
|
32
|
+
set the allowed options for the mode. As an example
|
33
|
+
`Oj::Parser.new(:usual, cache_keys: true)`.
|
34
|
+
|
3
35
|
## 3.13.5 - 2021-09-08
|
4
36
|
|
5
37
|
- Assure value strings of zero length are not always cached.
|
data/RELEASE_NOTES.md
CHANGED
@@ -5,6 +5,12 @@ see the See [{file:CHANGELOG.md}](CHANGELOG.md) file. In this file are
|
|
5
5
|
the steps to take to aid in keeping things rolling after updating to
|
6
6
|
the latest version.
|
7
7
|
|
8
|
+
## 3.13.7
|
9
|
+
|
10
|
+
The default for JSON when mimicked by Oj is now to set
|
11
|
+
`:allow_invalid_unicode`. To change that behavior JSON.load, set that
|
12
|
+
option to false.
|
13
|
+
|
8
14
|
## 3.13.x
|
9
15
|
|
10
16
|
This release included a new cache that performs better than the
|
data/ext/oj/fast.c
CHANGED
@@ -879,6 +879,10 @@ static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path) {
|
|
879
879
|
}
|
880
880
|
} else if (NULL == leaf->elements) {
|
881
881
|
leaf = NULL;
|
882
|
+
} else if (STR_VAL == leaf->value_type || RUBY_VAL == leaf->value_type) {
|
883
|
+
// We are trying to get a children of a leaf, which
|
884
|
+
// doesn't exist.
|
885
|
+
leaf = NULL;
|
882
886
|
} else if (COL_VAL == leaf->value_type) {
|
883
887
|
Leaf first = leaf->elements->next;
|
884
888
|
Leaf e = first;
|
@@ -1373,8 +1377,8 @@ static VALUE doc_fetch(int argc, VALUE *argv, VALUE self) {
|
|
1373
1377
|
* Returns true if the value at the location identified by the path exists.
|
1374
1378
|
* @param [String] path path to the location
|
1375
1379
|
* @example
|
1376
|
-
* Oj::Doc.open('[1,2]') { |doc| doc.exists('/1') } #=> true
|
1377
|
-
* Oj::Doc.open('[1,2]') { |doc| doc.exists('/3') } #=> false
|
1380
|
+
* Oj::Doc.open('[1,2]') { |doc| doc.exists?('/1') } #=> true
|
1381
|
+
* Oj::Doc.open('[1,2]') { |doc| doc.exists?('/3') } #=> false
|
1378
1382
|
*/
|
1379
1383
|
static VALUE doc_exists(VALUE self, VALUE str) {
|
1380
1384
|
Doc doc;
|
data/ext/oj/intern.c
CHANGED
@@ -186,6 +186,7 @@ static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int a
|
|
186
186
|
char * end = class_name + sizeof(class_name) - 1;
|
187
187
|
char * s;
|
188
188
|
const char *n = name;
|
189
|
+
size_t nlen = len;
|
189
190
|
|
190
191
|
clas = rb_cObject;
|
191
192
|
for (s = class_name; 0 < len; n++, len--) {
|
@@ -208,7 +209,12 @@ static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int a
|
|
208
209
|
}
|
209
210
|
*s = '\0';
|
210
211
|
if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
|
211
|
-
|
212
|
+
if (sizeof(class_name) <= nlen) {
|
213
|
+
nlen = sizeof(class_name) - 1;
|
214
|
+
}
|
215
|
+
strncpy(class_name, name, nlen);
|
216
|
+
class_name[nlen] = '\0';
|
217
|
+
oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class '%s' is not defined", class_name);
|
212
218
|
if (Qnil != error_class) {
|
213
219
|
pi->err_class = error_class;
|
214
220
|
}
|
data/ext/oj/mimic_json.c
CHANGED
@@ -6,8 +6,6 @@
|
|
6
6
|
#include "oj.h"
|
7
7
|
#include "parse.h"
|
8
8
|
|
9
|
-
static VALUE symbolize_names_sym = Qundef;
|
10
|
-
|
11
9
|
extern const char oj_json_class[];
|
12
10
|
|
13
11
|
VALUE oj_array_nl_sym;
|
@@ -516,7 +514,7 @@ static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
|
|
516
514
|
pi.options = oj_default_options;
|
517
515
|
pi.options.auto_define = No;
|
518
516
|
pi.options.quirks_mode = Yes;
|
519
|
-
pi.options.allow_invalid =
|
517
|
+
pi.options.allow_invalid = Yes;
|
520
518
|
pi.options.empty_string = No;
|
521
519
|
pi.options.create_ok = No;
|
522
520
|
pi.options.allow_nan = (bang ? Yes : No);
|
@@ -531,11 +529,7 @@ static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
|
|
531
529
|
if (T_HASH != rb_type(ropts)) {
|
532
530
|
rb_raise(rb_eArgError, "options must be a hash.");
|
533
531
|
}
|
534
|
-
if (
|
535
|
-
symbolize_names_sym = ID2SYM(rb_intern("symbolize_names"));
|
536
|
-
rb_gc_register_address(&symbolize_names_sym);
|
537
|
-
}
|
538
|
-
if (Qnil != (v = rb_hash_lookup(ropts, symbolize_names_sym))) {
|
532
|
+
if (Qnil != (v = rb_hash_lookup(ropts, oj_symbolize_names_sym))) {
|
539
533
|
pi.options.sym_key = (Qtrue == v) ? Yes : No;
|
540
534
|
}
|
541
535
|
if (Qnil != (v = rb_hash_lookup(ropts, oj_quirks_mode_sym))) {
|
@@ -573,8 +567,7 @@ static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
|
|
573
567
|
}
|
574
568
|
}
|
575
569
|
if (oj_hash_has_key(ropts, oj_decimal_class_sym)) {
|
576
|
-
pi.options.compat_bigdec = (oj_bigdecimal_class ==
|
577
|
-
rb_hash_lookup(ropts, oj_decimal_class_sym));
|
570
|
+
pi.options.compat_bigdec = (oj_bigdecimal_class == rb_hash_lookup(ropts, oj_decimal_class_sym));
|
578
571
|
}
|
579
572
|
v = rb_hash_lookup(ropts, oj_max_nesting_sym);
|
580
573
|
if (Qtrue == v) {
|
@@ -682,7 +675,7 @@ static VALUE mimic_set_create_id(VALUE self, VALUE id) {
|
|
682
675
|
*/
|
683
676
|
static VALUE mimic_create_id(VALUE self) {
|
684
677
|
if (NULL != oj_default_options.create_id) {
|
685
|
-
return
|
678
|
+
return rb_utf8_str_new(oj_default_options.create_id, oj_default_options.create_id_len);
|
686
679
|
}
|
687
680
|
return rb_str_new_cstr(oj_json_class);
|
688
681
|
}
|
@@ -706,7 +699,7 @@ static struct _options mimic_object_to_json_options = {0, // indent
|
|
706
699
|
No, // empty_string
|
707
700
|
Yes, // allow_gc
|
708
701
|
Yes, // quirks_mode
|
709
|
-
|
702
|
+
Yes, // allow_invalid
|
710
703
|
No, // create_ok
|
711
704
|
No, // allow_nan
|
712
705
|
No, // trace
|
@@ -853,9 +846,6 @@ void oj_mimic_json_methods(VALUE json) {
|
|
853
846
|
// Pull in the JSON::State mimic file.
|
854
847
|
state_class = rb_const_get_at(generator, rb_intern("State"));
|
855
848
|
rb_gc_register_mark_object(state_class);
|
856
|
-
|
857
|
-
symbolize_names_sym = ID2SYM(rb_intern("symbolize_names"));
|
858
|
-
rb_gc_register_address(&symbolize_names_sym);
|
859
849
|
}
|
860
850
|
|
861
851
|
/* Document-module: JSON
|
data/ext/oj/object.c
CHANGED
@@ -35,7 +35,7 @@ static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) {
|
|
35
35
|
return ID2SYM(rb_intern3(kval->key + 1, kval->klen - 1, oj_utf8_encoding));
|
36
36
|
}
|
37
37
|
if (Yes == pi->options.sym_key) {
|
38
|
-
|
38
|
+
return ID2SYM(rb_intern3(kval->key, kval->klen, oj_utf8_encoding));
|
39
39
|
}
|
40
40
|
#if HAVE_RB_ENC_INTERNED_STR
|
41
41
|
rkey = rb_enc_interned_str(kval->key, kval->klen, oj_utf8_encoding);
|
@@ -60,21 +60,16 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
|
|
60
60
|
}
|
61
61
|
rstr = oj_circ_array_get(pi->circ_array, i);
|
62
62
|
} else {
|
63
|
-
|
63
|
+
rstr = rb_utf8_str_new(str, len);
|
64
64
|
}
|
65
65
|
return rstr;
|
66
66
|
}
|
67
67
|
|
68
|
-
#if (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
|
69
|
-
static VALUE oj_parse_xml_time(const char *str, int len) {
|
70
|
-
return rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(str, len));
|
71
|
-
}
|
72
|
-
#else
|
73
68
|
// The much faster approach (4x faster)
|
74
69
|
static int parse_num(const char *str, const char *end, int cnt) {
|
75
|
-
int
|
70
|
+
int n = 0;
|
76
71
|
char c;
|
77
|
-
int
|
72
|
+
int i;
|
78
73
|
|
79
74
|
for (i = cnt; 0 < i; i--, str++) {
|
80
75
|
c = *str;
|
@@ -88,9 +83,9 @@ static int parse_num(const char *str, const char *end, int cnt) {
|
|
88
83
|
|
89
84
|
VALUE
|
90
85
|
oj_parse_xml_time(const char *str, int len) {
|
91
|
-
VALUE
|
86
|
+
VALUE args[8];
|
92
87
|
const char *end = str + len;
|
93
|
-
int
|
88
|
+
int n;
|
94
89
|
|
95
90
|
// year
|
96
91
|
if (0 > (n = parse_num(str, end, 4))) {
|
@@ -201,7 +196,6 @@ oj_parse_xml_time(const char *str, int len) {
|
|
201
196
|
}
|
202
197
|
return rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
203
198
|
}
|
204
|
-
#endif
|
205
199
|
|
206
200
|
static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
|
207
201
|
const char *key = kval->key;
|
@@ -226,13 +220,10 @@ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t
|
|
226
220
|
}
|
227
221
|
parent->val = odd->clas;
|
228
222
|
parent->odd_args = oj_odd_alloc_args(odd);
|
229
|
-
} break;
|
230
|
-
case 'm':
|
231
|
-
parent->val = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
|
232
|
-
break;
|
233
|
-
case 's':
|
234
|
-
parent->val = rb_utf8_str_new(str, len);
|
235
223
|
break;
|
224
|
+
}
|
225
|
+
case 'm': parent->val = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding)); break;
|
226
|
+
case 's': parent->val = rb_utf8_str_new(str, len); break;
|
236
227
|
case 'c': // class
|
237
228
|
{
|
238
229
|
VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
|
@@ -242,7 +233,8 @@ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t
|
|
242
233
|
} else {
|
243
234
|
parent->val = clas;
|
244
235
|
}
|
245
|
-
|
236
|
+
break;
|
237
|
+
}
|
246
238
|
case 't': // time
|
247
239
|
parent->val = oj_parse_xml_time(str, (int)len);
|
248
240
|
break;
|
@@ -282,22 +274,21 @@ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
|
282
274
|
VALUE args[8];
|
283
275
|
|
284
276
|
sec_as_time(t, &ti);
|
285
|
-
args[0]
|
286
|
-
args[1]
|
287
|
-
args[2]
|
288
|
-
args[3]
|
289
|
-
args[4]
|
290
|
-
args[5]
|
291
|
-
args[6]
|
277
|
+
args[0] = LONG2NUM((long)(ti.year));
|
278
|
+
args[1] = LONG2NUM(ti.mon);
|
279
|
+
args[2] = LONG2NUM(ti.day);
|
280
|
+
args[3] = LONG2NUM(ti.hour);
|
281
|
+
args[4] = LONG2NUM(ti.min);
|
282
|
+
args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
|
283
|
+
args[6] = LONG2NUM(ni->exp);
|
292
284
|
parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
293
285
|
} else {
|
294
286
|
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
295
287
|
}
|
296
288
|
}
|
297
289
|
break;
|
298
|
-
case 'i':
|
299
|
-
if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp &&
|
300
|
-
0 != pi->circ_array) { // fixnum
|
290
|
+
case 'i': // circular index
|
291
|
+
if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
|
301
292
|
if (Qnil == parent->val) {
|
302
293
|
parent->val = rb_hash_new();
|
303
294
|
}
|
@@ -402,9 +393,7 @@ WHICH_TYPE:
|
|
402
393
|
}
|
403
394
|
break;
|
404
395
|
case T_HASH:
|
405
|
-
rb_hash_aset(parent->val,
|
406
|
-
calc_hash_key(pi, kval, parent->k1),
|
407
|
-
str_to_value(pi, str, len, orig));
|
396
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
|
408
397
|
break;
|
409
398
|
case T_STRING:
|
410
399
|
rval = str_to_value(pi, str, len, orig);
|
@@ -481,8 +470,8 @@ WHICH_TYPE:
|
|
481
470
|
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval);
|
482
471
|
break;
|
483
472
|
case T_OBJECT:
|
484
|
-
if (2 == klen && '^' == *key && 'i' == key[1] && !ni->infinity && !ni->neg &&
|
485
|
-
|
473
|
+
if (2 == klen && '^' == *key && 'i' == key[1] && !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp &&
|
474
|
+
0 != pi->circ_array) { // fixnum
|
486
475
|
oj_circ_array_set(pi->circ_array, parent->val, ni->i);
|
487
476
|
} else {
|
488
477
|
rval = oj_num_as_value(ni);
|
@@ -559,11 +548,7 @@ WHICH_TYPE:
|
|
559
548
|
volatile VALUE *a = RARRAY_PTR(value);
|
560
549
|
|
561
550
|
if (2 != len) {
|
562
|
-
oj_set_error_at(pi,
|
563
|
-
oj_parse_error_class,
|
564
|
-
__FILE__,
|
565
|
-
__LINE__,
|
566
|
-
"invalid hash pair");
|
551
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
|
567
552
|
return;
|
568
553
|
}
|
569
554
|
rb_hash_aset(parent->val, *a, a[1]);
|
@@ -637,10 +622,7 @@ static void end_hash(ParseInfo pi) {
|
|
637
622
|
} else if (NULL != parent->odd_args) {
|
638
623
|
OddArgs oa = parent->odd_args;
|
639
624
|
|
640
|
-
parent->val = rb_funcall2(oa->odd->create_obj,
|
641
|
-
oa->odd->create_op,
|
642
|
-
oa->odd->attr_cnt,
|
643
|
-
oa->args);
|
625
|
+
parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args);
|
644
626
|
oj_odd_free(oa);
|
645
627
|
parent->odd_args = NULL;
|
646
628
|
}
|
@@ -653,8 +635,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
|
|
653
635
|
volatile VALUE rval = Qnil;
|
654
636
|
|
655
637
|
// orig lets us know whether the string was ^r1 or \u005er1
|
656
|
-
if (3 <= len && 0 != pi->circ_array && '^' == orig[0] &&
|
657
|
-
0 == rb_array_len(stack_peek(&pi->stack)->val)) {
|
638
|
+
if (3 <= len && 0 != pi->circ_array && '^' == orig[0] && 0 == rb_array_len(stack_peek(&pi->stack)->val)) {
|
658
639
|
if ('i' == str[1]) {
|
659
640
|
long i = read_long(str + 2, len - 2);
|
660
641
|
|