問題
このようなクラスがあります。
class DioRejectSomething
def self.perform(something)
new(something).perform
end
def initialize(something)
@something = something
end
def perform
puts("おれは#{@something}をやめるぞ!")
puts("おれは#{@something}を超越するッ!")
end
end
DioRejectSomething.perform('人間')
を実行すると、以下の 2 行のセリフが標準出力に表示されます。
おれは人間をやめるぞ!
おれは人間を超越するッ!
これはクラスメソッドを自身のインスタントメソッドに委譲する形で実装しています。
ところで、2 行のセリフの間に任意の処理を挟めるようにしたいです。これは
class DioRejectSomething
def self.perform(something, &block)
new(something).perform(&block)
end
### 略 ###
def perform
puts("おれは#{@something}をやめるぞ!")
yield
puts("おれは#{@something}を超越するッ!")
end
end
あるいは
class DioRejectSomething
def self.perform(something, &block)
new(something).perform(&block)
end
### 略 ###
def perform(&block)
puts("おれは#{@something}をやめるぞ!")
&block.call
puts("おれは#{@something}を超越するッ!")
end
end
と実装することで実現できます。
DioRejectSomething.perform('人間') { puts("ジョジョーーーーッ!!!") }
おれは人間をやめるぞ!
ジョジョーーーーッ!!!
おれは人間を超越するッ!
ブロックを &block
という &
修飾した引数を利用してクラスメソッドからインスタントメソッドにリレーすることで実現しています。
では、前置きが長くなりましたがここで問題です。&
修飾した引数を一切使わずに同じことを実現するにはどうすればいいでしょうか?
解答
class DioRejectSomething
def self.perform(something)
new(something).perform(&Proc.new)
end
def initialize(something)
@something = something
end
def perform
puts("おれは#{@something}をやめるぞ!")
yield
puts("おれは#{@something}を超越するッ!")
end
end
このように Proc.new を利用することで実現できます。Proc.new をリファレンスマニュアルで調べると、
ブロックを指定しなければ、このメソッドを呼び出したメソッドがブロックを伴うときに、それを Proc オブジェクトとして生成して返します。
と説明されています。これを使えばブロックの引数をわざわざ増やさなくてもさきほどの 2 つの実装例と同じことが実現できます。