Class: Object

Inherits:
BasicObject
Defined in:
lib/taskjuggler/deep_copy.rb

Overview

This file extends some Ruby core classes to add deep-copying support. I’m aware of the commonly suggested method using Marshal:

class Object

def deep_copy
  Marshal.load(Marshal.dump(self))
end

end

But just because I program in Ruby, I don’t have to write bloatware. It’s like taking a trip to the moon and back to shop groceries at the store around the corner. I’m not sure if I need more special cases than Array and Hash, but this file works for me.

In certain cases the full deep copy may not be desired. To preserve references to objects, you need to overload deep_clone and handle the special cases. Alternatively, an object can be frozen to prevent deep copies.

Instance Method Summary collapse

Instance Method Details

#deep_cloneObject

This is a variant of Object#clone that returns a deep copy of an object.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/taskjuggler/deep_copy.rb', line 36

def deep_clone
  # We can't clone frozen objects. So just return a reference to them.
  # Built-in classed can't be cloned either. The check below is probably
  # cheaper than the frequent (hiddent) exceptions from those objects.
  return self if frozen? || nil? || is_a?(Integer) || is_a?(Float) ||
                 is_a?(TrueClass) || is_a?(FalseClass) || is_a?(Symbol)

  # In case we have loops in our graph, we return references, not
  # deep-copied objects.
  if RUBY_VERSION < '1.9.0'
    return @clonedObject if instance_variables.include?('@clonedObject')
  else
    return @clonedObject if instance_variables.include?(:@clonedObject)
  end

  # Clone the current Object (shallow copy with internal state)
  begin
    @clonedObject = clone
  rescue TypeError
    return self
  end
  # Recursively copy all instance variables.
  @clonedObject.instance_variables.each do |var|
    val = instance_variable_get(var).deep_clone
    @clonedObject.instance_variable_set(var, val)
  end
  if kind_of?(Array)
    @clonedObject.collect! { |x| x.deep_clone }
  elsif kind_of?(Hash)
    @clonedObject.each { |key, val| store(key, val.deep_clone) }
  end
  # Remove the @clonedObject again.
  if RUBY_VERSION < '1.9.0'
    remove_instance_variable('@clonedObject')
  else
    remove_instance_variable(:@clonedObject)
  end
end