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 の例と事実上区別がつきませんが、言語に新しい構文を追加する必要がないことに注意してください。