x_evalしたときのコンテクスト
コンテクスト
「コンテキストとはおおざっぱに言えばローカル変数の状態、self, klassから成る。」*1
- 「ローカル変数というのは、参照できる限り外側のスコープも含めた全部だ。」
- 「selfというのはデフォルトでメソッドを受け取る相手である。」
- 「klassとは『今メソッドを定義したらどこに定義されるか』というクラスである。」*2
ローカル変数の状態は措いておき、selfとklassについて確認していく。
サンプルコードでは以下を前提とする。
class Sample; end sample = Sample.new
シンプルなクラス定義での話
Sampleのクラス定義内
class Sample p self # => Sample def m1; end end Sample.new.method(:m1).owner # => Sample
Sampleのクラス定義内ではselfもklassもSampleである。
Sampleの特異クラス定義内
class << Sample p self # => #<Class:Sample> def m2; end end Sample.method(:m2).owner # => #<Class:Sample>
Sampleの特異クラス定義内ではselfもklassもSampleの特異クラスである。
sampleの特異クラス定義内
class << sample p self # => #<Class:#<Sample:0x007fc71aa74f98>> def m3; end end sample.method(:m3).owner # => #<Class:#<Sample:0x007fc71aa74f98>>
sampleの特異クラス定義内ではselfもklassもsampleの特異クラスである。
x_evalをつかったときの話
class_eval
Sample.class_eval do p self # => Sample def m4; end end sample.method(:m4).owner # => Sample
selfもklassも、レシーバ(Sample)となる。
これはSampleのクラス定義内のコンテクストと同一である。
instance_eval
Sample.instance_eval do p self # => Sample def m5; end end Sample.method(:m5).owner # => #<Class:Sample>
sample.instance_eval do p self # => #<Sample:0x007fc71aa74f98> def m6; end end sample.method(:m6).owner # => #<Class:#<Sample:0x007fc71aa74f98>>
selfはレシーバとなり、klassはレシーバの特異クラスとなる。
これはSample/sampleの特異クラス定義内のコンテクストとは下表のとおり異なる。
x.instance_eval | xの特異クラス定義内 | ||
---|---|---|---|
self | x自体 | ≠ | xの特異クラス |
klass | xの特異クラス | = | xの特異クラス |