aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--hash.c8
-rw-r--r--internal.h1
-rw-r--r--sprintf.c20
-rw-r--r--test/ruby/test_sprintf.rb5
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 <nobu@ruby-lang.org>
+
+ * 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 <nobu@ruby-lang.org>
* 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 %<location>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