File: deep_clone.rb

package info (click to toggle)
ruby-facets 2.9.2-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 9,824 kB
  • sloc: ruby: 25,483; xml: 90; makefile: 20
file content (48 lines) | stat: -rw-r--r-- 1,282 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
module Kernel

  # Adds deep_clone method to an object which produces deep copy of it. It means
  # if you clone a Hash, every nested items and their nested items will be cloned.
  # Moreover deep_clone checks if the object is already cloned to prevent endless recursion.
  #
  #   obj = []
  #   a = [ true, false, obj ]
  #   b = a.deep_clone
  #   obj.push( 'foo' )
  #   p obj   # >> [ 'foo' ]
  #   p b[2]  # >> []
  #
  #  CREDIT: Jan Molic

  def deep_clone( obj=self, cloned={} )
    if cloned.has_key?( obj.object_id )
      return cloned[obj.object_id]
    else
      begin
        cl = obj.clone
      rescue Exception
        # unclonnable (TrueClass, Fixnum, ...)
        cloned[obj.object_id] = obj
        return obj
      else
        cloned[obj.object_id] = cl
        cloned[cl.object_id] = cl
        if cl.is_a?( Hash )
          cl.clone.each { |k,v|
            cl[k] = deep_clone( v, cloned )
          }
        elsif cl.is_a?( Array )
          cl.collect! { |v|
                  deep_clone( v, cloned )
          }
        end
        cl.instance_variables.each do |var|
          v = cl.instance_eval( var )
          v_cl = deep_clone( v, cloned )
          cl.instance_eval( "#{var} = v_cl" )
        end
        return cl
      end
    end
  end

end