Ya, ensurememastikan bahwa kode selalu dievaluasi. Itu sebabnya disebut ensure. Jadi, itu setara dengan Java dan C # finally.
Aliran umum dari begin/ rescue/ else/ ensure/ endterlihat seperti ini:
begin
# something which might raise an exception
rescue SomeExceptionClass => some_variable
# code that deals with some exception
rescue SomeOtherException => some_other_variable
# code that deals with some other exception
else
# code that runs only if *no* exception was raised
ensure
# ensure that this code always runs, no matter what
# does not change the final value of the block
end
Anda bisa keluar rescue, ensureatau else. Anda juga dapat mengabaikan variabel dalam hal ini Anda tidak akan dapat memeriksa pengecualian dalam kode penanganan pengecualian Anda. (Ya, Anda selalu dapat menggunakan variabel pengecualian global untuk mengakses pengecualian terakhir yang dimunculkan, tapi itu sedikit gila.) Dan Anda dapat meninggalkan kelas pengecualian, dalam hal ini semua pengecualian yang mewarisi dari StandardErrorakan ditangkap. (Harap dicatat bahwa ini tidak berarti bahwa semua pengecualian tertangkap, karena ada pengecualian yang contoh Exceptiontapi tidak StandardError. Pengecualian Kebanyakan sangat parah bahwa kompromi integritas program seperti SystemStackError, NoMemoryError, SecurityError, NotImplementedError, LoadError, SyntaxError, ScriptError, Interrupt,SignalExceptionatau SystemExit.)
Beberapa blok membentuk blok pengecualian implisit. Sebagai contoh, definisi metode secara implisit juga merupakan blok pengecualian, jadi alih-alih menulis
def foo
begin
# ...
rescue
# ...
end
end
Anda hanya menulis
def foo
# ...
rescue
# ...
end
atau
def foo
# ...
ensure
# ...
end
Hal yang sama berlaku untuk classdefinisi dan moduledefinisi.
Namun, dalam kasus spesifik yang Anda tanyakan, sebenarnya ada ungkapan yang jauh lebih baik. Secara umum, ketika Anda bekerja dengan beberapa sumber daya yang Anda perlu bersihkan pada akhirnya, Anda melakukannya dengan melewati blok ke metode yang melakukan semua pembersihan untuk Anda. Ini mirip dengan usingblok di C #, kecuali bahwa Ruby sebenarnya cukup kuat sehingga Anda tidak perlu menunggu imam besar Microsoft turun dari gunung dan dengan ramah mengubah kompiler mereka untuk Anda. Di Ruby, Anda bisa menerapkannya sendiri:
# This is what you want to do:
File.open('myFile.txt', 'w') do |file|
file.puts content
end
# And this is how you might implement it:
def File.open(filename, mode='r', perm=nil, opt=nil)
yield filehandle = new(filename, mode, perm, opt)
ensure
filehandle&.close
end
Dan apa yang Anda ketahui: ini sudah tersedia di perpustakaan inti sebagai File.open. Tetapi ini adalah pola umum yang dapat Anda gunakan dalam kode Anda sendiri, untuk menerapkan segala jenis pembersihan sumber daya (à la usingdalam C #) atau transaksi atau apa pun yang mungkin Anda pikirkan.
Satu-satunya kasus di mana ini tidak berhasil, jika memperoleh dan melepaskan sumber daya didistribusikan di berbagai bagian program. Tetapi jika dilokalkan, seperti dalam contoh Anda, maka Anda dapat dengan mudah menggunakan blok sumber daya ini.
BTW: di C # modern, usingsebenarnya berlebihan, karena Anda dapat mengimplementasikan blok sumber daya gaya-Ruby sendiri:
class File
{
static T open<T>(string filename, string mode, Func<File, T> block)
{
var handle = new File(filename, mode);
try
{
return block(handle);
}
finally
{
handle.Dispose();
}
}
}
// Usage:
File.open("myFile.txt", "w", (file) =>
{
file.WriteLine(contents);
});
beginblok.