Подтвердить что ты не робот

Ruby def и instance_eval vs. class_eval

Я читаю раздел "Метапрограммирование" в "Программирование Ruby 1.9", и мне трудно понять, что происходит внутри между class_eval/class_exec и instance_eval/instance_exec.

Итак, в первую очередь, я понимаю, что def добавляет метод в таблицу методов self (объект класса):

class A
  puts self  # => A
  def foo; 42; end  # added to the method table of self, so becomes an instance method
end
A.new.foo  # => 42

И если мы используем class_eval, мы получим то же поведение:

A.class_eval do
  puts self  # => A
  def bar; 42; end  # same as above
end
A.new.bar  # => 42

Но как-то в случае instance_eval все по-другому:

A.instance_eval do
  puts self  # => A
  def baz; 42; end  # added to the method table of an anonymous
                    # singleton class of self, so becomes a class method
end
puts A.baz  # => 42

s = 'string'
s.instance_eval do ... end  # same behavior, so now def creates an instance method

Итак, я понимаю функциональную разницу между class_eval и instance_eval.

Но контексты внутри блоков class_eval и instance_eval выглядят одинаково для меня - в частности, self указывает на один и тот же объект, а local_variables - то же самое. Итак, что происходит внутри блоков (внутренне), что делает def действовать иначе?

Есть ли какая-то документация, которую я мог бы прочитать? RDoc для instance_eval и class_eval не помогает. Глядя на источник, instance_eval, кажется, настроил объект одноэлементного класса, тогда как class_eval нет - но разве это отличие видимо вне кода C, на уровне Ruby?

4b9b3361

Ответ 1

Я думаю, что ваша путаница исходит из того факта, что def не зависит от текущего "я", вы можете подумать об этом как о "текущем классе", который имеет свои собственные правила.

Следуя вашим примерам:

class A
  # defs here go to A
  puts self  # => A
  class << self
     #defs here go to A eigenclass
  end
end

A.class_eval do
  #defs here go to A
end

A.instance_eval do
  #defs here go to A eigenclass     
end

s = "Hello World"

class << s
  #defs here go to s eigenclass
end

Вот часть главы, в которой говорится о проблеме, и это довольно ясно о поведении

class_eval и instance_eval оба установлены self для продолжительности блока. Однако они отличаются тем, как они настроить среду для метода определение. class_eval устанавливает вещи вверх как будто вы были в теле класса, поэтому определения методов будут определить методы экземпляра. Напротив, вызов instance_eval в действиях класса как будто вы работали внутри одиночный класс. Следовательно, любые методы, которые вы определяете, станут класса.

Единственное, что, я думаю, стоит добавить, это то, что вы можете вызвать instance_eval в любом объекте, а не только в классах, и поведение не меняется, но имеет разные последствия.

Некоторое релевантное чтение:

Определения Ruby: instance_eval и class_eval

Глава 4 этой самой превосходной серии

Ответ 2

Просто добавьте в ответ @krusty.ar: def и define_method добавьте методы в контекст определения текущего метода (я считаю, что он вызвал, я не уверен), а не с текущим self.

Это просто то, что внутри тела модуля, класса или Singleton эти два экземпляра совпадают.

Но, например, в теле script (aka top-level), self является объектом main, но контекст определения текущего метода Object.