Rubyの例外とその捕捉――基本のbegin〜rescue〜endからensure、else、retry、後置rescueまで:若手エンジニア/初心者のためのRuby 2.1入門(9)(2/4 ページ)
オープンソースのオブジェクト指向プログラミング言語「Ruby」の文法を一から学ぶための入門連載。最新版の2.1に対応しています。今回は、例外とその補足について、begin、rescue、end、ensure、else、retry、後置rescueなどの基本的な使い方を交えて解説します。
例外クラスを作ってみる
前節で組み込みの例外クラスを紹介しましたが、必要ならば、自分で例外クラスを作成することもできます。exception01.rbに、例外クラスを作成する例を示します。
class UnacceptableRequidError < StandardError attr_reader :obj def initialize(obj) @obj = obj end end class Vessel def pour_out requid = @requid @requid = nil requid end def pour_in(requid) if requid.to_s == acceptance @requid = requid else raise UnacceptableRequidError.new(requid), "unacceptable" end end def acceptance raise NotImplementedError.new, "#acceptance is not implemented!" end end class Teapot < Vessel def initialize(requid) pour_in(requid) end def acceptance "tea" end end class Decanter < Vessel def initialize(requid) pour_in(requid) end def acceptance "wine" end end class Kettle < Vessel def initialize(requid) pour_in(requid) end end
このコードは、容器を表すクラス「Vessel」と、Vesselを継承した「Teapot」(お茶を入れる容器)と「Decanter」(ワインなどを入れる容器)といったクラスを定義し、それを利用する例となっています。クラスについて復習の意味も兼ねて、少し複雑な例にしてみました。
Teapotにはお茶しか入れることはできませんし、Decanterにはワインしか入れることができません(できないと思ってください!)。なので、クラスの利用者が許容できない液体を入れようとした場合は、例外を発生させて利用者に知らせるものとしましょう。
利用例
では、exception01.rbと同じディレクトリでpryを起動して、定義した各クラスを使ってみましょう。
[1] pry(main)> require_relative "exception01" => true [2] pry(main)> teapot = Teapot.new("tea") => #<Teapot:0x007faa8dacc008 @requid="tea"> [3] pry(main)> teapot.pour_out => "tea" [4] pry(main)> teapot.pour_out => nil [5] pry(main)> teapot.pour_in("coffee") UnacceptableRequidError: unacceptable from /Users/flost/work/ruby_rails_tutorial/ruby_21_guide/09/exception01.rb:20:in `pour_in' [6] pry(main)> decanter = Decanter.new("wine") => #<Decanter:0x007faa8d99fce8 @requid="wine"> [7] pry(main)> decanter.pour_in("beer") UnacceptableRequidError: unacceptable from /Users/flost/work/ruby_rails_tutorial/ruby_21_guide/09/exception01.rb:20:in `pour_in'
[1]では、require_relativeを使って、exception01.rbを読み込んでいます。この1行を実行することで、exception01.rbの中で定義されたクラスを使うことができます。
[2]では、Teapotクラスのオブジェクトを作成し、初期値として「tea」を与えています。Teapotは「tea」を許容するので、無事オブジェクトが生成され、[3]でteapotに格納されている「tea」を取り出せます。また、一度取り出されると中身がnilになるので、[4]では返り値がnilとなっています。[5]では「coffee」をteapotに格納しようとしていますが、許容できないのでUnacceptableRequidErrorが発生しています。
[6]から[7]は、Decanterの利用例です。[6]では「wine」を初期値としてDecanterオブジェクトを生成できていますが、「beer」は許容できないので、[7]でUnacceptableRequidErrorが発生しています。
コードの解説
exeption01.rbは1〜7行目で、UnacceptableRequidErrorという例外を定義しています。4行目から6行目のコンストラクタで、UnacceptableRequidErrorのオブジェクト変数に、クラスの利用者が入れようとしたオブジェクトを格納しておきます(格納したオブジェクトの利用例は、次節の例外の捕捉で説明します)。
9〜23行目はVesselクラスの定義です。Vesselクラスは三つのメソッドpour_outとpour_inとacceptanceを持っており、pour_outは格納された液体を外に注ぎ、pour_inは外から液体を注ぐためのメソッドです。また、acceptanceは許容する液体を示す文字列を返すためのメソッドです。
pour_outはインスタンス変数@requidに格納された液体をローカル変数requidにいったん移し、@requidにnilを代入し、一時的に移しておいたrequidの内容を返します。この一連の動作によって、「容器の中身を外に移して空(nil)になった」ということを表しています。
pour_inは引数に与えられたオブジェクトを、acceptanceメソッドの返すオブジェクトと付き合わせて、同じならインスタンス変数@requidに格納し、違えばUnacceptableRequidError例外を発生させます。TeapotやDecanterといった派生クラスでacceptanceをオーバーライドすることによって、派生クラスの実装次第で許容する液体を変えることができます。
ここで、Vesselクラスでのacceptanceの定義に注目してください。25行目でNotImplementedErrorという例外を発生させています。これは、Rubyのクラス設計でよく使われるテクニックです。
もし派生クラスでacceptanceメソッドがオーバーライドされていなければ、基底クラスVesselのacceptanceメソッドが呼ばれます。このとき、NotImplementedError、つまり「メソッドが実装されていませんよ」という例外が発生するので、クラスの利用者にacceptanceメソッドを実装するように促せます。
サンプルコードではKettleクラスがacceptanceメソッドをオーバーライドしていないので、NotImplementedErrorが発生します。
[8] pry(main)> Kettle.new("water") NotImplementedError: #acceptance is not implemented! from /Users/flost/work/ruby_rails_tutorial/ruby_21_guide/09/exception01.rb:25:in `acceptance'
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- 公用語に英語、「再起動」したRubyKaigi 2013が東京で開催
いったん終了していたRubyコミュニティ主催の年次イベントが再開。技術色、国際色を強め、盛況のうちに幕を閉じた - Web業界、今から行くならRubyエンジニアが狙い目?
不況で冷え込んでいたIT業界の転職市場に、回復の兆しが見え始めている。だが、業種や職種によって採用数や条件に大きな差異が生まれている。転職市場の動向を追い、自身のキャリア戦略立案に生かしてほしい。 - Ruby 2.0.0がリリース、大規模化対応の機能などを搭載
生誕20年となる節目を迎えて、プログラミング言語「Ruby」の最新版がリリースされた - 新バージョンで何が変わるのか、Rubyはどこへ向かうのか:まつもと×笹田、Ruby 1.9を語る
- いよいよ始まるRuby 1.9への移行:開発コアメンバが語るRubyの今とこれから(前編)
- Rubyの今後の進化の方向性とは?:開発コアメンバが語るRubyの今とこれから(後編)
- 互換性や脆弱性の問題にどう対応していくのか:Rubyが抱える課題、NaClの前田氏が講演
- Rails Hub情報局:「なんでRubyなんか作った!? 迷惑だ!」に対するMatzの答え
- Rails Hub情報局:Rubyはイノベーション言語として選ばれている
- Rails Hub情報局:Rubyのまつもと氏は、一発屋で終わるのか?
- Rails Hub情報局:Rubyに魔法は要らない
- 数々の“スペル”で高度なプログラミング:Rubyの魔術
- 晴読雨読@エンジニアライフ:『たのしい開発 スタートアップRuby』――なぜRubyistたちはあれほど楽しそうなのか
- 「JRuby 1.7.0」登場、1年半ぶりのメジャーアップデート
JavaVM上のRuby実装「JRuby」の最新版となる「JRuby 1.7.0」が、10月22日にリリースされた。