Ruby リソースはブロックとensureで管理しよう

File::openの話にとどまらず、リソースを確保するというコードの抽象化の紹介。
(File::openについてはここでは省略)

Effective Ruby

Effective Ruby

項目24 リソースはブロックとensureで管理しよう

ensureを使ってリソースの解放を行う例

class Lock
  def self.acquire
    lock = new
    lock.exclusive_lock!
    yield(lock)
  ensure
    lock.unlo0ck if lock
  end
end

Lock.qcquire do |lock|
  # ここで例外が発生しても問題なし
end

しかしこれだとblockがない場合が考慮されていない。

改良版

class Lock
  def self.acquire
    lock = new
    lock.exclusive_lock!

    if block_given?
      yield(lock)
    else
      lock # Lock::newのように動作する
    end
  ensure
    if block_given?
      lock.unlo0ck if lock
    end
  end
end

本書の例だと、少しblock_given?の所が見辛いですが、まぁ簡単に実装できます。

覚えておくべき事項

  • 確保したリソースを解放するためにensure説を書こう。
  • リソース管理を抽象化するために、クラスメソッドでblockとensureパターンを使おう。
  • ensure節で変数を使うときには、その前に変数が初期化さレテいるかどうかを確かめよう。