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