From 56e3b493043f5d1b25a52d073f25b8c0f825052f Mon Sep 17 00:00:00 2001 From: nobu Date: Wed, 11 Nov 2015 09:30:31 +0000 Subject: sprintf.c: nil value is valid * sprintf.c (rb_str_format): look up the key, then get default value and raise KeyError if the returned value is nil. [ruby-dev:49338] [Ruby trunk - Bug #11677] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52537 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 ++++++ hash.c | 8 ++++---- internal.h | 1 + sprintf.c | 20 ++++++++++++++------ test/ruby/test_sprintf.rb | 5 +++++ 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8b3e1f86b0..9c455b43f5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Wed Nov 11 18:30:28 2015 Nobuyoshi Nakada + + * sprintf.c (rb_str_format): look up the key, then get default + value and raise KeyError if the returned value is nil. + [ruby-dev:49338] [Ruby trunk - Bug #11677] + Wed Nov 11 17:38:24 2015 Nobuyoshi Nakada * vm_eval.c (local_var_list_add): skip internal local variable diff --git a/hash.c b/hash.c index f34e6e7fdf..a41e8bf76f 100644 --- a/hash.c +++ b/hash.c @@ -758,8 +758,8 @@ rb_hash_rehash(VALUE hash) return hash; } -static VALUE -hash_default_value(VALUE hash, VALUE key) +VALUE +rb_hash_default_value(VALUE hash, VALUE key) { if (rb_method_basic_definition_p(CLASS_OF(hash), id_default)) { VALUE ifnone = RHASH_IFNONE(hash); @@ -792,7 +792,7 @@ rb_hash_aref(VALUE hash, VALUE key) st_data_t val; if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) { - return hash_default_value(hash, key); + return rb_hash_default_value(hash, key); } return (VALUE)val; } @@ -1184,7 +1184,7 @@ rb_hash_shift(VALUE hash) } } } - return hash_default_value(hash, Qnil); + return rb_hash_default_value(hash, Qnil); } static int diff --git a/internal.h b/internal.h index dfd02e95cc..600ad8e7d3 100644 --- a/internal.h +++ b/internal.h @@ -828,6 +828,7 @@ void rb_gc_resurrect(VALUE ptr); /* hash.c */ struct st_table *rb_hash_tbl_raw(VALUE hash); VALUE rb_hash_has_key(VALUE hash, VALUE key); +VALUE rb_hash_default_value(VALUE hash, VALUE key); VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc); long rb_objid_hash(st_index_t index); st_table *rb_init_identtable(void); diff --git a/sprintf.c b/sprintf.c index 5c0f94005c..c2e5de5d64 100644 --- a/sprintf.c +++ b/sprintf.c @@ -605,12 +605,20 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt) } CHECKNAMEARG(start, len, enc); get_hash(&hash, argc, argv); - sym = rb_cstr_intern(start + 1, - len - 2 /* without parenthesis */, - enc); - nextvalue = rb_hash_aref(hash, sym); - if (NIL_P(nextvalue) && !FL_TEST(hash, HASH_PROC_DEFAULT)) { - rb_enc_raise(enc, rb_eKeyError, "key%.*s not found", len, start); + sym = rb_check_symbol_cstr(start + 1, + len - 2 /* without parenthesis */, + enc); + if (!NIL_P(sym)) nextvalue = rb_hash_lookup2(hash, sym, Qundef); + if (nextvalue == Qundef) { + if (NIL_P(sym)) { + sym = rb_cstr_intern(start + 1, + len - 2 /* without parenthesis */, + enc); + } + nextvalue = rb_hash_default_value(hash, sym); + if (NIL_P(nextvalue)) { + rb_enc_raise(enc, rb_eKeyError, "key%.*s not found", len, start); + } } if (term == '}') goto format_s; p++; diff --git a/test/ruby/test_sprintf.rb b/test/ruby/test_sprintf.rb index 97eb4809c4..8af94a89fe 100644 --- a/test/ruby/test_sprintf.rb +++ b/test/ruby/test_sprintf.rb @@ -415,4 +415,9 @@ class TestSprintf < Test::Unit::TestCase assert_equal("hello world", "hello %{location}" % h) assert_equal("hello world", "hello %s" % h) end + + def test_named_with_nil + h = { key: nil, key2: "key2_val" } + assert_equal("key is , key2 is key2_val", "key is %{key}, key2 is %{key2}" % h) + end end -- cgit v1.2.3