Ответ 1
Вам может показаться полезным прочитать рубиновое определение общедоступное, личное и защищенное. (Перейти к контролю доступа)
Ruby private аналогичен защищенной Java. Нет эквивалента Ruby для Java. EDIT:. Это решение теперь предоставляет метод фальсификации Java-идеала частного в Ruby-объектах.
Частный определяется как методы/переменные, которые можно называть неявно. Вот почему утверждения 2 и 3 терпят неудачу. Другими словами, частные лимиты используют методы/переменные для контекста класса или подкласса, в котором они определены. Наследование передает частные методы подклассам и поэтому может быть доступно с неявным я. (Объясняет, почему работает инструкция 6.)
Я думаю, что вы ищете что-то более близкое к защищенному. Который ведет себя аналогично Java-аксессуарам, которым не предоставляется видимость (например, public, private, protected) Изменив личное в 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. Вы правы, считая это, чтобы избежать двусмысленности. Это скорее защищает потенциальный вред рубинового динамического характера. Это гарантирует, что вы не сможете переопределить аксессуры, снова открыв класс позже. Ситуация, которая может возникнуть, например, путем eval'ing испорченного кода.
Я могу только догадываться о его дизайнерских решениях, которые привели к этим поведением. По большей части я чувствую, что это сводится к динамичному характеру языка.
P.S. Если вы действительно хотите дать вещи, определение java частного. Доступно только классу, в котором он определен, даже не подклассам. Вы можете добавить метод 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
Это обеспечивает гораздо более эффективную ошибку и ту же функциональность.
Отправка необходима для вызова частных методов для других классов. Используется только для доказательства того, что на самом деле все работает.
Который в ретроспективе делает частные и защищенные бесполезными. Если вы действительно серьезно относитесь к защите своих методов, вам придется переопределить отправку, чтобы заблокировать их. Следующий код делает это на основе 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 private, но есть законное использование вызова send извне объекта.