1.4.1.9. fejezet, Kivételkezelés

Nullával való osztás kivételt generál, ezt kezeljük az alábbi kódban:

begin 
  x = 1/0
rescue Exception
  x = 0
  puts( $!.class )
  puts( $! )
end

Az Exception a legtágabb értelembe vett kivétel. Lehet szűkíteni a kivételkezelése (ZeroDivisionError) és lehet változóba tenni a kivétel objektumot ami segíti a jobb olvashatóságát.

def calc( val1, val2 ) 
  begin
    result = val1 / val2 
  rescue TypeError, NoMethodError => e 
    puts( e.class ) 
    puts( e ) 
    puts( "One of the values is not a number!" ) 
    result = nil 
  rescue Exception => e 
    puts( e.class ) 
    puts( e ) 
    result = nil
  end 
  return result
end

Lehet olyan szakaszt tenni a kivétel kezelésébe, ami mindenféle kép lefut (ensure, pl. fájl lezárása), és lehet olyant, ami csak akkor fut le, ha nem történt kivétel (else).

f = File.new( "test.txt" )
begin
  for i in (1..6) do
    puts("line number: #{f.lineno}")
    line = f.gets.chomp
    num = line.to_i puts( "Line '#{line}' is converted to #{num}" )
    puts( 100 / num )
  end
rescue Exception => e
  puts( e.class )
  puts( "Message: " + e )
  puts( e.backtrace )
else
  puts("no error")
ensure
  f.close
  puts( "File closed" )
end

Van egy retry kulcsszó is, amit a kivétel kezelésénél alkalmazhatunk. Ha újra szeretnénk értékelni az egész kivételkezelő részt, ezzel megtehetjük. Például helyezzünk el egy számlálót a próbálkozások számolására a kivétel kezelőjébe:

tries=0
begin
  tries+=1
rescue Exception
  if tries < 3 then # szamlalo ellenorzes
    retry
ensure
  puts("tries: "+tries.to_s)
end

Használjuk a raise kulcsszót, ha kivételt generálására van szükségünk. Ennek változatai:

raise # RuntimeError kivétel generálása
raise "Egy ismeretlen épp most jött létre!" # paraméter a RuntimeError-hoz
raise ZeroDivisionError
raise ZeroDivisionError.new( "Attól tartok nullával osztottál, ami hibát generált." )

Kivétel osztály létrehozása leszármaztatással lehetséges:

class NoNameError < Exception
  def to_str
    "Névtelen kivétel!"
  end
end

Most hagyjuk el a begin és end kulcsszavakat:

def calc 
    result = 1/0
  rescue Exception => e 
    puts( e.class )
    puts( e ) 
    result = nil 
  return result 
end
module Y
    @@x = 1/0 
  rescue Exception => e
    puts( e.class )
    puts( e )
end

Itt már látható, hogy modulok hogyan készülnek. Maradjunk még a kivételeknél. Kivétel továbbadásához a throw kulcsszót használhatjuk a rescue részben. A catch szintén használható, bár nem elegáns módja a kivétel kezelésnek.

catch( :finished) {
  print( 'Írjon be egy számot: ' )
  num = gets().chomp.to_i
  begin
    result = 100 / num 
  rescue Exception => e
    throw :finished # ugrás a blokk végére
  end
  puts( "A számítás eredménye #{result}" )
} # vége of :finished catch blokknak