From: squidster@... (Squidster) Date: 2002-11-15T15:22:34+09:00 Subject: (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 --------------------------