When you copy an object, all you do is copy its set of instance variables, which are just references to other objects. For an array, the instance variables are its set of indexes, which again are just references. Copying an array just means making a new list of references, but the objects they point to remain unmodified and uncopied.
Consider:
<pre> array = ["foo"] copy = array.dup </pre>
array and copy are independently mutable - modifying the index in one does not affect the indexes in the other - but they still both contain references to the single string "foo". Thus:
<pre> copy.first.gsub! /foo/, "bar" </pre>
modifies the string referenced by copy, which is the same string referenced by array. So array becomes ["bar"].
If you want a true deep copy, do something like this:
<pre> def deep_copy(object) case object when Array object.map { |item| deep_copy(item) } when Hash object.inject({}) do |hash, (key,value)| hash[deep_copy(key)] = deep_copy(value) hash end # handle other data structures if need be else object.respond_to?(:dup) ? object.dup : object end end </pre>