Rubyのinstance_evalメソッドとclass_evalとの比較
instance_eval メソッド
このBasicObject#instance_evalはJSのbindメソッドと少し似ていますが、bindはこれをオブジェクトに渡すのに対し、instance_evalは指定したオブジェクトにコードブロック(Context Probe)を、一つはオブジェクトに、一つは実行ファイルに渡しています。こうすることで、instance_evalのコードブロックの中で、呼び出し元のオブジェクトの変数にアクセスすることが可能になります。
サンプルコード
class MyClass
def initialize
@v = 1
end
end
obj = MyClass.new
obj.instance_eval do
self #=> #<MyClass:0x33333 @v=1>
@v #=> 1
end
v = 2
obj.instance_eval { @v = v }
obj.instance_eval { @v } # => 2
さらに、instance_eval メソッドには instance_exec メソッドという双子の兄弟がいます。後者は前者よりも柔軟性があり、コードのブロックにパラメータを渡すことができます。
サンプルコード
class C
def initialize
@x = 1
end
end
class D
def twisted_method
@y = 2
#C.new.instance_eval { "@x: #{@x}, @y>: #{y}" }
C.new.instance_exec(@y) { |y| "@x: #{@x}, @y: #{y}" }
end
end
# D.new.twisted_method # => "@x: 1, @y: "
D.new.twisted_method # => "@x: 1, @y: 2"
instance_evalの呼び出しによって呼び出し元が現在の自己になったため、クラスCではスコープが入れ替わり、以前のスコープが効かなくなります。この時点で、まだ前の変数@yにアクセスしたい場合は、引数に@yを詰めてinstance_evalと一緒にエスケープする必要がありますが、instance_evalは引数を持てないため、兄弟メソッドのinstance_execを使用するのです。
instance_evalとclass_evalの違いについて
###インスタンスエヴァル
名前から得られる最初の情報は、instance_evalの呼び出し側であるreceiverがインスタンスでなければならないこと、instance_evalブロック内ではselfがreceiverのインスタンス自身であることです。
obj_instance.instance_eval do
self # => obj_instance
# current class => obj_instance's singleton class
end
<! --more-->
この定義によれば、あるインスタンスに対して instance_eval が呼ばれた場合、そのインスタンスに対する単相関数 singleton_method をその中で定義することができる。
class A
end
a = A.new
a.instance_eval do
self # => a
# current class => a's singleton class
def method1
puts 'this is a singleton method of instance a'
end
end
a.method1
#=> this is a singleton method of instance a
b = A.new
b.method1
#=> NoMethodError: undefined method `method1' for #<A:0x10043ff70>
同様に、Classクラス自体もClassクラスのインスタンスなので、instance_evalもクラスに対して使うことができ、今度はその中にクラスのsingleton_methodを定義する、つまりクラスのクラス関数として定義することができるのです。
つまり、instance_evalを使ってクラス関数クラスメソッドを定義することができるのですが、これはもっと分かりにくいので、解明する必要があります。
class A
end
A.instance_eval do
self # => A
# current class => A's singleton class
def method1
puts 'this is a singleton method of class A'
end
end
A.method1
#=> this is a singleton method of class A
class_eval
###クラス評価
改めてclass_evalを見てみると、名前から得られる最初の情報は、class_evalの呼び出し側であるreceiverはクラスでなければならないということ、そしてclass_evalブロックの内部ではselfはreceiverクラス自身であることです。
class A
end
A.class_eval do
self # => A
# current class => A
end
この定義によれば、あるクラスに対して class_eval が呼ばれた場合、そのクラスのインスタンス関数 instance_method を定義することができます。
class A
end
a = A.new
a.method1
#=> NoMethodError: undefined method `method1' for #<A:0x10043ff70>
A.class_eval do
self # => A
# current class => A
def method1
puts 'this is a instance method of class A'
end
end
a.method1
#=> this is a instance method of class A
つまり、class_evalを使ってインスタンスメソッドを定義することができるのですが、これもより分かりにくいので、把握する必要があります。
関連
-
Ruby on rails install to remove DL is deprecated, please use Fiddle warning message method [test available].
-
Ruby on Rails ラックミドルウェア基礎学習チュートリアル
-
Luhnアルゴリズムの学習とそのRuby実装コード例
-
Ruby Hash ハッシュ型 基本操作のメソッド一覧 まとめ
-
RubyアプリケーションでHTTPベースのリクエストを送信する簡単な例
-
CentOS7でruby on railsの開発環境を構築する。
-
Rubyにおける数値型と定数の例
-
Rubyにおけるrequireの使用例
-
Rubyの変数参照に関するいくつかの注意点
-
Rubyプログラミングにおけるアサインメント関連操作
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Ruby正規表現とサンプルコード
-
Ruby on Rails:rakeとデータベースのデータ移行作業
-
Ruby on Railsフレームワークの設計構造をMVCマインドで理解する
-
Rubyブロックチュートリアル
-
Jekyll静的ウェブサイトのバックエンドエンジンのチュートリアル
-
Rubyのデザインパターン開発におけるProxyパターンの利用について
-
デザインパターンにおけるDecoratorパターンを用いたRubyの例
-
RubyGnome2 ライブラリを用いた GTK 環境での Ruby GUI プログラミングの基本的な考え方
-
RubyプログラムにおけるXMLファイルの作成と解析のための方法
-
Rubyのメソッドを検索して実行する