メソッドにブロックを渡す場合はブロックの内容をyieldで実行することもできましたが、Procというオブジェクトをとして引数を受け取る方法もあります。まずはProcクラスのオブジェクトを作ってみて挙動を確かめてみます。
1 2 3 4 5 6 7 8 9 10 |
foo = Proc.new do |bar| puts bar end str = "proc!!" foo.call(str) num = 1 + 2 foo.call(num) p foo.class |
proc!! 3 Proc
変数「foo」に格納した「Proc」クラスのオブジェクトは「call」メソッドを使って呼び出すことができます。今回はブロック変数として与えられたものをただ単に「puts」するだけにしてみました。「call」の引数として渡した変数「str」と「num」がちゃんとputsされていますね。
メソッド内でProcオブジェクトを使う
それではメソッドを呼び出し、Procオブジェクトを使ってみましょう。
1 2 3 4 5 6 7 8 9 10 11 |
def test_proc(&block) block.call end test_proc do puts "proc!!!" end test_proc do puts 2 * 5 end |
proc!!! 10
ブロックをメソッドに引数として与えるためには「&変数名」という記述でメソッドの最後の引数に付け足す感じで記述を行います。これで「yield」と同様にブロックの内容をメソッドに渡すことができるようになりました。
ちなみにこの「&変数名」として渡された引数は「Proc引数」といいます。
block_given?メソッド
block_given?メソッドはそのメソッドにブロックが渡されているかいないかで真偽値(true,false)を返してくれます。
また同様にメソッドにProcオブジェクトとして機能している変数を記述しても真偽値が返ってきます。ちなみにブロックを渡している場合はProcオブジェクトが返ってきて、なにもブロックを渡していない場合は「nil」が返ってきます。
1 2 3 4 5 6 7 |
def test_proc(&pro) p block_given? p pro end test_proc {} test_proc |
true #<Proc:0x000000009a71d0@C:/Users/proc.rb:6> false nil
上記のProcオブジェクトの挙動(真偽値のようなもの)を利用してブロックを渡したときと渡していないときに違う挙動となるスクリプトを作ってみます。というかyieldの記事のArray_Create.rbと同じ内容のスクリプトをyieldではなくProcオブジェクトを使って表現してみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
def test_proc(strat_num, end_num, &block) ary = Array.new while strat_num <= end_num if block a = block.call(strat_num) ary.push(a) else ary.push(strat_num) end strat_num += 1 end return ary end p test_proc(1, 3) p test_proc(1, 3) { |a| a * 3 } |
[1, 2, 3] [3, 6, 9]
ブロックを渡していない方のメソッドは引数で指定した「1~3」の配列ができましたが、ブロックを渡した場合はブロック内で加工した変数が配列として作成されています。今回の場合は「block.call(strat_num)」でブロック変数「a」に渡した値「1~3」をそれぞれ3倍にして返して、それを配列として作成しています。
Procオブジェクトをインスタンス内で保持
「&変数名」で渡されたProcオブジェクトはインスタンス変数に格納すると他のメソッドでもブロックを呼び出すことができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class MyProc def proc_in(&pro) @pro = pro end def proc_do p @pro puts @pro.call end end pr = MyProc.new pr.proc_in do "yes!!" end pr.proc_do |
#<Proc:0x00000000976aa8@C:/Users/proc.rb:14> yes!!
このように記述することで「proc_in」メソッドを実行しブロックをインスタンス変数「@pro」に格納し、その後「proc_do」メソッドにて渡したブロックを実行することもできるようになります。
&変数名のまま他のメソッドに渡す
メソッド内で「&変数名」で受け取ったブロックは、「&変数名(Procオブジェクト)」といった形で記述すると、そのまま他のメソッドにブロックとして渡すことが可能となります。
1 2 3 4 5 6 7 8 9 |
def proc_each(myary, &block) myary.each(&block) end ary = ["a", "b", "c"] proc_each(ary) do |str| puts str end |
a b c
これでまずproc_eachメソッドを実行し、配列オブジェクトを引数として渡し、ブロックも同時に渡しています。このブロックの処理内容はそのまま「myary.each(&block)」メソッドに渡すことができて配列に入れた文字列「a,b,c」がそれぞれputsされています。
コメントを残す