BlankSlate

いや、そういう声もあるというだけです

手続きオブジェクトをクラスインスタンス内で評価する

「もう悩み無用 あなたの髪きっと生えてくる」コーナー宛 RN:セブンが怪人にやられてるときに地球はひなまつり

こんにちは、rebuild.fm毎回楽しく聴いています! さっそくですが、僕は最近困っていることがあります。

例えば以下のようなクラスと、引数を1つとる手続きオブジェクトがあるとします:

class C
  def initialize
    @instance_variable = 'This is instance_variable!'
  end

  def instance_method
    'Called!'
  end
end

proc_obj = Proc.new do |arg|
  puts <<~"EOS"
    proc_argument:     #{arg}
    self:              #{self}
    instance_variable: #{@instance_variable}
    instance_method:   #{instance_method rescue nil}
  EOS
end

このproc_objCクラスインスタンスklassのコンテキストで評価しようとBasicObject#instance_evalを試したのですが、手続きオブジェクトは定義されたコンテキストを保持するためmainクラスインスタンス(Rubyスクリプトのトップレベル)で評価されてしまいます。

klass = C.new

klass.instance_eval do
  proc_obj.call('This is proc_obj argument.')
end
#=> proc_argument:     This is proc_obj argument.
#   self:              main
#   instance_variable: 
#   instance_method:

どうしたらいいでしょうか?そうです、BasicObject#instance_execを使います。

BasicObject#instance_execはブロックに引数を渡しながら、レシーバのコンテキストでブロックを評価できます。今回の場合、ブロックではなく手続きオブジェクトなのでproc_obj&修飾子を付けてBasicObject#instance_execに渡します。

klass.instance_exec('This is proc_obj argument.', &proc_obj)
#=> proc_argument:     This is proc_obj argument.
#   self:              #<C:0x0000000220a880>
#   instance_variable: This is instance_variable!
#   instance_method:   Called!

やりましたね!


このお悩み相談は おさむん家 Advent Calendar 2014 のメールです

History