(Simple/Naive) Deep Copy Implementation

Rubyists,
I wanted to have a deep-copy mechanism in order to protect my precious
data from getting all trampled over by a client class, and was both
surprised and frustated by the lack of a native deep-copy in Ruby.

Since then, I’ve scanned the archive and came across the
Marshal.load/dump “hack” to do deep-copy. Well, tried that and Marshal
just doesn’t cut the mustard for me, and my data doesn’t even have
"weird" objects like IO or contextual binding, just hashes and arrays,
albeit they are very deeply nested.

Well, I got off my figurative butt and decided (like a good OSS/FSF
devotee) to take things into my own hands. I have now a working
mechanism for my needs.

Some disclaimers:

  1. Although this works for me, YMMV
  2. DOESN’T support singletons, bindings, etc.
  3. DOESN’t support IO
  4. DOES support recursion
  5. DOES support complex nesting (I hope :-p)
  6. DOES support user classes, arrays, and hashes

Well, 'nuff said. Here’s the code and feel free to improve upon it.

-------------------------- C U T --------------------------
#!/usr/bin/ruby -w

module DeepClone
alias shallow_clone clone
def clone
klone = self.shallow_clone
self.instance_variables.each { |v|
vari = v[1…-1]
val = send(vari).clone
klone.send("#{vari}=", val)
}
return klone
end
end
class Hash
alias shallow_clone clone
def clone
klone = self.shallow_clone
self.each { |k,v| klone[k] = v.clone }
return klone
end
end
class Array
def clone
# FIXME: Not cloning, am rebuilding from scratch!!
klone = Array.new
self.each { |v|
klone << v.clone
}
return klone
end
end
class Fixnum
def clone
return self
end
end
class Bignum
def clone
return self
end
end
class NilClass
def clone
return self
end
end
class FalseClass
def clone
return self
end
end
class TrueClass
def clone
return self
end
end

class SD
attr_accessor :sub, :tot, :stud

def initialize sub, tot
	@sub	= sub
	@tot 	= tot
	@stud	= Hash.new
end

end

class User
attr_accessor :subj_dist
def initialize subj_dist
@subj_dist = subj_dist
end
end

foo = {“ssk1234” => SD.new(“ssk1234”, 44)}
ctx = User.new foo

ctx.subj_dist[“ssk1234”].stud =
{“foo”=>[1,3,45,nil],“bar”=>[4,23,false,2242],“baz”=>[true,3425,23]}

include DeepClone
clone_ctx = ctx.subj_dist.clone
clone_ctx[“ssk1234”].stud.delete “foo”

puts "ctx: #{ctx.subj_dist.inspect}"
puts “clone_ctx: #{clone_ctx.inspect}”
-------------------------- C U T --------------------------