class Backports::Ractor::Cloner
Public Class Methods
deep_clone(obj)
click to toggle source
# File lib/backports/ractor/cloner.rb, line 9 def deep_clone(obj) return obj if Ractor.ractor_shareable_self?(obj, false) { false } new.deep_clone(obj) end
new()
click to toggle source
# File lib/backports/ractor/cloner.rb, line 18 def initialize @processed = {}.compare_by_identity @changed = nil end
Public Instance Methods
deep_clone(obj)
click to toggle source
# File lib/backports/ractor/cloner.rb, line 23 def deep_clone(obj) result = process(obj) do |r| copy_contents(r) end return result if result Ractor.ractor_mark_set_shareable(@processed) obj end
Private Instance Methods
clone_deeper(obj) { |result| ... }
click to toggle source
Yields a deep copy. If no deep copy is needed, `obj` is returned and nothing is yielded
# File lib/backports/ractor/cloner.rb, line 36 def clone_deeper(obj) return obj if Ractor.ractor_shareable_self?(obj, false) { false } result = process(obj) do |r| copy_contents(r) end return obj unless result yield result if block_given? result end
copy_contents(obj)
click to toggle source
modifies in place `obj` by calling `deep clone` on its contents
# File lib/backports/ractor/cloner.rb, line 77 def copy_contents(obj) case obj when ::Hash if obj.default clone_deeper(obj.default) do |copy| obj.default = copy end end obj.transform_keys! { |key| clone_deeper(key) } obj.transform_values! { |value| clone_deeper(value) } when ::Array obj.map! { |item| clone_deeper(item) } when ::Struct obj.each_pair do |key, item| clone_deeper(item) { |copy| obj[key] = copy } end end obj.instance_variables.each do |var| clone_deeper(obj.instance_variable_get(var)) do |copy| obj.instance_variable_set(var, copy) end end end
process(obj) { |result| ... }
click to toggle source
Yields if `obj` is a new structure Returns the deep copy, or `false` if no deep copy is needed
# File lib/backports/ractor/cloner.rb, line 50 def process(obj) @processed.fetch(obj) do # For recursive structures, assume that we'll need a duplicate. # If that's not the case, we will have duplicated the whole structure # for nothing... @processed[obj] = result = obj.dup changed = track_change { yield result } return false if obj.frozen? && !changed @changed = true result.freeze if obj.frozen? result end end
track_change() { || ... }
click to toggle source
returns if the block called `deep clone` and that the deep copy was needed
# File lib/backports/ractor/cloner.rb, line 67 def track_change prev = @changed @changed = false yield @changed ensure @changed = prev end