lib/finalize.rb


DEFINITIONS

This source file includes following functions.


   1  #
   2  #   finalizer.rb - 
   3  #       $Release Version: 0.3$
   4  #       $Revision: 1.4 $
   5  #       $Date: 1998/02/27 05:34:33 $
   6  #       by Keiju ISHITSUKA
   7  #
   8  # --
   9  #
  10  #   Usage:
  11  #
  12  #   add(obj, dependant, method = :finalize, *opt)
  13  #   add_dependency(obj, dependant, method = :finalize, *opt)
  14  #       add dependency R_method(obj, dependant)
  15  #
  16  #   delete(obj_or_id, dependant, method = :finalize)
  17  #   delete_dependency(obj_or_id, dependant, method = :finalize)
  18  #       delete dependency R_method(obj, dependant)
  19  #   delete_all_dependency(obj_or_id, dependant)
  20  #       delete dependency R_*(obj, dependant)
  21  #   delete_by_dependant(dependant, method = :finalize)
  22  #       delete dependency R_method(*, dependant)
  23  #   delete_all_by_dependant(dependant)
  24  #       delete dependency R_*(*, dependant)
  25  #   delete_all
  26  #       delete all dependency R_*(*, *)
  27  #
  28  #   finalize(obj_or_id, dependant, method = :finalize)
  29  #   finalize_dependency(obj_or_id, dependant, method = :finalize)
  30  #       finalize the dependant connected by dependency R_method(obj, dependtant).
  31  #   finalize_all_dependency(obj_or_id, dependant)
  32  #       finalize all dependants connected by dependency R_*(obj, dependtant).
  33  #   finalize_by_dependant(dependant, method = :finalize)
  34  #       finalize the dependant connected by dependency R_method(*, dependtant).
  35  #   finalize_all_by_dependant(dependant)
  36  #       finalize all dependants connected by dependency R_*(*, dependant).
  37  #   finalize_all
  38  #       finalize all dependency registered to the Finalizer.
  39  #
  40  #   safe{..}
  41  #       stop invoking Finalizer on GC.
  42  #
  43  
  44  module Finalizer
  45    RCS_ID='-$Id: finalize.rb,v 1.4 1998/02/27 05:34:33 keiju Exp keiju $-'
  46  
  47    class <<self
  48      # @dependency: {id => [[dependant, method, *opt], ...], ...}
  49  
  50      # add dependency R_method(obj, dependant)
  51      def add_dependency(obj, dependant, method = :finalize, *opt)
  52        ObjectSpace.call_finalizer(obj)
  53        method = method.intern unless method.kind_of?(Integer)
  54        assoc = [dependant, method].concat(opt)
  55        if dep = @dependency[obj.id]
  56          dep.push assoc
  57        else
  58          @dependency[obj.id] = [assoc]
  59        end
  60      end
  61      alias add add_dependency
  62  
  63      # delete dependency R_method(obj, dependant)
  64      def delete_dependency(id, dependant, method = :finalize)
  65        id = id.id unless id.kind_of?(Integer)
  66        method = method.intern unless method.kind_of?(Integer)
  67        for assoc in @dependency[id]
  68          assoc.delete_if do
  69            |d, m, *o|
  70            d == dependant && m == method
  71          end
  72          @dependency.delete(id) if assoc.empty?
  73        end
  74      end
  75      alias delete delete_dependency
  76  
  77      # delete dependency R_*(obj, dependant)
  78      def delete_all_dependency(id, dependant)
  79        id = id.id unless id.kind_of?(Integer)
  80        method = method.intern unless method.kind_of?(Integer)
  81        for assoc in @dependency[id]
  82          assoc.delete_if do
  83            |d, m, *o|
  84            d == dependant
  85          end
  86          @dependency.delete(id) if assoc.empty?
  87        end
  88      end
  89  
  90      # delete dependency R_method(*, dependant)
  91      def delete_by_dependant(dependant, method = :finalize)
  92        method = method.intern unless method.kind_of?(Integer)
  93        for id in @dependency.keys
  94          delete(id, dependant, method)
  95        end
  96      end
  97  
  98      # delete dependency R_*(*, dependant)
  99      def delete_all_by_dependant(dependant)
 100        for id in @dependency.keys
 101          delete_all_dependency(id, dependant)
 102        end
 103      end
 104  
 105      # finalize the depandant connected by dependency R_method(obj, dependtant)
 106      def finalize_dependency(id, dependant, method = :finalize)
 107        id = id.id unless id.kind_of?(Integer)
 108        method = method.intern unless method.kind_of?(Integer)
 109        for assocs in @dependency[id]
 110          assocs.delete_if do
 111            |d, m, *o|
 112            d.send(m, id, *o) if ret = d == dependant && m == method
 113            ret
 114          end
 115          @dependency.delete(id) if assoc.empty?
 116        end
 117      end
 118      alias finalize finalize_dependency
 119  
 120      # finalize all dependants connected by dependency R_*(obj, dependtant)
 121      def finalize_all_dependency(id, dependant)
 122        id = id.id unless id.kind_of?(Integer)
 123        method = method.intern unless method.kind_of?(Integer)
 124        for assoc in @dependency[id]
 125          assoc.delete_if do
 126            |d, m, *o|
 127            d.send(m, id, *o) if ret = d == dependant
 128          end
 129          @dependency.delete(id) if assoc.empty?
 130        end
 131      end
 132  
 133      # finalize the dependant connected by dependency R_method(*, dependtant)
 134      def finalize_by_dependant(dependant, method = :finalize)
 135        method = method.intern unless method.kind_of?(Integer)
 136        for id in @dependency.keys
 137          finalize(id, dependant, method)
 138        end
 139      end
 140  
 141      # finalize all dependants connected by dependency R_*(*, dependtant)
 142      def finalize_all_by_dependant(dependant)
 143        for id in @dependency.keys
 144          finalize_all_dependency(id, dependant)
 145        end
 146      end
 147  
 148      # finalize all dependants registered to the Finalizer.
 149      def finalize_all
 150        for id, assocs in @dependency
 151          for dependant, method, *opt in assocs
 152            dependant.send(method, id, *opt)
 153          end
 154          assocs.clear
 155        end
 156      end
 157  
 158      # method to call finalize_* safely.
 159      def safe
 160        old_status = Thread.critical
 161        Thread.critical = true
 162        ObjectSpace.remove_finalizer(@proc)
 163        begin
 164          yield
 165        ensure
 166          ObjectSpace.add_finalizer(@proc)
 167          Thread.critical = old_status
 168        end
 169      end
 170  
 171      private
 172  
 173      # registering function to ObjectSpace#add_finalizer
 174      def final_of(id)
 175        if assocs = @dependency.delete(id)
 176          for dependant, method, *opt in assocs
 177            dependant.send(method, id, *opt)
 178          end
 179        end
 180      end
 181  
 182    end
 183    @dependency = Hash.new
 184    @proc = proc{|id| final_of(id)}
 185    ObjectSpace.add_finalizer(@proc)
 186  end