开发者

hash.delete_if { |key, value| true } doesn't delete ... why?

开发者 https://www.devze.com 2023-01-22 10:04 出处:网络
I am working on the acts_as_taggable_on plugin, but there is something I can\'t really understand (even if it is just a very simple code line).

I am working on the acts_as_taggable_on plugin, but there is something I can't really understand (even if it is just a very simple code line).

puts "before: " + cache.inspect
# cache.delete_if { |key, value| key.id == owner.id && key.class == owner.class } # original code line
cache.delete_if { |key, value| true } # my test code
puts "after: " + cache.inspect

# output

before: {#<TaggableUser id: 1, name: nil>=>["dog"]}

after: {# TaggableUser id: 1, name: nil>=>["dog"]}

My problem is that the cache.delete_if d开发者_如何学运维oesn't delete anything even if it always evaluates to true. I simply don't get why ... and really tried much. It's only the problem with that cache hash. But I really couldn't find anything special about that particular hash.

The cache is created in that method:

def cached_owned_tag_list_on(context)
  variable_name = "@owned_#{context}_list"
  cache = instance_variable_get(variable_name) || instance_variable_set(variable_name, {})
end

The full code can be viewed here (see line 60): http://github.com/mbleigh/acts-as-taggable-on/blob/master/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb#L60

One step further

When I do a rehash before the delete_if it works. What can "corrupt" a hash in a way that rehash is needed before any deletions works?


From the documentation of rehash:

 call-seq:
   hsh.rehash -> hsh

 Rebuilds the hash based on the current hash values for each key. If
 values of key objects have changed since they were inserted, this
 method will reindex <i>hsh</i>. 

So your keys (which are regular ActiveRecord instances) had their hashes changed from the time they were created. Looking into the AR sources:

# File activerecord/lib/active_record/base.rb, line 1613
1613:       def hash
1614:         id.hash
1615:       end

So, their id's were changed. Why can that happen? Well, the obvious cause is that the object was created, then put into hash, and after that saved (which assigned it an id and changed its hash).

Also, this has another bad consequence: as the hash of all those newly-created objects is that of nil, if there were multiple unsaved objects added to the hash, they all will occupy the same slot, and trying to index the hash with some other unsaved object will return nonsense.


Are you certain that cache is a Hash? The behavior you are describing is not normal.

$ ruby -v
ruby 1.8.7 (2009-06-12 patchlevel 174) [universal-darwin10.0]

>> h = {:a => 1, :b => 2}
=> {:b=>2, :a=>1}
>> h
=> {:b=>2, :a=>1}
>> h.delete_if {|k,v| v == 2}
=> {:a=>1}
>> h
=> {:a=>1}

>> h = {:a => 1, :b => 2}
=> {:b=>2, :a=>1}
>> h.delete_if {|k,v| true}
=> {}
>> h
=> {}


Maybe it is a bug of acts_as_taggable_on and you can just fill in a bug report.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号