Глубоко в 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 создает методы класса. Уже есть отличная публикация для этого наблюдения: