Ruby защищен видимость вызова из суперкласса

У меня есть этот маленький код, который в некотором роде противоречит документации Ruby:

Вторая видимость protected, При вызове защищенного метода отправитель должен быть подклассом получателя, или получатель должен быть подклассом отправителя. В противном случае NoMethodError будет поднят.

class Test
  def publico(otro)
    otro.prot
  end  
end

class Hija < Test
  protected def prot; end
end

Test.new.publico(Hija.new)

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

NoMethodError: защищенный метод `prot'вызван для # publico

Что мне не хватает? Видимо, опция "получатель должен быть подклассом отправителя" недоступна.

2 ответа

Решение

Хотя он не работает с родительским классом, который ничего не знает о защищенном методе, он работает с подклассами подкласса, которые определяют защищенный метод. Например.

class A
  def n(other)
    other.m
  end
end

class B < A
  def m
    1
  end

  protected :m

end

class C < B
end

class D < C
end

a = A.new
b = B.new
c = C.new
d = C.new

c.n b #=> 1 -- sender C is a subclass of B
b.n b #=> 1 -- m called on defining class
a.n b # raises NoMethodError although reciever B is  a subclass of sender A
b.n c #=> 1 -- reciever C is subclass of sender B
c.n d #=> 1 -- reciever D is sublcass of sender C

Вероятно, мы можем заключить, что поведение выглядит примерно так: "отправитель или получатель должны унаследовать метод". Этим объяснением можно объяснить, что, поскольку ни A (который не знает о существовании m), ни B (который знает о существовании, но не унаследовал его) не унаследовали метод, возникает ошибка.

Хотя есть также вероятность того, что это может быть ошибкой.

Защищенные методы могут вызываться только из экземпляров того же класса или подкласса. Hija является подклассом Test. Тест не является подклассом Hija. Таким образом, защищенный метод в Hija не доступен для экземпляров Test.

Так что, если бы ваш пример был другим способом:

class Hija
  protected def prot; end
end
class Test < Hija
  def publico(otro)
    otro.prot
  end
end
Test.new.publico(Hija.new)

работает отлично.

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