Skip to content

Instantly share code, notes, and snippets.

@acook
Last active December 11, 2015 18:28
Show Gist options
  • Save acook/4641364 to your computer and use it in GitHub Desktop.
Save acook/4641364 to your computer and use it in GitHub Desktop.
Some serious weirdness with Ruby hashes.
files = Hash.new Array.new
file = Pathname.new '../.DS_Store'
hash = Digest::SHA256.file file
# This results in weirdness
files[hash.to_s] << file
files #=> {}
files.length #=> 0
file[hash.to_s] #=> [#<Pathname:../.DS_Store>]
# WTF?!
# doing this, however, works fine:
files[hash.to_s].empty? ? (files[hash.to_s] = [file]) : (files[hash.to_s] << file)
file #=> {"a730298b87029223e6a4fd22716b52da69b01384642fe305eca2d33fa93db8e7" => [#<Pathname:../.DS_Store>]}
files.length #=> 1
file[hash.to_s] #=> [#<Pathname:../.DS_Store>]
@sj26
Copy link

sj26 commented Jan 26, 2013

Yep, the Hash.new takes a default, but it doesn't set that default in the hash.

And you're explicitly creating a single array as the default value, so every time a key is missed in the hash it will return the same array.

To illustrate better:

default = Array.new
files = Hash.new default

files["a"] # => []
files # => {}
files["a"] << 1 # => [1]
files # => {}
default # => [1]
files["b"] # => [1]
files["b"] << 2 # => [1, 2]
files["a"] # => [1, 2]
default # => [1, 2]

You want:

files = Hash.new { |hash, k| hash[k] = [] }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment