Rubyで自作した作成したメソッドでブロックを使う際に利用するのがyieldです。ブロックは複雑な処理をシンプルに記述できる機能ですが、yieldで使用することで自作のメソッドでも使えるようにできます。
今回はRubyのブロックの使い方とブロックを有効にするためのyieldの使い方について紹介します。
Rubyにおけるブロックとは
今回紹介するyieldは、自分で定義したメソッドでブロックを呼び出す仕組みを定義するために使用します。つまりyieldを使うためには、Rubyにおけるブロックの仕組みを知らなければなりません。そこでyieldの使い方を紹介する前に、まずはRubyにおけうブロックの役割と使い方を解説します。
ブロックとはメソッドの引数
Rubyにおけるブロックとは、変数に代わりにメソッドの引数として引き渡す処理のかたまりです。Rubyで扱う変数とは実際にはオブジェクトで、格納されているデータが1つとは限りません。複数のデータを含むオブジェクトを処理するメソッドでは、個々のデータをどう処理するかをブロックに記述できます。
例えば、ブロックを使うメソッドとしてよく使われるのがeachメソッドです。そして、eachメソッドでは、対象とするオブジェクトに含まれる個々のデータを、どう処理するかを記述します。
ブロックパラメーターを使う
メソッドの引数として指定するブロックは、doとendの間、または{}の間に記述します。そして、対象のブロックの要素を、||で囲まれた変数であるブロックパラメーターで受け取り、続いてブロックパラメーターを使った処理を定義すます。
例えば、下記の例を見てください。eachは配列クラスのメソッドで、配列オブジェクトを対象に、その要素を1つずつ処理します。そして、処理内容をブロックに定義しますが、||で囲まれた「x」がブロックパラメーターです。また、続いて「puts x」とブロックパラメーターを使った処理を定義しており、このプログラムは配列の要素全てをputsメソッドで表示します。
ブロックを使ったeachメソッドの例
arr.each do |x| puts x end
ブロック付きのメソッドを定義するには
Rubyでは、新規にクラスを定義し、そのクラスに属する独自のメソッドを作ることが可能です。なおRubyにおけるメソッドとは他のプログラム言語の関数にあたるもので、変数を受け渡す際に引数を指定できます。そして、新規に定義したメソッドの引数で、ブロックを使えるようにする仕組みがyieldです。
そしてyieldは、メソッドの引数として記述されるブロックの||で囲まれるブロックパラメーターを定義します。
yieldの使い方
今回紹介するyieldは、先ほど紹介したように自分で定義したブロック付きメソッドでブロックを呼び出す際に、||で囲まれるブロックパラメーターを定義するメソッドです。次からyieldの使い方について解説します。
ブロックを有効にする
Rubyでは全てのメソッドで引数の最後にブロックを指定できます。しかしそのブロックが評価されるとは限りません。ブロックが評価されるかどうかはメソッドの定義の仕方によります。
例えば、メッセージを表示するputsメソッドに次のようにブロックを指定してみてください。
putsメソッドにブロックを指定した例
puts("Hello Ruby!") do puts "Go next World!" end
putsメソッドはブロックを評価しないので、引数のメッセージのみ表示されます。しかし、ブロックを指定したことでエラーにはなりません。ブロックを評価しないので無視するだけです。
新たに定義したメソッドにブロックを記述したとしても無視されます。今回紹介するyieldは、引数の最後に指定するブロックを有効にするために使います。
ブロックの有無に応じてyieldを適用する
新規に定義したメソッドの中でyieldを実行すると、そのメソッドに指定されたブロックを実行します。しかし、そのままでは引数の最後にブロックが定義されていない場合、エラーとなり動作しません。そのため、ブロックの有無をチェックするblock_givenと組み合わせて使用します。
もしブロックを指定されていたらそれを実行するyieldの書き方
yield if block_given?
ブロックを評価する例
def calc_p2(x) if x > 0 then yield if block_given? return x + 2 end return 0 end p calc_p2(3) # ブロックが無いので、5のみ表示する p calc_p2(5) { puts "block message" } # ブロックを評価してblock messageと表示した後、7を表示する p calc_p2(-1){ puts "block message" } # ブロックを評価せず、0のみ表示する
ブロックパラメータを指定する
yiledはブロック内で利用するブロックパラメーターの値を指定できます。先ほど説明したようにブロックを評価した際、ブロックパラメーターが定義されていればyiledの引数で指定した式や値を適用されます。なお、ブロックパラメーターは複数指定することが可能です。
ブロックパラメーターを指定する方法
yield(式、式 … )
ブロックパラメータを指定した例
def calc_p2(x) if (x > 0) && (x = 10 then yield("over_teen") if block_given? end return x + 2 end p calc_p2(1){ |message| puts message } # ブロックを評価しunder_teenを表示した後、3を表示する p calc_p2(13){ |message| puts message } # ブロックを評価しover_teenを表示した後、15を表示する
ブロックをオブジェクト化して使う
先ほどyieldを活用したブロックの使用例を紹介しましたが、Webシステム開発で使われるRuby on Rilasの理念は「同じことを繰り返さない」と「設定より規約」です。同じブロックを使うのなら、オブジェクト化して共通に使えるようにしましょう。
次からyieldを使う際に同時に使うことの多い、ブロックをオブジェクト化する仕組みについて紹介します。
ブロックをオブジェクト化するには
Rubyのブロックをオブジェクト化するにはProcクラスを利用します。使い方は簡単で、Porc.newに続いてオブジェクト化したいブロックを指定するだけです。
ブロックをオブジェクト化する方法
ブロックのオブジェクト = Proc.new ブロック
ブロックをオブジェクト化する例
proc1 = Proc.new { |message| puts message }
ブロックをオブジェクト化した例
先ほど紹介したブロックパラメータを指定した例を紹介しましたが、それをオブジェクト化したブロックで書き換えた例を次に紹介します。
ブロックをオブジェクト化して書き換えた例
def calc_p2(x) if (x > 0) && (x = 10 then yield("over_teen") if block_given? end return x + 2 end proc1 = Proc.new { |message| puts message } p calc_p2(1){ proc1 } # ブロックを評価しunder_teenを表示した後、3を表示する p calc_p2(13){ proc1 } # ブロックを評価しover_teenを表示した後、15を表示する
先ほどの例では、独自に定義したメソッドcalc_p2()を呼び出す際、それぞれで「|message| puts message」のブロックを指定していました。そのブロックをProcクラスを用いてオブジェクトproc1に定義し、メソッド呼び出しに使用した例です。このようにシンプルに記述できます。
まとめ
これまで新規に作成したメソッドでブロックを利用する際に使うyieldについて解説してきました。Rubyのメソッドでは、引数とは別にブロックを指定できます。さらにProcクラスを利用すれば、オブジェクト化したブロックを利用することも可能です。
Rubyのyiledをうまく利用して、ブロックをプログラミングに活用してください。