Ruby における Binding オブジェクトとは

Ruby の eval メソッドなどで引数として指定される Binding オブジェクトについて説明します。

参照:Rubyのevalメソッドの使い方

Binding オブジェクトとは

Binding オブジェクトとは、変数・メソッドなどの環境情報を表すオブジェクトです。言い換えると、変数やメソッドが定義された文脈(スコープ)を表すものです。

例えば、あるメソッド内のローカル変数を外部から eval メソッドなどで参照したい時に、そのメソッドの Binding オブジェクトを指定するなどといった使い方をします。

binding メソッド

binding メソッドは、Binding オブジェクトを生成して返すカーネルメソッドです。Binding オブジェクトは、この binding メソッドからのみ生成されます。

Binding オブジェクトを使ったサンプル

メソッドの Binding オブジェクト

以下のような sample メソッドがあるとします。ローカル変数 a を定義し、 binding メソッドで sample メソッドの Binding オブジェクトを生成し返します。

def sample
  a = 1
  binding ##fooの Binding オブジェクトを生成して返す
end

この時、以下のように eval メソッドで変数 a を表示しようとしても、変数 a はローカル変数なので undefined エラーとなります。

eval("p a")
#=> undefined local variable or method `a'

しかし、eval メソッドの第二引数に、sample メソッドのBinding オブジェクトを指定するとエラーとならず「1」と表示されます。

eval("p a", sample)
#=> 1

クラスの Binding オブジェクト

以下のような Person クラスがあるとします。bind メソッドは、Person クラスの Binding オブジェクトを返すだけのメソッドです。

class Person
  @name
  def initialize(name)
    @name = name
  end
  def bind    # Personの環境情報bindingを返すメソッド
    binding
  end
end

この Person クラスを元にした peter と jason というインスタンスを作成します。

そして、eval メソッドで インスタンス変数 @name を参照し表示するとします。

この時、第二引数に peter.bind を指定した場合は、peter オブジェクトの Binding オブジェクト が適用されるので、「Peter」と表示されます。一方、 jason.bind を指定した場合は、 「Jason」と表示されます。

peter = Person.new("Peter")
jason = Person.new("Jason")

eval("puts @name", peter.bind)
#"Peter"

eval("puts @name", jason.bind)
#"Jason"

また、第二引数を指定しない場合は、以下のようにエラーとなります。

eval("puts @name")
#=>(eval):1: warning: class variable access from toplevel

Binding オブジェクトの使いどころ

Binding オブジェクトは、eval メソッドの第二引数として使われ、メタプログラミングなどに利用されます。

メタプログラミングとは、簡単に言ってしまえば「コードでコードを生成し実行する」することを指すプログラミング技法の一種です。