2024-01-12 09:53:53 -08:00
|
|
|
# typed: strict
|
2023-11-29 15:18:14 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2024-01-12 09:53:53 -08:00
|
|
|
require "extend/object/duplicable"
|
2023-11-29 15:18:14 +00:00
|
|
|
|
|
|
|
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
|
2024-01-12 09:53:53 -08:00
|
|
|
sig { returns(T.self_type) }
|
2024-01-12 15:17:12 -08:00
|
|
|
def deep_dup
|
|
|
|
duplicable? ? dup : self
|
|
|
|
end
|
2023-11-29 15:18:14 +00:00
|
|
|
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
|
2024-01-12 09:53:53 -08:00
|
|
|
sig { returns(T.self_type) }
|
2024-01-12 15:17:12 -08:00
|
|
|
def deep_dup
|
|
|
|
T.unsafe(self).map(&:deep_dup)
|
|
|
|
end
|
2023-11-29 15:18:14 +00:00
|
|
|
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"
|
2024-01-12 09:53:53 -08:00
|
|
|
sig { returns(T.self_type) }
|
2023-11-29 15:18:14 +00:00
|
|
|
def deep_dup
|
|
|
|
hash = dup
|
|
|
|
each_pair do |key, value|
|
2024-01-12 09:53:53 -08:00
|
|
|
case key
|
|
|
|
when ::String, ::Symbol
|
|
|
|
hash[key] = T.unsafe(value).deep_dup
|
2023-11-29 15:18:14 +00:00
|
|
|
else
|
|
|
|
hash.delete(key)
|
2024-01-12 09:53:53 -08:00
|
|
|
hash[T.unsafe(key).deep_dup] = T.unsafe(value).deep_dup
|
2023-11-29 15:18:14 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
hash
|
|
|
|
end
|
|
|
|
end
|
2024-01-12 09:53:53 -08:00
|
|
|
|
|
|
|
class Module
|
|
|
|
# Returns a copy of module or class if it's anonymous. If it's
|
|
|
|
# named, returns +self+.
|
|
|
|
#
|
|
|
|
# Object.deep_dup == Object # => true
|
|
|
|
# klass = Class.new
|
|
|
|
# klass.deep_dup == klass # => false
|
|
|
|
sig { returns(T.self_type) }
|
|
|
|
def deep_dup
|
|
|
|
if name.nil?
|
|
|
|
super
|
|
|
|
else
|
|
|
|
self
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|