🍒 はじめに
チェリー本輪読会の第14週目のエントリーになります。
輪読会の概要については第1週目にまとめています。
- 第1週目のエントリーはこちら
- 第2週目のエントリーはこちら
- 第3週目のエントリーはこちら
- 第4週目のエントリーはこちら
- 第5週目のエントリーはこちら
- 第6週目のエントリーはこちら
- 第7週目のエントリーはこちら
- 第8週目のエントリーはこちら
- 第9週目のエントリーはこちら
- 第10週目のエントリーはこちら
- 第11週目のエントリーはこちら
- 第12週目のエントリーはこちら
- 第13週目のエントリーはこちら
🍒 輪読会 第14週目まとめ
第9章9.1.1〜第9章9.7まで
期間:2021年08月23日〜2021年08月27日
エラーとは
プログラムの処理中に発生するエラーにはいくつか種類があります。
- データのエラー((広い意味で)データの誤り。構造上の間違いなど)
- システムのエラー(ハードディスクが故障、回線が切断など)
- プログラミングのエラー(メソッド名、引数が存在しない、間違っているなど)
上記のようなさまざま状況で発生するエラーですが、プログラムを正常に戻し処理を続けるには、エラーの原因を取り除く必要があります。その際に役に立つのが「例外」という仕組みです。
Rubyには、エラー処理をサポートするための「例外処理」の仕組みが備わっています。
例外(Exception)とは
wikipediaには以下のように書いています。
プログラミングでは、プログラムがある処理を実行している途中で生じ得る、設計から逸脱した状態を「例外」という。
ここでは、地震、落雷により急にパソコンのハードウエアが壊れてエラーが起きるような、想定が困難な状況ではなく、「メソッド名の定義がおかしい。変数に誤った値が格納されている、タイポしている等」予め発生する可能性があると思われる、想定しているエラーのことを指しています。通常、例外は何らかの理由により処理が中断され、その状況に関する情報が通常とは異なる経路で送出されます。
例外処理とは
エラーが起きたときに行う処理のことを例外処理と呼んでいます。プログラムの実行中にエラーが起こると、プログラムは一時中断し「例外処理」を探しそれを実行します。
仮に、以下のファイルを用意し実行してみました。敢えて、行末のメソッドで呼び出すことができない引数を渡しています。
# fizz_buzz.rb def fizz_buzz(n) if n % 15 == 0 'Fizz Buzz' elsif n % 3 == 0 'Fizz' elsif n % 5 == 0 'Buzz' else n.to_s end end fizz_buzz(foobarbaz)
結果、プログラムが一時中断し「例外処理」が出力されます。
❯ ruby fizz_buzz.rb fizz_buzz.rb:13:in `<main>': undefined local variable or method `foobarbaz' for main:Object (NameError)
例外処理もオブジェクト
上記の例外処理では、NameError
となり、「定義されていないローカル変数またはメソッドなので、エラーですよ〜」と怒られています。この例外処理は、NameErrorクラスのオブジェクトになります。
NameError(未定義のローカル変数や定数を使用したときに発生します。)
class NameError (Ruby 3.0.0 リファレンスマニュアル)
例外クラス(るりま)
例外も例外クラスのインスタンス(オブジェクト)なので、るりまに情報がまとめられています。
library _builtin (Ruby 3.0.0 リファレンスマニュアル)
例外処理が発生した場合、るりまを読んでも具体的な解決策がわかないことが多いです。その際は、適切なキーワードを元に(エラー文など)解決策をググって見つけた方が早いです。(個人的意見)
例外を捕捉して処理を実行する
何らかの理由で例外が発生してもプログラムを続行したい場合は、begein 〜 rescue 〜 end
と、記述することで、プログラムを続行させることができます。
# 構文 begein # 例外が起きうる処理 rescue # 例外が発生した場合の処理 end
実際に試してみました。
puts '演奏開始' module BassGuitar def play(bassist) puts "#{bassist}: ブン!ブン!" end end begin bass_guitar = BassGuitar.new('ジャコ・パストリアス') rescue puts '機材トラブルが発生したが、このまま演奏を続行する' end puts '演奏終了'
この処理を実行してみると...
# 処理結果
演奏開始
機材トラブルが発生したが、このまま演奏を続行する
演奏終了
「演奏開始」を出力し、その後、begin以下で「例外が起きうる処理」を書いていますので、rescue以下で、「機材トラブルが発生したが、このまま演奏を続行する」がputsで出力されました。その後の「演奏終了」まで無事出力されたので、最初から最後までプログラムを実行できたことになります。
例外オブジェクトから情報を取得する
例外オブジェクトから情報を取得することも可能です。
# 構文 begin # 例外が起きうる処理 rescue => 例外オブジェクトを格納する変数 # 例外が発生した場合の処理 end
rescue => e
として、変数に例外オブジェクトを格納することができます。変数e
は、exception(例外)から来ています。
例外オブジェクトへメソッドを使うことで、エラーメッセージmessageメソッド
を返したり、バックトレース情報backtraceメソッド
を返したりすることができます。
module BassGuitar def play(bassist) puts "#{bassist}: Bom!Bom!" end end begin bass_guitar = BassGuitar.new('ジャコ・パストリアス') rescue => e puts "エラークラス: #{e.class}" puts "エラーメッセージ: #{e.message}" puts "バックトレース: #{e.backtrace}" puts "---------------------------------" end
この処理を実行してみると...
# 処理結果 エラークラス: NoMethodError エラーメッセージ: undefined method `new' for BassGuitar:Module バックトレース: ["(irb):27:in `<main>'", "/Users/shiro/.rbenv/versions/3.0.2/lib........(省略) ---------------------------------
変数e
へ格納した例外オブジェクトの情報を出力することができます。
意図的に例外を発生させる
例外は捕捉するだけではなく、コードの中で意図的に発生させることもできます。
その際に使用するのが、raiseメソッド
です。
チェリー本のプログラム例を試してみました。(9.3 「意図的に例外を発生させる」チェリー本341頁)
def currency_of(country) case country when :japan 'yen' when :us 'dollar' when :india 'rupee' else raise end end # 実行結果 currency_of(:italy) (irb):24:in `currency_of': unhandled exception from (irb):27:in `<main>' from /Users/shiro/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/irb-1.3.5/exe/irb:11:in `<top (required)>' from /Users/shiro/.rbenv/versions/3.0.2/bin/irb:23:in `load' from /Users/shiro/.rbenv/versions/3.0.2/bin/irb:23:in `<main>'
???
エラーメッセージにunhandled exception
と出てしまいました。
チェリー本とるりまには、特定の例外クラスに該当しないエラーが起こった場合はRuntimeError
が発生すると書いてあるが、なぜ?
質問してみました
伊藤さんから回答いただきました。
どこかのタイミングで表示が変わったようです。以下のように記述すると、RuntimeError
を出すことができました。
def currency_of(country) case country when :japan 'yen' when :us 'dollar' when :india 'rupee' else raise end end begin currency_of(:italy) rescue => e p e end # 実行結果 RuntimeError
例外処理のベストプラクティス
- 例外処理のセオリー
- 例外が発生したら即座に異常終了させよう
- フレームワークの共通事項に全部丸投げしよう
安易にrescueせずに、フレームワークに備わっている例外処理の仕組みに処理を委ねるのがセオリーです。実際にrescueすべきケースに遭遇した時、今回の件を改めて見直し対応を検討するのが、初心者の内はベストプラクティスだと思いました。
RubyMine入門
フィヨルドブートキャンプ受講生の@ikumatdkrさんが、Zennで出版されたRubyMineの入門書です。
RubyMineを使い始めたばかりの方、基本操作は覚えたんだけどさらなる便利機能を覚えたい方、ぜひとも一度読んでいただきたい内容です。
僕もRubyMineを使い初めて3ヶ月目ごろに読みましたが、知らない内容や知ってはいたが使いこなせていない内容が盛りだくさん、かつ親切丁寧に説明されており、非常に勉強になりました。
RubyMineは、ググっても詳しく丁寧に説明されている情報があまりありません。また公式ページも細かい説明までは載っていなく、RubyMine初心者にとっては、まず最初に読むべきベストな一冊だと思います!!
しかも無料!@ikumatdkrさん、ありがとうございます〜!
参考書籍
- 伊藤淳一 著/『プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで』/技術評論社/2017年https://gihyo.jp/book/2017/978-4-7741-9397-7
- 五十嵐邦明,松岡浩平 著/『ゼロからわかる Ruby 超入門』/技術評論社/2018年https://gihyo.jp/book/2018/978-4-297-10123-7
- 高橋征義、後藤裕蔵 著/『たのしいRuby第6版』/SBクリエイティブ/2019年https://tanoshiiruby.github.io/6/index.html
- プログラミング言語 Ruby リファレンスマニュアル https://docs.ruby-lang.org/ja/
🍒 まとめ
今週は例外処理編でした。
例外処理のベストプラクティスに書いたように、まずはフレームワークに従うのが良いとは思いますが、裏側で起こっている処理の仕組みを知ることができ勉強になりました。
次は、yield、Procについて書きたいと思います。
では、また来週!(次回、第15週目)