Skip to content

Commit 9fd18dd

Browse files
committed
Merge branch 'develop'
2 parents 0bca459 + 5e9c707 commit 9fd18dd

File tree

10 files changed

+135
-62
lines changed

10 files changed

+135
-62
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# CHANGELOG
22

3+
4+
## 3.13.8 - 2021-09-27
5+
6+
- Fix `Oj::Doc` behaviour for inexisting path.
7+
```ruby
8+
Oj::Doc.open('{"foo":1}') do |doc|
9+
doc.fetch('/foo/bar') # used to give `1`, now gives `nil`
10+
doc.exists?('/foo/bar') # used to give `true`, now gives `false`
11+
end
12+
```
13+
14+
- Fix `Oj::Parser` handling of BigDecimal. `snprint()` does not handle `%Lg` correctly but `sprintf()` does.
15+
316
## 3.13.7 - 2021-09-16
417

518
- The JSON gem allows invalid unicode so Oj, when mimicing JSON now

Rakefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ task :default => :test_all
5252
begin
5353
require "rails/version"
5454

55-
if Rails.version =~ /4\.\d/
55+
if Rails.version =~ /^4\.\d/
5656
Rake::TestTask.new "activesupport4" do |t|
5757
t.libs << 'test'
5858
t.pattern = 'test/activesupport4/*_test.rb'
@@ -62,7 +62,7 @@ begin
6262
Rake::Task[:test_all].enhance ["activesupport4"]
6363
end
6464

65-
if Rails.version =~ /5\.\d/
65+
if Rails.version =~ /^5\.\d/
6666
Rake::TestTask.new "activesupport5" do |t|
6767
t.libs << 'test'
6868
t.pattern = 'test/activesupport5/*_test.rb'
@@ -72,7 +72,7 @@ begin
7272
Rake::Task[:test_all].enhance ["activesupport5"]
7373
end
7474

75-
if Rails.version =~ /6\.\d/
75+
if Rails.version =~ /^6\.\d/
7676
Rake::TestTask.new "activesupport6" do |t|
7777
t.libs << 'test'
7878
t.pattern = 'test/activesupport6/*_test.rb'

