So, I want to create a hash where any keys become arrays without having to separately declare them.
I therefore use
foo = Hash.new([])
=> {}
Then I can add items to keys that haven't been previously declared
foo[:bar] << 'Item 1'
=> ['Item 1']
There's just something odd about doing this. As when I call
foo
=> {}
to view the hash, it is empty. Even running
foo.keys
=> []
shows that it's empty. However, if I run
foo[:bar]
=> ['Item 1']
Please make it make sense.
foo = Hash.new([]) sets the default value of a not existed key to an array. Herefoo[:bar] << 'Item 1' the :bar key doesn't exist, so foo uses an array to which you add a new element. By doing so you mutate the default value because the array is provided to you by a reference.
> foo = Hash.new([])
=> {}
> foo.default
=> []
If you call any not defined key on your hash you'll get this array:
> foo[:bar] << 'Item 1'
=> ["Item 1"]
> foo[:foo]
=> ["Item 1"]
To achieve your goal you should return a new array every time. It's possible by passing a block to Hash.new, the block will be executed every time you access a not defined key:
> foo = Hash.new { |hash, key| hash[key] = [] }
=> {}
> foo[:bar] << 'Item 1'
=> ["Item 1"]
> foo[:bar]
=> ["Item 1"]
> foo.keys
=> [:bar]
> foo[:foo]
=> []
> foo[:foo] << 'Item 2'
=> ["Item 2"]
> foo
=> {:bar=>["Item 1"], :foo=>["Item 2"]}