k-tokitoh

2019-08-04

x_evalしたときのコンテクスト

.

コンテクスト

「コンテキストとはおおざっぱに言えばローカル変数の状態、self, klass から成る。」*1

ローカル変数の状態は措いておき、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 の特異クラス

*1:https://blog.yugui.jp/entry/547

*2:https://blog.yugui.jp/entry/558