Ответ 1
Начнем с того, что в Ruby, как вам известно, в методе a
, объявленном в классе Foo
, я могу вызывать защищенные методы в любом экземпляре Foo
.
Как Ruby определяет, есть ли у нас метод, объявленный в классе Foo
? Чтобы понять это, нам придется выкопать внутренности вызова метода. Я буду использовать примеры из версии 2.2 МРТ, но, по-видимому, поведение и реализация одинаковы в других версиях (я бы хотел увидеть результаты тестирования этого на JRuby или Rubinious, хотя).
Ruby делает это в rb_call0
. Как следует из комментария, self
используется для определения того, можем ли мы назвать защищенные методы. self
извлекается в rb_call
из текущей информации кадра потока. Затем в rb_method_call_status
мы проверяем, что это значение self
имеет тот же класс, на котором определен защищенный метод.
self
является тем же самым self
, на котором был вызван метод. Рассмотрим пример:
class Foo
def give_me_a_block!
puts "making a block, self is #{self}"
Proc.new do
puts "self in block0 is #{self}"
end
end
end
proc = Foo.new.give_me_a_block!
proc.call
Запустив это, мы видим, что один и тот же экземпляр Foo
одинаковый на всех уровнях, хотя мы назвали proc из совершенно другого объекта.
Итак, теперь мы понимаем, почему можно вызвать защищенный метод в другом экземпляре того же класса изнутри блока в методе.
Теперь посмотрим, почему proc, созданный с помощью &:bar
, не может этого сделать. Когда мы помещаем знак &
перед аргументом метода, мы делаем две вещи: проинструктируем ruby передать этот аргумент как блок и поручить ему называть to_proc
на нем.
Это означает вызов метода Symbol#to_proc
. Этот метод реализован в C, но когда мы вызываем метод C, указатель на self
на текущий кадр становится приемником этого метода C - в этом случае он становится символом :bar
. Итак, мы смотрим на экземпляр Foo
, который мы получили, как будто мы находимся в методе класса Symbol, и мы не можем вызывать защищенный метод.
Это глоток, но, надеюсь, он имеет достаточный смысл. Дайте мне знать, если у вас есть какие-либо предложения относительно того, как я могу улучшить его!