Глубоко в Ruby class_eval и instance_eval

class_eval а также instance_eval вполне предсказуемы в таких случаях, как определение методов. Я также понимаю разницу между экземпляром класса и синглтоном класса (он же собственный класс).

НО

Я не могу понять единственную вещь, такую ​​как следующее: допустим, для некоторых странных целей мы хотим, чтобы существующий класс был одноэлементным.

class A; end
class B; end

A.class_eval do
  private :new
end

B.instance_eval do
  private :new
end

в обоих случаях получил

NameError: undefined method 'new' for class
Did you mean?  new

да, я имею в виду именно этот метод.

Более того, эти два варианта дают одинаковый результат, как self указывает на объект класса в обоих случаях

A.class_eval do
  class << self
    private :new
  end
end

A.new
=> NoMethodError: private method 'new' called for A:Class

B.instance_eval do
  class << self
    private :new
  end
end

B.new
=> NoMethodError: private method 'new' called for B:Class

Как так? Кто-нибудь может пролить свет на это?

1 ответ

Давайте взглянем на то, что я здесь:

class A
  puts self.inspect

  class << self
    puts self.inspect
  end
end

A.class_eval {
  puts self.inspect

  class << self
    puts self.inspect
  end
}

A.instance_eval{
  puts self.inspect

  class << self
    puts self.inspect
  end
}

Мы получаем следующий вывод:

A
#<Class:A>
A
#<Class:A>
A
#<Class:A>

Метод class_eval определен для модулей (и, следовательно, классов) и оценивается в контексте модуля (класса). Метод instance_eval оценивается в контексте BasicObject. Кажется, что в этих случаях два (фактически три) - это одно и то же.

Однако я точно знаю, что если методы создаются внутри блока eval, class_eval создает методы экземпляра, а instance_eval создает методы класса. Уже есть отличная публикация для этого наблюдения:

Другие вопросы по тегам