1# frozen_string_literal: true 2require "delegate" 3 4# Weak Reference class that allows a referenced object to be 5# garbage-collected. 6# 7# A WeakRef may be used exactly like the object it references. 8# 9# Usage: 10# 11# foo = Object.new # create a new object instance 12# p foo.to_s # original's class 13# foo = WeakRef.new(foo) # reassign foo with WeakRef instance 14# p foo.to_s # should be same class 15# GC.start # start the garbage collector 16# p foo.to_s # should raise exception (recycled) 17# 18 19class WeakRef < Delegator 20 21 ## 22 # RefError is raised when a referenced object has been recycled by the 23 # garbage collector 24 25 class RefError < StandardError 26 end 27 28 @@__map = ::ObjectSpace::WeakMap.new 29 30 ## 31 # Creates a weak reference to +orig+ 32 # 33 # Raises an ArgumentError if the given +orig+ is immutable, such as Symbol, 34 # Integer, or Float. 35 36 def initialize(orig) 37 case orig 38 when true, false, nil 39 @delegate_sd_obj = orig 40 else 41 @@__map[self] = orig 42 end 43 super 44 end 45 46 def __getobj__ # :nodoc: 47 @@__map[self] or defined?(@delegate_sd_obj) ? @delegate_sd_obj : 48 Kernel::raise(RefError, "Invalid Reference - probably recycled", Kernel::caller(2)) 49 end 50 51 def __setobj__(obj) # :nodoc: 52 end 53 54 ## 55 # Returns true if the referenced object is still alive. 56 57 def weakref_alive? 58 @@__map.key?(self) or defined?(@delegate_sd_obj) 59 end 60end 61