Ruby 受保护的来自超类的可见性调用

Ruby protected visibility calling from superclass

我的这段小代码似乎在某些方面自相矛盾 Ruby's documentation:

The second visibility is protected. When calling a protected method the sender must be a subclass of the receiver or the receiver must be a subclass of the sender. Otherwise a NoMethodError will be raised.

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

class Hija < Test
  protected def prot; end
end

Test.new.publico(Hija.new)

我得到以下输出:

NoMethodError: protected method `prot' called for # publico

我错过了什么?显然选项“接收者必须是发送者的子类”不可用。

虽然它不适用于对受保护方法一无所知的父Class,但它适用于定义受保护方法的子类的子类。例如

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(知道存在但没有继承它)都没有继承该方法,所以它引发了错误。

尽管这也有可能是一个错误。

受保护的方法只能从相同class 或子class 的实例调用。 Hija 是 Test 的子class。测试不是 Hija 的子class。因此 Hija 中的受保护方法不可用于 Test 实例。

因此,如果您的示例是另一种方式:

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

工作正常。