docs/mode_table.html

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<table>
2+
<tr><th>Option</th><th>type</th><th>null</th><th>strict</th><th>compat</th><th>rails</th><th>object</th><th>custom</th><th>wab</th></tr>
3+
<tr><td>:allow_blank</td><td>Boolean</td><td></td><td></td><td>1</td><td>1</td><td></td><td>x</td><td></td><td></tr>
4+
<tr><td>:allow_gc</td><td>Boolean</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td></tr>
5+
<tr><td>:allow_invalid_unicode</td><td>Boolean</td><td></td><td></td><td></td><td></td><td>x</td><td>x</td><td></td></tr>
6+
<tr><td>:allow_nan</td><td>Boolean</td><td></td><td></td><td>x</td><td></td><td>x</td><td>x</td><td></td></tr>
7+
<tr><td>:array_class</td><td>Class</td><td></td><td></td><td>x</td><td>x</td><td></td><td>x</td><td></td></tr>
8+
<tr><td>:array_nl</td><td>String</td><td></td><td></td><td></td><td></td><td></td><td>x</td><td></td></tr>
9+
<tr><td>:ascii_only</td><td>Boolean</td><td>x</td><td>x</td><td>2</td><td>2</td><td>x</td><td>x</td><td></td></tr>
10+
<tr><td>:auto_define</td><td>Boolean</td><td></td><td></td><td></td><td></td><td>x</td><td>x</td><td></td></tr>
11+
<tr><td>:bigdecimal_as_decimal</td><td>Boolean</td><td></td><td></td><td></td><td>3</td><td>x</td><td>x</td><td></td></tr>
12+
<tr><td>:bigdecimal_load</td><td>Boolean</td><td></td><td></td><td></td><td></td><td></td><td>x</td><td></td></tr>
13+
<tr><td>:compat_bigdecimal</td><td>Boolean</td><td></td><td></td><td>x</td><td></td><td></td><td>x</td><td></td></tr>
14+
<tr><td>:cache_keys</td><td>Boolean</td><td>x</td><td>x</td><td>x</td><td>x</td><td></td><td>x</td><td></td></tr>
15+
<tr><td>:cache_strings</td><td>Fixnum</td><td>x</td><td>x</td><td>x</td><td>x</td><td></td><td>x</td><td></td></tr>
16+
<tr><td>:circular</td><td>Boolean</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td></td></tr>
17+
<tr><td>:class_cache</td><td>Boolean</td><td></td><td></td><td></td><td></td><td>x</td><td>x</td><td></td></tr>
18+
<tr><td>:create_additions</td><td>Boolean</td><td></td><td></td><td>x</td><td>x</td><td></td><td>x</td><td></td></tr>
19+
<tr><td>:create_id</td><td>String</td><td></td><td></td><td>x</td><td>x</td><td></td><td>x</td><td></td></tr>
20+
<tr><td>:empty_string</td><td>Boolean</td><td></td><td></td><td></td><td></td><td></td><td>x</td><td></td></tr>
21+
<tr><td>:escape_mode</td><td>Symbol</td><td></td><td></td><td></td><td></td><td></td><td>x</td><td></td></tr>
22+
<tr><td>:float_precision</td><td>Fixnum</td><td>x</td><td>x</td><td></td><td></td><td></td><td>x</td><td></td></tr>
23+
<tr><td>:hash_class</td><td>Class</td><td></td><td></td><td>x</td><td>x</td><td></td><td>x</td><td></td></tr>
24+
<tr><td>:ignore</td><td>Array</td><td></td><td></td><td></td><td></td><td>x</td><td>x</td><td></td></tr>
25+
<tr><td>:indent</td><td>Integer</td><td>x</td><td>x</td><td>3</td><td>4</td><td>x</td><td>x</td><td>x</td></tr>
26+
<tr><td>:indent_str</td><td>String</td><td></td><td></td><td>x</td><td>x</td><td></td><td>x</td><td></td></tr>
27+
<tr><td>:integer_range</td><td>Range</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td></tr>
28+
<tr><td>:match_string</td><td>Hash</td><td></td><td></td><td>x</td><td>x</td><td></td><td>x</td><td></td></tr>
29+
<tr><td>:max_nesting</td><td>Fixnum</td><td>4</td><td>4</td><td>x</td><td></td><td>5</td><td>4</td><td></td></tr>
30+
<tr><td>:mode</td><td>Symbol</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td></td></tr>
31+
<tr><td>:nan</td><td>Symbol</td><td></td><td></td><td></td><td></td><td></td><td>x</td><td></td></tr>
32+
<tr><td>:nilnil</td><td>Boolean</td><td></td><td></td><td></td><td></td><td></td><td>x</td><td></td></tr>
33+
<tr><td>:object_class</td><td>Class</td><td></td><td></td><td>x</td><td></td><td></td><td>x</td><td></td></tr>
34+
<tr><td>:object_nl</td><td>String</td><td></td><td></td><td>x</td><td>x</td><td></td><td>x</td><td></td></tr>
35+
<tr><td>:omit_nil</td><td>Boolean</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td></td></tr>
36+
<tr><td>:quirks_mode</td><td>Boolean</td><td></td><td></td><td>6</td><td></td><td></td><td>x</td><td></td></tr>
37+
<tr><td>:safe</td><td>String</td><td></td><td></td><td>x</td><td></td><td></td><td></td><td></td></tr>
38+
<tr><td>:second_precision</td><td>Fixnum</td><td></td><td></td><td></td><td></td><td>x</td><td>x</td><td></td></tr>
39+
<tr><td>:space</td><td>String</td><td></td><td></td><td>x</td><td>x</td><td></td><td>x</td><td></td></tr>
40+
<tr><td>:space_before</td><td>String</td><td></td><td></td><td>x</td><td>x</td><td></td><td>x</td><td></td></tr>
41+
<tr><td>:symbol_keys</td><td>Boolean</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td></td></tr>
42+
<tr><td>:trace</td><td>Boolean</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td></tr>
43+
<tr><td>:time_format</td><td>Symbol</td><td></td><td></td><td></td><td></td><td>x</td><td>x</td><td></td></tr>
44+
<tr><td>:use_as_json</td><td>Boolean</td><td></td><td></td><td></td><td></td><td></td><td>x</td><td></td></tr>
45+
<tr><td>:use_raw_json</td><td>Boolean</td><td></td><td></td><td>x</td><td>x</td><td>x</td><td>x</td><td></td></tr>
46+
<tr><td>:use_to_hash</td><td>Boolean</td><td></td><td></td><td></td><td></td><td></td><td>x</td><td></td></tr>
47+
<tr><td>:use_to_json</td><td>Boolean</td><td></td><td></td><td></td><td></td><td></td><td>x</td><td></td></tr>
48+
</table>

