Ruby における Binding オブジェクトとは
Ruby の eval メソッドなどで引数として指定される Binding オブジェクトについて説明します。
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 メソッドの第二引数として使われ、メタプログラミングなどに利用されます。
メタプログラミングとは、簡単に言ってしまえば「コードでコードを生成し実行する」することを指すプログラミング技法の一種です。