pockestrap

Programmer's memo

【黒魔術】binding_of_caller gem でメソッド呼び出し元の binding を手に入れる

GitHub - banister/binding_of_caller: Retrieve the binding of a method's caller in MRI 1.9.2+

この gem を使うと、メソッド呼び出し元の binding で eval することができます。

binding とは

class Binding (Ruby 2.0.0)

ローカル変数やオブジェクトを保持するクラスです。

def a
  x = 'Hello'
  b(binding)
end

def b(bi)
  puts bi.eval('x')
end

a     # => Hello

binding を利用すると、このように a メソッドのスコープで任意のコードを実行することが出来ます。

ただし、この方法では binding を b メソッドの引数として渡してやらないと a のスコープを手に入れることが出来ません。当たり前ですね。

ですが、引数に渡すのはめんどくさいと思います。そこで、binding_of_caller gem を使います。

binding_of_caller gem

Install

$ gem install binding_of_caller

もしくは

### file: Gemfile

gem 'binding_of_caller'
$ bundle install

使用例

require 'binding_of_caller'

def a
  x = 'Hello'
  b
end

def b
  puts binding.of_caller(1).eval('x')
end

a       # => Hello

先ほどのコードと違い、b メソッドには何も引数を渡していません。 ですが、b メソッドの中で binding#of_caller を呼び出して、呼び出し元のメソッド(a)での binding を取得しています。

まあ、色々書いたわけですが、言いたいことは全部READMEにかかれているのでそっちを読んだほうがいいと思います。

ちなみに、READMEには

Recommended for use only in debugging situations. Do not use this in production apps.

だなんて書いてあります。