ruby-changes:40456
From: nobu <ko1@a...>
Date: Wed, 11 Nov 2015 18:30:49 +0900 (JST)
Subject: [ruby-changes:40456] nobu:r52537 (trunk): sprintf.c: nil value is valid
nobu 2015-11-11 18:30:31 +0900 (Wed, 11 Nov 2015) New Revision: 52537 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=52537 Log: 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] Modified files: trunk/ChangeLog trunk/hash.c trunk/internal.h trunk/sprintf.c trunk/test/ruby/test_sprintf.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 52536) +++ ChangeLog (revision 52537) @@ -1,3 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Wed Nov 11 18:30:28 2015 Nobuyoshi Nakada <nobu@r...> + + * 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@r...> * vm_eval.c (local_var_list_add): skip internal local variable Index: sprintf.c =================================================================== --- sprintf.c (revision 52536) +++ sprintf.c (revision 52537) @@ -605,12 +605,20 @@ rb_str_format(int argc, const VALUE *arg https://github.com/ruby/ruby/blob/trunk/sprintf.c#L605 } 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++; Index: hash.c =================================================================== --- hash.c (revision 52536) +++ hash.c (revision 52537) @@ -758,8 +758,8 @@ rb_hash_rehash(VALUE hash) https://github.com/ruby/ruby/blob/trunk/hash.c#L758 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) https://github.com/ruby/ruby/blob/trunk/hash.c#L792 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) https://github.com/ruby/ruby/blob/trunk/hash.c#L1184 } } } - return hash_default_value(hash, Qnil); + return rb_hash_default_value(hash, Qnil); } static int Index: internal.h =================================================================== --- internal.h (revision 52536) +++ internal.h (revision 52537) @@ -828,6 +828,7 @@ void rb_gc_resurrect(VALUE ptr); https://github.com/ruby/ruby/blob/trunk/internal.h#L828 /* 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); Index: test/ruby/test_sprintf.rb =================================================================== --- test/ruby/test_sprintf.rb (revision 52536) +++ test/ruby/test_sprintf.rb (revision 52537) @@ -415,4 +415,9 @@ class TestSprintf < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_sprintf.rb#L415 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 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/