2019-08-04
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 の特異クラス |