デストラクタ

class TestDestructor
  @@refcount = 0
  @@filelist = [] # TestDestructorが開いているファイルのリスト

  def initialize
    _set_finalizer(nil)
    @@refcount+=1
  end

  def _set_finalizer( data)
    ObjectSpace.undefine_finalizer(self)
    ObjectSpace.define_finalizer( self, TestDestructor.cb(data))
    @@filelist << data if data
  end

  def open( name)
    close
    p ["open", name]
    @name = name
    _set_finalizer(@name)
  end

  def close()
    return unless @name
    p ["close", @name]
    @@filelist.delete_at(@@filelist.index(@name))
    @name = nil
    _set_finalizer(nil)
  end

  # 明示的な終了
  def quit()
    close()
    # 開いているファイルがあるのでここで帰る
    return if @@filelist.size>0
    # 終了処理
    p ["quit"]
  end

  def TestDestructor.cb( data)
    lambda {
      # まだファイルを開いているなら閉じる
      p ["close_in_cb", data] if data
      @@refcount -= 1
      p ["quit_in_cb"] if (@@refcount==0)
        # 誰もTestDestructorを参照していないので強制終了する
    }
  end

end

p "-- start --"
d = TestDestructor.new()
d.open( "test")
d2 = TestDestructor.new()
d.open( "test2")
d2.open( "bar")
d2.quit()
p "-- end --"

これで,ファイルを開きっぱなしにしても勝手に閉じてくれる?
tempfile.rbを見ているうちに面倒になったので,適当に書き殴ってみた.


undefine_finalizerで検索してもあまり情報が出てこない.もっとましなやり方があるのだろうか.それとも自明すぎて誰も書いていないだけ?RAAのgonzuiで検索してもあまり出てこないところを見ると前者のような気がする.


この擬似コードの実際の使い道を考えると,a=TestDestructor.new(サーバに接続)→a.quit(接続オフ)→a.openとすると,接続が切れてるのでa.openに失敗する.quitの呼び出しを禁止するか,openで毎回接続を確認して再接続するか.