Proc(lamda)を定義時ではなく実行時のコンテキスで実行する際にちょっとハマったのでメモ📝
結論: instance_exec(&proc)
で実行すれば良かった。
以下のような外部で定義したprocを受け取って実行した際にhello! by Caller.
と出ることを期待したのですが実行するとNameError
が発生します。
下記の通りProcは定義時のコンテキストで作成されますが、
class Caller def initialize(msg) @msg = msg end attr_reader :msg def callProc(targetProc) puts targetProc.call end end sampleProc = -> { "hello! by #{msg}." } puts Caller.new('Caller').callProc(sampleProc) # => undefined local variable or method `msg' for main:Object (NameError)
これは以下の通りProc
が定義時のコンテキストを保持しており、そのコンテキストで実行されるためmainのmsg
を探索してしまい変数が見つからずエラーになってしまいます。
class Proc ブロックをコンテキスト(ローカル変数のスコープやスタックフレーム)とともにオブジェクト化した手続きオブジェクトです。 class Proc (Ruby 3.2 リファレンスマニュアル)
そのためinstance_exec
で呼び出したインスタンスのコンテキストで実行すれば変数が見つかり期待通りの出力を得ることが出来ました!
class Caller def initialize(msg) @msg = msg end attr_reader :msg def callProc(targetProc) instance_exec(&targetProc) end end sampleProc = -> { "hello! by #{msg}." } puts Caller.new('Caller').callProc(sampleProc) #=> hello! by Caller.
ちなみにinstance_eval(&targetProc)
の場合には、instance_eval
がデフォルトでobj
(実行時のself)をblock
引数として渡してしまうので、lamda
だと引数が合わずにArgumentError
が発生します。