From 160d02d830d93316a8b4afd54138c1a8bfb8a6b3 Mon Sep 17 00:00:00 2001 From: nobu Date: Sat, 31 Mar 2012 05:23:01 +0000 Subject: [PATCH] * hash.c (hash_default_value): extract from rb_hash_aref(), to be shared with rb_hash_shift(), so that overriding Hash#default will be respected. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 ++++++ hash.c | 29 ++++++++++++++++------------- test/ruby/test_hash.rb | 8 ++++++++ 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index df64cad02d..1f55a98a9d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Sat Mar 31 14:22:59 2012 Nobuyoshi Nakada + + * hash.c (hash_default_value): extract from rb_hash_aref(), to be + shared with rb_hash_shift(), so that overriding Hash#default + will be respected. + Sat Mar 31 14:16:02 2012 Sokolov Yura (funny-falcon) * hash.c: do not allocate st_table when it is not necessary. diff --git a/hash.c b/hash.c index 08325a142e..4764bdd6b2 100644 --- a/hash.c +++ b/hash.c @@ -480,6 +480,20 @@ rb_hash_rehash(VALUE hash) return hash; } +static VALUE +hash_default_value(VALUE hash, VALUE key) +{ + if (rb_method_basic_definition_p(CLASS_OF(hash), id_default)) { + VALUE ifnone = RHASH_IFNONE(hash); + if (!FL_TEST(hash, HASH_PROC_DEFAULT)) return ifnone; + if (key == Qundef) return Qnil; + return rb_funcall(ifnone, id_yield, 2, hash, key); + } + else { + return rb_funcall(hash, id_default, 1, key); + } +} + /* * call-seq: * hsh[key] -> value @@ -500,13 +514,7 @@ rb_hash_aref(VALUE hash, VALUE key) st_data_t val; if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) { - if (!FL_TEST(hash, HASH_PROC_DEFAULT) && - rb_method_basic_definition_p(CLASS_OF(hash), id_default)) { - return RHASH_IFNONE(hash); - } - else { - return rb_funcall(hash, id_default, 1, key); - } + return hash_default_value(hash, key); } return (VALUE)val; } @@ -865,12 +873,7 @@ rb_hash_shift(VALUE hash) return rb_assoc_new(var.key, var.val); } } - if (FL_TEST(hash, HASH_PROC_DEFAULT)) { - return rb_funcall(RHASH_IFNONE(hash), id_yield, 2, hash, Qnil); - } - else { - return RHASH_IFNONE(hash); - } + return hash_default_value(hash, Qnil); } static int diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index 494fc98a9f..4b635a194d 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -739,6 +739,14 @@ class TestHash < Test::Unit::TestCase h.each { assert_equal([1, 2], h.shift) } end + def test_shift_none + h = Hash.new {|hh, k| "foo"} + def h.default(k = nil) + default_proc.call(k).upcase + end + assert_equal("FOO", h.shift) + end + def test_reject_bang2 assert_equal({1=>2}, {1=>2,3=>4}.reject! {|k, v| k + v == 7 }) assert_nil({1=>2,3=>4}.reject! {|k, v| k == 5 })