ext/oj/fast.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,10 @@ static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path) {
879879
}
880880
} else if (NULL == leaf->elements) {
881881
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;
882886
} else if (COL_VAL == leaf->value_type) {
883887
Leaf first = leaf->elements->next;
884888
Leaf e = first;
@@ -1373,8 +1377,8 @@ static VALUE doc_fetch(int argc, VALUE *argv, VALUE self) {
13731377
* Returns true if the value at the location identified by the path exists.
13741378
* @param [String] path path to the location
13751379
* @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
13781382
*/
13791383
static VALUE doc_exists(VALUE self, VALUE str) {
13801384
Doc doc;

ext/oj/intern.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int a
186186
char * end = class_name + sizeof(class_name) - 1;
187187
char * s;
188188
const char *n = name;
189+
size_t nlen = len;
189190

190191
clas = rb_cObject;
191192
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
208209
}
209210
*s = '\0';
210211
if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
211-
oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class %s is not defined", name);
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);
212218
if (Qnil != error_class) {
213219
pi->err_class = error_class;
214220
}

ext/oj/object.c

Lines changed: 26 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) {
3535
return ID2SYM(rb_intern3(kval->key + 1, kval->klen - 1, oj_utf8_encoding));
3636
}
3737
if (Yes == pi->options.sym_key) {
38-
return ID2SYM(rb_intern3(kval->key, kval->klen, oj_utf8_encoding));
38+
return ID2SYM(rb_intern3(kval->key, kval->klen, oj_utf8_encoding));
3939
}
4040
#if HAVE_RB_ENC_INTERNED_STR
4141
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
6060
}
6161
rstr = oj_circ_array_get(pi->circ_array, i);
6262
} else {
63-
rstr = rb_utf8_str_new(str, len);
63+
rstr = rb_utf8_str_new(str, len);
6464
}
6565
return rstr;
6666
}
6767

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
7368
// The much faster approach (4x faster)
7469
static int parse_num(const char *str, const char *end, int cnt) {
75-
int n = 0;
70+
int n = 0;
7671
char c;
77-
int i;
72+
int i;
7873

7974
for (i = cnt; 0 < i; i--, str++) {
8075
c = *str;
@@ -88,9 +83,9 @@ static int parse_num(const char *str, const char *end, int cnt) {
8883

8984
VALUE
9085
oj_parse_xml_time(const char *str, int len) {
91-
VALUE args[8];
86+
VALUE args[8];
9287
const char *end = str + len;
93-
int n;
88+
int n;
9489

9590
// year
9691
if (0 > (n = parse_num(str, end, 4))) {
@@ -201,7 +196,6 @@ oj_parse_xml_time(const char *str, int len) {
201196
}
202197
return rb_funcall2(rb_cTime, oj_new_id, 7, args);
203198
}
204-
#endif
205199

206200
static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
207201
const char *key = kval->key;
@@ -226,13 +220,10 @@ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t
226220
}
227221
parent->val = odd->clas;
228222
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);
235223
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;
236227
case 'c': // class
237228
{
238229
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
242233
} else {
243234
parent->val = clas;
244235
}
245-
} break;
236+
break;
237+
}
246238
case 't': // time
247239
parent->val = oj_parse_xml_time(str, (int)len);
248240
break;
@@ -282,22 +274,21 @@ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
282274
VALUE args[8];
283275

