You have created a new Hash with an Array as an accumulator when the key is not present so
hash = Hash.new([])
hash[:one] << "uno"
hash[:one] == ["uno"] #=> true
but
hash[:two] << "dos"
(hash[:one] == hash[:two]) && (hash[:two] == ["uno","dos"]) #=> true
hash[:three] == ["uno","dos"] #=> true
because ["uno","dos"] is the original array created with the Hash and hash[:non_existant_key] points to it.
Note: no keys have actually been added to hash in this case. It would be similar to
a = []
hash = {}
hash.fetch(:one,a) << 'uno'
hash.fetch(:two,a) << 'dos'
hash.fetch(:three, a)
#=> ['uno','dos']
hash
#=> {}
To solve this you can use this syntax as mentioned in your second test
hash = Hash.new {|h,k| h[k] = [] }
This means fro every new key instantiate a new Array as its value rather than reusing the same Array over and over again
This is the problem with the Hash.new(obj) syntax when obj is a mutable object