LoginSignup
7
7

More than 5 years have passed since last update.

Proc.new を使ってブロック引数をリレーする

Posted at

問題

このようなクラスがあります。

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 つの実装例と同じことが実現できます。

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7