# Rubyのリフレクション解説(eval族のはなし)
_published: 2009/01/14_ 
Rubyのリフレクションについてステキな記事を見つけてしまいました。
- [Ruby reflection | Khelll's Blog](http://www.khelll.com/blog/ruby/ruby-reflection/)
## 前提知識
Rubyでは何でもオブジェクトだと言われます。まずは、この辺について。
最初に思い浮かぶのはこれですね。
```ruby
5.class #=> Fixnum
"hello".class #=> String
```
class自体はどうでしょうか?
```ruby
class Foo;end #=> nil
Foo.class #=> Class
```
ここから2つのことが解ります。 `Foo` は定数であるということ。そして `Class` 型のオブジェクトを参照しているということ。
これはどうでしょう?
```ruby
Foo = Class.new
(irb):8 warning: already initialized constant Foo
=> Foo
```
予想通りエラーになります。定数 `Foo` を再度初期化しようとしたからです。
`Foo` クラスを定義したい時にすべきことは。
1. クラス型のオブジェクトをつくる
2. つくったオブジェクトで定数 `Foo` を初期化する
今後、「オブジェクト」と言った時には、 `Class` 型も含めてあらゆるオブジェクトを指します。
では、次です。「シングルトンクラス (Singleton Class)」について。
簡単に言うと、すべてのシングルトンメソッド (singleton method) を保持するクラスです。
2つのクラスメソッドを定義してみましょう。クラスメソッドは `Class` 型のオブジェクトのシングルトンメソッドにすぎません。
```ruby
class Foo
def self.hi ; p "hi" ;end
def self.bye ; p "bye" ; end
end
Foo.singleton_methods #=> ["hi","bye"]
```
下のように書き換えることもできます。
```ruby
class Foo
class << self
def hi ; p "hi" ; end
def bye ; p "bye" ; end
end
end
Foo.singleton_methods #=> ["hi","bye"]
```
上記の「class << self」と書かれたインナークラスがシングルトンクラスです。
シングルトンクラス自体を返すメソッドを定義してみましょう。
```
class Object
def singleton_class
class << self
self
end
end
end
```
試してみます。
```ruby
Foo.singleton_methods #=> ["bye", "hi"]
Foo.singleton_class.instance_methods(false) #=> ["bye", "hi"]
```
お解りのように、シングルトンクラスは、すべてのシングルトンメソッドを保持したクラスなのです。
それでは、RubyのリフレクションAPIに話を戻しましょう。ここでは、 `eval` 、 `instance_eval` 、 `class_eval` の3つのメソッドを紹介します。
## eval
`eval` は、Rubyの文字列を評価するメソッドです。
```ruby
eval "3+4" #=> 7
eval "def multiply(x,y) ; x*y; end"
multiply(4,7) #=> 28
```
`eval` は `binding` のスコープでも動きます。 `binding` はコードの特定の場所で実行コンテキストをカプセル化するオブジェクトです。このコンテキストを再利用することができます。 `eval` で `binding` を使った例をみてみましょう。
```ruby
class Demo
def initialize(n)
@secret = n
end
def getBinding
return binding()# a method defined in Kernel module
end
end
k1 = Demo.new(99)
#get the value of the instance variable @secrete stored in the binding of object k1
eval("@secret", k1.getBinding) #=> 99
```
`proc` オブジェクトを使うこともできます。
```ruby
def greeting(name)
lambda{|greetings| greetings.collect {|g| "#{g} #{name}"} }
end
greeter = greeting("dude") #=> #<Proc:0xb752b810@(irb):2>
greeter.call ["hi","hello","hola"] #=> ["hi dude", "hello dude", "hola dude"]
eval("name='khelll'",greeter) #=> "khelll"
greeter.call ["hi","hello","hola"] #=> ["hi khelll", "hello khelll", "hola khelll"]
```
## instance_eval
`instance_eval` はオブジェクトのコンテキストで働きます。
```ruby
class Klass
def initialize
@secret = 99
end
end
k = Klass.new
k.instance_eval { @secret } #=> 99 , notice the @
```
シングルトンメソッドを定義するのに使うこともできます。
```ruby
Fixnum.instance_eval "def zero; 0 ;end"
Fixnum.zero #=> 0
```
文字列の代わりに `block` を渡すことができます。
```ruby
Fixnum.instance_eval{ def ten ;10;end }
Fixnum.ten #=> 10
```
## class_eval
レシーバーのコンテキストの文字列やブロックを評価します。
```ruby
Foo.class_eval{@@x=1} #=> 1
Foo.class_eval{@@x} #=> 1
```
インスタンスメソッドを定義します。
```ruby
Fixnum.class_eval "def number ; self ;end"
5.number #=> 5
```
`instance_eval` と同じく、文字列の代わりに `block` を渡すことができます。
```ruby
Fixnum.class_eval{ def number;self;end}
7.number #=> 7
```
`class_eval` を使うと、 private メソッドを動的に呼び出すことができます。例として、 `include` という private メソッドを呼び出してみます。
```ruby
module M; end
String.include M #=> NoMethodError: private method `include' called for String:Class
String.class_eval{include M} #=> you could do it with String.send(:include,M)
```
これまでの知識を使って、自作 `attr_accessor` メソッドをつくってみましょう。 `attr_access` というメソッドをつくります。
```ruby
class Class
def attr_access(*attrs)
attrs.each do |attr|
class_eval %Q{
def #{attr}
@#{attr}
end
def #{attr}=(value)
@#{attr} = value
end
}
end
end
end
class Foo
attr_access :a,:b
end
Foo.instance_methods(false) #=> ["b=", "a=", "b", "a"]
```
同じような方法で、クラスの `attribute` のアクセサを定義することができます。
```ruby
class Class
def cattr_access(*attrs)
attrs.each do |attr|
class_eval %Q{
def self.#{attr}
@@#{attr}
end
def self.#{attr}=(value)
@@#{attr} = value
end
}
end
end
end
```
シングルトンクラスを使うこともできます。
```ruby
class Class
def singleton_class
class << self
self
end
end
def cattr_access(*attrs)
attrs.each do |attr|
singleton_class.class_eval %Q{
def #{attr}
@@#{attr}
end
def #{attr}=(value)
@@#{attr} = value
end
}
end
end
end
```
どちらの場合でもOKです。
```ruby
class Foo ; cattr_access :cx,:cy end
Foo.singleton_methods(false) #=> ["cy", "cy=", "cx", "cx="]
```
オブジェクト変数やクラス変数にアクセスする `attr_reader` や `attr_writer` の定義も試してみてください。