284276
sec_as_time(t, &ti);
285-
args[0] = LONG2NUM((long)(ti.year));
286-
args[1] = LONG2NUM(ti.mon);
287-
args[2] = LONG2NUM(ti.day);
288-
args[3] = LONG2NUM(ti.hour);
289-
args[4] = LONG2NUM(ti.min);
290-
args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
291-
args[6] = LONG2NUM(ni->exp);
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);
292284
parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
293285
} else {
294286
parent->val = rb_time_nano_new(ni->i, (long)nsec);
295287
}
296288
}
297289
break;
298-
case 'i': // circular index
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
301292
if (Qnil == parent->val) {
302293
parent->val = rb_hash_new();
303294
}
@@ -402,9 +393,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
402393
}
403394
break;
404395
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));
408397
break;
409398
case T_STRING:
410399
rval = str_to_value(pi, str, len, orig);
@@ -481,8 +470,8 @@ static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
481470
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval);
482471
break;
483472
case T_OBJECT:
484-
if (2 == klen && '^' == *key && 'i' == key[1] && !ni->infinity && !ni->neg &&
485-
1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
473+
if (2 == klen && '^' == *key && 'i' == key[1] && !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp &&
474+
0 != pi->circ_array) { // fixnum
486475
oj_circ_array_set(pi->circ_array, parent->val, ni->i);
487476
} else {
488477
rval = oj_num_as_value(ni);
@@ -559,11 +548,7 @@ static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
559548
volatile VALUE *a = RARRAY_PTR(value);
560549

561550
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");
567552
return;
568553
}
569554
rb_hash_aset(parent->val, *a, a[1]);
@@ -637,10 +622,7 @@ static void end_hash(ParseInfo pi) {
637622
} else if (NULL != parent->odd_args) {
638623
OddArgs oa = parent->odd_args;
639624

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);
644626
oj_odd_free(oa);
645627
parent->odd_args = NULL;
646628
}
@@ -653,8 +635,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
653635
volatile VALUE rval = Qnil;
654636

655637
// 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)) {
658639
if ('i' == str[1]) {
659640
long i = read_long(str + 2, len - 2);
660641

ext/oj/parse.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -904,9 +904,17 @@ void oj_set_error_at(ParseInfo pi,
904904
char * end = p + sizeof(msg) - 2;
905905
char * start;
906906
Val vp;
907+
int mlen;
907908

908909
va_start(ap, format);
909-
p += vsnprintf(msg, sizeof(msg) - 1, format, ap);
910+
mlen = vsnprintf(msg, sizeof(msg) - 1, format, ap);
911+
if (0 < mlen) {
912+
if (sizeof(msg) - 2 < (size_t)mlen) {
913+
p = end - 2;
914+
} else {
915+
p += mlen;
916+
}
917+
}
910918
va_end(ap);
911919
pi->err.clas = err_clas;
912920
if (p + 3 < end) {

ext/oj/usual.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ static void add_float_key(ojParser p) {
537537
static void add_float_as_big(ojParser p) {
538538
char buf[64];
539539

540-
// fails on ubuntu
540+
// snprintf fails on ubuntu and macOS for long double
541541
// snprintf(buf, sizeof(buf), "%Lg", p->num.dub);
542542
sprintf(buf, "%Lg", p->num.dub);
543543
push(p, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(buf)));
@@ -546,7 +546,9 @@ static void add_float_as_big(ojParser p) {
546546
static void add_float_as_big_key(ojParser p) {
547547
char buf[64];
548548

549-
snprintf(buf, sizeof(buf), "%Lg", p->num.dub);
549+
// snprintf fails on ubuntu and macOS for long double
550+
// snprintf(buf, sizeof(buf), "%Lg", p->num.dub);
551+
sprintf(buf, "%Lg", p->num.dub);
550552
push_key(p);
551553
push2(p, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(buf)));
552554
}

lib/oj/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

22
module Oj
33
# Current version of the module.
4-
VERSION = '3.13.7'
4+
VERSION = '3.13.8'
55
end

0 commit comments

Comments
 (0)