#
# Backport from Rails 4.0 active_support/core_ext/object/deep_dup.rb
#
raise "Code is removable" if Rails.version.to_f >= 4.0

require 'active_support/core_ext/object/duplicable'

class Object
  # Returns a deep copy of object if it's duplicable. If it's
  # not duplicable, returns +self+.
  #
  # object = Object.new
  # dup = object.deep_dup
  # dup.instance_variable_set(:@a, 1)
  #
  # object.instance_variable_defined?(:@a) #=> false
  # dup.instance_variable_defined?(:@a) #=> true
  def deep_dup
    duplicable? ? dup : self
  end
end

class Array
  # Returns a deep copy of array.
  #
  # array = [1, [2, 3]]
  # dup = array.deep_dup
  # dup[1][2] = 4
  #
  # array[1][2] #=> nil
  # dup[1][2] #=> 4
  def deep_dup
    map { |it| it.deep_dup }
  end
end

class Hash
  # Returns a deep copy of hash.
  #
  # hash = { a: { b: 'b' } }
  # dup = hash.deep_dup
  # dup[:a][:c] = 'c'
  #
  # hash[:a][:c] #=> nil
  # dup[:a][:c] #=> "c"
  def deep_dup
    each_with_object(dup) do |(key, value), hash|
      hash[key.deep_dup] = value.deep_dup
    end
  end
end