あなたならどう書く - 可変個のネストしたブロックつきメソッドの呼び出し

Ruby では Dir.chdir とか Kernel#open, Mutex#synchronize のように、ブロックを渡してそのブロックの呼び出しの前後に準備/後片付けの処理で挟むためのメソッドというのがありますね。ブロックから抜けると自動的に後始末をしてくれるので便利です。

ブロックの中でそのようなメソッドをネストさせることもできます。

@mutex.synchronize do
  open(file) do
   ...
  end
end

そこで複数のオブジェクトについてそのようなブロックつきメソッドをネストさせて呼びだしたい、しかもオブジェクトの数は可変個(たとえば配列に入ってくる)にしたいという時にどう書くのか考えてみました。思ったよりも難しかったです。

class A
  def initialize(n)
    @n = n
  end
  def guard(&blk)
    begin
      p [:before, @n]
      blk.call
    ensure
      p [:after, @n]
    end
  end
end

ary = Array.new(5){|i| A.new(i) }

enum = ary.to_enum
callback = lambda do
  begin
    enum.next.guard(&callback)
  rescue StopIteration
    p :inner
  end
end
callback.call

実行結果はこんな風になります。

[:before, 0]
[:before, 1]
[:before, 2]
[:before, 3]
[:before, 4]
:inner
[:after, 4]
[:after, 3]
[:after, 2]
[:after, 1]
[:after, 0]

最初にこの問題を考えついた時には直感的に継続(callcc とか Fiber とか)が使えるんじゃないかと思いましたが、あまりうまい使い方が思いつきませんでした。to_enum でEnumerator を作っているので継続を使っているといえば使ってはいますが、そこは別に ary.shift しても良いので本質的ではないです。

もっといい書き方があるんじゃないかと思うのですが、思いついたら教えてください。