Programming Ruby(読書ノート)-10章(異常)
5401 ワード
異常はリターンコードに比べて,誤り状況を論理コードからよりよく分離することができ,すなわち正常な論理のみに関心を持つことができ,あるいは自分が処理できる異常状況に関心を持つことができる.一方、戻りコードが1つのcallの後ろに複数のサブオペレーションがある場合、異常が発生すると、呼び出し者はどのステップでエラーが発生したのか分かりにくい.
10.1異常類
すべての組み込み例外クラスは、Exceptionクラスを継承します.
10.2処理異常
このメカニズムはjavaと同じです
複数のrescueの場合のマッチングルールはcase文に似ています.実際にparameter==$!,rescueが指定した例外クラスが$と!オブジェクトのクラスが同じまたはそのサブクラスである場合、rescueのコードが実行されます.
rescueの後にキャプチャされた例外を指定しなくても、デフォルトではStandardErrorが使用されます.
rescueは、Exceptionクラスのオブジェクトを返す限り、式の後になります.
システムエラー
オペレーティングシステムの操作を呼び出すと、エラーがエラーコードを返し、rubyはモジュールErrnoにSystemCallErrorのサブクラスとしてパッケージされます.
異常後のリソースクリーンアップ(Finally)
ensureを使用して、例外後にバッチを実行するコードを保証します.ensureは最後のrescueの後ろに置かれています.
rescueはまたelseを使用して異常が発生していない場合に実行する必要があるコードを処理することもできる.
エラー後に再試行
エラーが発生したら、retryブロックを使用して再実行します(パラメータを変更した後).
retryブロックはrescueブロックに入れて使用します.
10.3 Raising Exceptions(throwとは異なる)
アクティブraiseは例外です.raiseもfailもObjectクラスのメソッド(違い?)です.
構造方法は3つあります
1つ目は、現在の異常$を投げ出せ!(rescueブロックの場合)、またはRuntimeError($!が存在しない場合).
2つ目は、新しいRuntimeError例外を作成し、説明を設定することです.
3つ目は、新しい例外オブジェクトを作成し、2番目のパラメータの内容を割り当て、現在の実行スタックを3番目のパラメータに設定します.Object#callerメソッドは、現在の実行スタックを返します.
カスタムException
10.4 catch and throw
goto文に似ていますか?ある正常な状況では、実行体から飛び出して、実行されたこの部分を放棄したい.この場合catchとthrowを使用できます.
catchは、ラベル名(通常symbolまたはstring)を指定することによってコードブロックを定義します.throwが発生しない場合は、ブロックコード全体が正常に実行されます.
throwが発生するとrubyはスタックを一致するcatchポイントに圧縮し、現在の実行ブロックを終了する.throwにはオプションのパラメータがあり、値を割り当てるとcatchブロックの戻り値を変数に割り当てることができます.
throwは必ずしもcatchと静的に1つのブロック内に存在するわけではありません.次に、throwとなるメソッドを定義し、呼び出し時にcatchを使用します.
10.1異常類
すべての組み込み例外クラスは、Exceptionクラスを継承します.
10.2処理異常
# begin...rescue...end
require 'open-uri'
page= "podcasts"
file_name = "#{page}.html"
web_page = open("http://pragprog.com/#{page}")
output = File.open(file_name,"w")
begin
while line = web_page.gets
output.puts line
end
output.close
rescue Exception
STDERR.puts "Failed to download#{page}:#{$!}"
output.close
File.delete(file_name)
raise
end
# $! (Global variable)
このメカニズムはjavaと同じです
# java catch , rescue。
# rescue , $!
begin
eval string
rescue SyntaxError,NameError=>boom
print"String doesn't compile:"+boom
rescue StandardError=>bang
print"Error running script:"+bang
end
複数のrescueの場合のマッチングルールはcase文に似ています.実際にparameter==$!,rescueが指定した例外クラスが$と!オブジェクトのクラスが同じまたはそのサブクラスである場合、rescueのコードが実行されます.
rescueの後にキャプチャされた例外を指定しなくても、デフォルトではStandardErrorが使用されます.
rescueは、Exceptionクラスのオブジェクトを返す限り、式の後になります.
システムエラー
オペレーティングシステムの操作を呼び出すと、エラーがエラーコードを返し、rubyはモジュールErrnoにSystemCallErrorのサブクラスとしてパッケージされます.
異常後のリソースクリーンアップ(Finally)
ensureを使用して、例外後にバッチを実行するコードを保証します.ensureは最後のrescueの後ろに置かれています.
f = File.open("testFile")
begin
#
rescue
#
ensure
f.close
end
#open begin , ,
rescueはまたelseを使用して異常が発生していない場合に実行する必要があるコードを処理することもできる.
f=File.open("testfile")
begin
#..process
rescue
#..handleerror
else
puts"Congratulations--noerrors!"
ensure
f.close
end
エラー後に再試行
エラーが発生したら、retryブロックを使用して再実行します(パラメータを変更した後).
retryブロックはrescueブロックに入れて使用します.
# , @estmp ,
@esmtp = true
begin
if @estmp then @command.ehlo(helodom)
else @command.helo(helodom)
end
rescue ProtocolError
if @estmp then
@estmp = false
retry
else
raise
end
end
10.3 Raising Exceptions(throwとは異なる)
アクティブraiseは例外です.raiseもfailもObjectクラスのメソッド(違い?)です.
構造方法は3つあります
raise
raise "bad mp3 encoding"
raise InterfaceException, "keyboard failure", caller
1つ目は、現在の異常$を投げ出せ!(rescueブロックの場合)、またはRuntimeError($!が存在しない場合).
2つ目は、新しいRuntimeError例外を作成し、説明を設定することです.
3つ目は、新しい例外オブジェクトを作成し、2番目のパラメータの内容を割り当て、現在の実行スタックを3番目のパラメータに設定します.Object#callerメソッドは、現在の実行スタックを返します.
# ,
raise ArgumentError, "Name too big", caller[1..-1]
カスタムException
# 。
class RetryException < RuntimeError
attr :ok_to_retry
def initialize(ok_to_retry)
@ok_to_retry = ok_to_retry
end
end
#
def read_data(socket)
data = socket.read(512)
if data.nil?
raise RetryException.new(true), "transient read error"
end
#..normal processing
end
#rescue
begin
stuff = read_data(socket)
#..process stuff
rescue RetryException => detail
retry if detail.ok_to_retry
raise
end
10.4 catch and throw
goto文に似ていますか?ある正常な状況では、実行体から飛び出して、実行されたこの部分を放棄したい.この場合catchとthrowを使用できます.
word_list = File.open("wordlist")
catch (:done) do
result = []
while line = word_list.gets
word = line.chomp
throw :done unless word =~ /^\w+$/
result << word
end
puts result.reverse
end
catchは、ラベル名(通常symbolまたはstring)を指定することによってコードブロックを定義します.throwが発生しない場合は、ブロックコード全体が正常に実行されます.
throwが発生するとrubyはスタックを一致するcatchポイントに圧縮し、現在の実行ブロックを終了する.throwにはオプションのパラメータがあり、値を割り当てるとcatchブロックの戻り値を変数に割り当てることができます.
word_list=File.open("wordlist")
word_in_error=catch(:done) do
result=[]
while line=word_list.gets
word=line.chomp
throw(:done,word) unless word=~/^\w+$/
result<<word
end
puts result.reverse
end
if word_in_error
puts"Failed:'#{word_in_error}'found,but a word was expected"
end
produces:
Failed:'*wow*'found,butawordwasexpected
throwは必ずしもcatchと静的に1つのブロック内に存在するわけではありません.次に、throwとなるメソッドを定義し、呼び出し時にcatchを使用します.
def prompt_and_get(prompt)
print prompt
res = readline.chomp
throw :quit_requested if res=="!"
res
end
catch:quit_requested do
name =prompt_and_get("Name:")
age =prompt_and_get("Age: ")
sex =prompt_and_get("Sex: ")
#..
#processinformation
end