Ruby - 基本的な文法 - 例外

 クラウディア
1. 概要
2. 基本
3. 例外発生時のオブジェクトをキャッチする
4. エラーの内容を出力する
5. 複数の例外をキャッチする

1. 概要

 「Ruby」の例外処理について、記述します。  本項は、下記のサイトを参考にさせていただきました。
【Ruby】エラー処理と例外処理」
「Rubyの例外とその捕捉――基本のbegin~rescue~endから ... - @IT

2. 基本

 「Ruby」で例外をキャッチする基本は、以下のように記述します。

begin
  処理
rescue
  例外が起こった場合の処理
ensure
  例外の有無に関わらず行う後処理
end
 使わない例題を記載するのはあまりわたしの好みではありませんが。  まぁ、これはあまり使わないでしょうね。

3. 生時のオブジェクトをキャッチする

 例外が発生したオブジェクトをキャッチするには、以下のように記述します。

begin
  処理
rescue => オブジェクトの変数名
  例外が起こった場合の処理
ensure
  例外の有無に関わらず行う後処理
end
 発生した例外の処理によって処理を分けるには、以下のように記述します。

begin
  処理
rescue Errno::EXXX => オブジェクトの変数名	#	Errno::EXXX 例外発生時の処理
  例外が起こった場合の処理
rescue => オブジェクトの変数名				#	上記までにキャッチできなかった例外発生時の処理
  例外が起こった場合の処理
ensure
  例外の有無に関わらず行う後処理
end
 Errno::EXXX の具体的な内容は「Ruby 2.4.0 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > Errno::EXXXクラス」に記載してあります。

4. エラーの内容を出力する

 例外発生時にはその内容がわからないと対処できないので、それを出力したいものです。  下記のような形式で書きます。

#!/usr/bin/env ruby

require 'nokogiri'
require 'open-uri'

begin
  url = URI.parse(ARGV[0])
  html = OpenURI::open_uri(url).read
  html.sub!(/^<!DOCTYPE html(.*)$/, '<!DOCTYPE html>')
  doc  = Nokogiri::HTML(html)

  puts "#{doc}"

rescue => error
  puts "例外発生"
  puts "#{error.backtrace}"
  puts "[#{self.class.name}][#{error.message}]"
ensure
  例外の有無に関わらず行う後処理
end
 これを

> ./ソースファイル名.rb URI
 という形式で実行すると URI の HTML を出力するわけですが。  存在しない URI や誤った形式の URI を指定すると例外が発生します。  バックトレースやエラー内容を表示します。  例外クラスの基本的なメソッドに関しては「Ruby 2.4.0 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > Exceptionクラス」をご参照ください。  以下、実際にやってみた結果です。

> ./ソースファイル名.rb http://www./
例外発生
["/usr/local/lib/ruby/2.4/net/http.rb:906:in `rescue in block in connect'", "/usr/local/lib/ruby/2.4/net/http.rb:903:in `block in connect'", "/usr/local/lib/ruby/2.4/timeout.rb:93:in `block in timeout'", "/usr/local/lib/ruby/2.4/timeout.rb:103:in `timeout'", "/usr/local/lib/ruby/2.4/net/http.rb:902:in `connect'", "/usr/local/lib/ruby/2.4/net/http.rb:887:in `do_start'", "/usr/local/lib/ruby/2.4/net/http.rb:876:in `start'", "/usr/local/lib/ruby/2.4/open-uri.rb:323:in `open_http'", "/usr/local/lib/ruby/2.4/open-uri.rb:741:in `buffer_open'", "/usr/local/lib/ruby/2.4/open-uri.rb:212:in `block in open_loop'", "/usr/local/lib/ruby/2.4/open-uri.rb:210:in `catch'", "/usr/local/lib/ruby/2.4/open-uri.rb:210:in `open_loop'", "/usr/local/lib/ruby/2.4/open-uri.rb:151:in `open_uri'", "./test02.rb:8:in `<main>'"]
[Object][Failed to open TCP connection to www.:80 (getaddrinfo: hostname nor servname provided, or not known)]

> ./ソースファイル名.rb http://www.日本語
例外発生
["/usr/local/lib/ruby/2.4/uri/rfc3986_parser.rb:21:in `split'", "/usr/local/lib/ruby/2.4/uri/rfc3986_parser.rb:73:in `parse'", "/usr/local/lib/ruby/2.4/uri/common.rb:231:in `parse'", "./test02.rb:7:in `<main>'"]
[Object][URI must be ascii only "http://www.\u65E5\u672C\u8A9E"]
- 余談 -

 わざとエラーを発生させるつもちで URI に「http://www.hogehoge.co.jp/」や「http://www.hogehoge.ne.jp/」を指定したら、取得できちゃいました。
 ドメイン登録されているようです。

5. 複数の例外をキャッチする

 なんだか馬鹿みたいに

begin
  処理
rescue Errno::EXX1 => オブジェクトの変数名	#	Errno::EXX1 例外発生時の処理
  例外が起こった場合の処理
rescue Errot::EXX2 => オブジェクトの変数名	#	Errno::EXX2 例外発生時の処理
  例外が起こった場合の処理
ensure
  例外の有無に関わらず行う後処理
end
 て書いて、例外発生時の処理が同じであった場合も、だらだらと 5、6 行目と同じものを追加しておりましたが・・・。  例外発生時の処理が同じものは

begin
  処理
rescue Errno::EXX1, Errot::EXX2 => オブジェクトの変数名	#	Errno::EXXX 例外発生時の処理
  例外が起こった場合の処理
ensure
  例外の有無に関わらず行う後処理
end
 と、「,」でつなげて行けば、短く書けるのでした・・・。