Search code examples
ruby-on-railsrubyconstantsimmutabilityruby-hash

Clone constant of hash into new variable without mutating constant on update with .each block?


I'm struggling with something. I've abstracted my code out to be as simple as possible, yet I still don't understand why it's having this behaviour.

I'm creating a constant consisting of a set of key-value pairs and freezing it. I'm then using the .dup method to copy the hash into a new variable.

However, when I iterate over an array and try to store it in the (previously empty) array in the new variable, it not only updates the new variable, but also the original constant. This only seems to be the case with the .each method - if I pass the new values directly as a new array, it works without updating the constant.

My abstracted code is below:

CONFIG_VALUES = { results: [], loop_count: 0 }.freeze
the_results = ["foo", "bar"]
abc = CONFIG_VALUES.dup
the_results.each do |res| 
  abc[:results] << res
end
abc
#=> {:results=>["foo", "bar"], :loop_count=>0}
CONFIG_VALUES
#=> {:results=>["foo", "bar"], :loop_count=>0}

Solution

  • Hash#dup method isn't recursive. Anyway, if you use Ruby on Rails, and I think you do since you tagged it, you can use #deep_dup method: http://api.rubyonrails.org/classes/Hash.html#method-i-deep_dup

    It's an ActiveSupport method, so you could just use the gem in case you aren't using Ruby on Rails.