24. Hata İşleme: rescue
deyimi
Çalıştırılan bir yazılım beklenmeyen sorunlar doğurabilir. Okunmaya çalışılan bir dosya mevcut olmayabilir ya da veri kaydetmemek istediğimiz disk dolu olabilir yada kullanıcı beklenmeyen bir girdi yapabilir.
ruby> file = open("bir_dosya") ERR: No such file or directory @ rb_sysopen - bir_dosya
Güçlü bir yazılım bu gibi durumları hassasiyetle yakalayacaktır. C yazılımcılarından, hata doğurabilecek her sistem çağrısının sonucunu kontrol etmeleri ve anında ne yapılacağına ilişkin karar vermeleri beklenir:
FILE *file = fopen("bir_dosya", "r"); if (file == NULL) { fprintf( stderr, "Dosya mevcut değil.\n" ); exit(1); } bytes_read = fread( buf, 1, bytes_desired, file ); if (bytes_read != bytes_desired ) { /* hata giderme işlemleri... */ } ...
Bu yazılımcıları dikkatsizliğe ve ihmalciliğe iten, üstelik hataları tam olarak yakalayamayan bir yazılım geliştirmenize yol açan sıkıcı bir uygulamadır. Öte yandan, işi doğru düzgün yapmak, yakalanabilecek bir çok hata olduğu için yazılımın okunabilirliğini oldukça zorlaştıracaktır.
Güncel bir çok dilde olduğu gibi Ruby'de de, yazılımcıyı ya da sonradan kodumuzu okuyan kişileri sıkıntıya sokmadan, sürprizleri kod bloklarından soyutlayan bir yolla yakalayabiliriz.
begin ile işaretlenmiş kod bloğu bir istisnayla karşılaşana dek çalıştırılır, hata durumunda denetimi rescue ile işaretlenmiş kod bloğuna verir. Eğer hiçbir istisnayla karşılaşılmazsa rescue kodu kullanılmaz. Aşağıdaki yöntem bir metin dosyasının ilk satırını, bir istisna ile karşılaşırsa nil döndürür:
def first_line( filename ) begin file = open("bir_dosya") info = file.gets file.close info # Değerlendirmeye alınan son şey dönüş değeri rescue nil # Dosyayı okuyamıyor musunuz? O zaman bir ileti dönmez. end end
Bir sorunla yaratıcı bir biçimde ilgilenmek istediğimiz zamanlar olacaktır. Örneğin dosyaya erişmek mümkün değilse standart girdi yerine başka bir şey kullanmak isteyebiliriz:
begin file = open("bir_dosya") rescue file = STDIN end begin # ... girdiyi değerlendir ... rescue # ... burada diğer istisnalarla uğraş. end
begin kodunu tekrar çalıştırmak için rescue'nun içinde retry kullanabiliriz. Bu bize önceki örneğimizi daha kısa şekilde yazmamıza izin verir:
fname = "bir_dosya" begin file = open(fname) # ... girdiyi degerlendir ... rescue fname = "STDIN" retry end
Ancak burada bir kusur bulunmaktadır. Hiç olmayan bir dosya bu kodun sonsuz bir döngüde kendisini tekrar etmesini sağlayacaktır. retry kullanırken bu tür durumlara dikkat etmelisiniz.
Her Ruby kütüphanesi, sizin de kendi kodunuzda yapabileceğiniz gibi, herhangi bir hata karşısında bir istisna oluşturur. Bir istisnayı ortaya çıkarmak için raise kullanılır. raise tek değer olarak istisnayı açıklayan bir dizge alır. Bu değer isteğe bağlıdır ancak atlanmaması gereken bir husustur. Özel değişkenlerden olan $! ile sonradan ulaşılabilir.
ruby> raise "deneme hatası" ERR: deneme hatası ruby> begin | raise "dnm2" | rescue | print "Bir hata meydana geldi: ",$!, "\n" | end Bir hata meydana geldi: dnm2 nil