Существует класс Стека в API. Это удовлетворит Ваши потребности?
Возможно, вам будет полезно прочитать определение Ruby для публичного, частного и защищенного. (Перейти к контролю доступа)
Закрытый Ruby аналогичен защищенному Java. Не существует Ruby-эквивалента Java private. РЕДАКТИРОВАТЬ: Это решение теперь предоставляет метод подделки Java-идеала приватности в объектах Ruby.
Частный определяется как методы / переменные, которые могут только вызываться неявно. Вот почему утверждения 2 и 3 терпят неудачу. Другими словами, частные ограничивают методы / переменные контекстом класса или подкласса, в котором они определены. Наследование передает частные методы подклассам, и поэтому к ним можно получить доступ с помощью неявного self. (Объясняя, почему утверждение 6 работает.)
Я думаю, вы ищете что-то более защищенное. Изменив приват в Spy на защищенный, все 6 ваших заявлений работают. Защищенные методы могут быть вызваны любым экземпляром определяющего класса или их подклассов. Явно или неявно вызываемые для self являются допустимыми операторами для защищенных методов, если вызывающий является либо классом объекта, отвечающего на вызов, либо наследуется от него.
class Person
private
attr_reader :weight
end
class Spy < Person
protected
attr_accessor :code
public
def test
code #(1) OK: you can call a private method in self
Spy.new.code #(2) OK: Calling protected method on another instance from same class family or a descendant.
self.code #(3) OK: Calling protected method on with explicit self is allowed with protected
code="xyz" #(4) Ok, it runs, but it actually creates a local variable!!!
self.code="z" #(5) OK! This is the only case where explicit 'self' is ok
weight #(6) OK! You can call a private method defined in a base class
end
end
s = Spy.new
s.test # succeeds
s.code #(7) Error: Calling protected method outside of the class or its descendants.
Что касается оператора 4. Вы правы, предполагая, что это чтобы избежать двусмысленности. Это скорее защита от потенциального вреда динамической природы рубина. Это гарантирует, что вы не сможете переопределить методы доступа, открыв класс позже. Ситуация, которая может возникнуть, например, при оценке испорченного кода.
Я могу только строить предположения о проектных решениях, которые привели к такому поведению. Я чувствую, что по большей части все сводится к динамической природе языка.
PS Если вы действительно хотите дать вещам java-определение private. Доступно только тому классу, в котором он определен, даже не подклассам. Вы можете добавить к своим классам метод self.inherited, чтобы удалить ссылки на методы, доступ к которым вы хотите ограничить.
Сделать атрибут веса недоступным для подклассов:
class Person
private
attr_reader :weight
def initialize
@weight = 5
end
def self.inherited(subclass)
subclass.send :undef_method, :weight
end
end
class Spy < Person
private
attr_accessor :code
public
def test
weight
end
end
Person.new.send(:weight) # => 5
Spy.new.send(:weight) #=> Unhelpful undefined method error
Возможно, имеет смысл заменить вызов undef_method чем-нибудь вроде этого:
def self.inherited(subclass)
subclass.class_eval %{
def weight
raise "Private method called from subclass. Access Denied"
end
}
end
Что дает гораздо более полезную ошибку и ту же функциональность.
Отправка необходима, чтобы обойти вызов частных методов для других классов. Используется только для доказательства того, что все действительно работает.
Что, оглядываясь назад, делает частные и защищенные бесполезными. Если вы действительно серьезно относитесь к защите своих методов, вам придется переопределить send, чтобы заблокировать их. Следующий код делает это на основе private_methods объекта:
def send_that_blocks_private_methods(method, *args)
if private_methods.include?(method.to_s)
raise "Private method #{method} cannot called be called with send."
else
send_that_allows_private_methods(method, *args)
end
end
alias_method :send_that_allows_private_methods, :send
alias_method :send, :send_that_blocks_private_methods
private :send_that_allows_private_methods
Вы можете указать class_variable для private_methods, к которому вы хотите заблокировать доступ, вместо того, чтобы запрещать доступ ко всем приватным методам. Вы также можете сделать send частной, но есть законное использование вызова send извне объекта.