Ruby の Python の「with」に相当します。

概要

Python では、with ステートメントを使用して、スローされた例外や関数呼び出しが返されたかどうかに関係なく、クリーンアップ コードが常に呼び出されるようにします。例えば:

with open("temp.txt", "w") as f:
    f.write("hi")
    raise ValueError("spitespite")

ここでは、例外が発生したにもかかわらず、ファイルは閉じられています。より良い説明はここにあります。

Ruby にはこの構造に相当するものはありますか?それとも、Ruby には継続があるので、コーディングすることはできますか?

解決策

Ruby は、リテラルの匿名プロシージャ (Ruby ではブロックと呼ばれます) を構文的に軽量にサポートしています。したがって、このために新しい言語機能は必要ありません。

したがって、通常行うことは、コードのブロックを取得し、リソースを割り当て、そのリソースのコンテキストでコードのブロックを実行して、リソースを閉じるメソッドを作成することです。

このようなもの:

def with(klass, *args)
  yield r = klass.open(*args)
ensure
  r.close
end

次のように使用できます。

with File, 'temp.txt', 'w' do |f|
  f.write 'hi'
  raise 'spitespite'
end

ただし、これは非常に手順的な方法です。 Ruby はオブジェクト指向言語です。つまり、ファイルのコンテキストでコードのブロックを適切に実行する責任は File クラスに属する必要があります。

File.open 'temp.txt', 'w' do |f|
  f.write 'hi'
  raise 'spitespite'
end

これは次のように実装できます。

def File.open(*args)
  f = new(*args)
  return f unless block_given?
  yield f
ensure
  f.close if block_given?
end

これは、Ruby コア ライブラリ、標準ライブラリ、サードパーティ ライブラリの多くのクラスによって実装される一般的なパターンです。

一般的な Python コンテキスト マネージャー プロトコルとより密接に対応するものは次のとおりです。

def with(ctx)
  yield ctx.setup
ensure
  ctx.teardown
end

class File
  def setup; self end
  alias_method :teardown, :close
end

with File.open('temp.txt', 'w') do |f|
  f.write 'hi'
  raise 'spitespite'
end

これは Python の例と事実上区別がつきませんが、言語に新しい構文を追加する必要がないことに注意してください。