puts 'Это что-то совсем другое.'
end
Эта конструкция работает, потому что в классе Module
реализован метод ===
, проверяющий, принадлежит ли параметр тому же классу, что вызывающий объект (или одному из его предков). Поэтому, если an_object
— это строка «cat», выражение string === an_object
окажется истинным и будет выбрана первая ветвь в предложении case
.
Наконец, в Ruby реализован оператор сопоставления с образцом =~
. Традиционно он применяется для сопоставления строки с регулярным выражением. Но если вы найдете ему применение в других классах, то можете переопределить.
У операторов ==
и =~
есть противоположные формы: ! =
и !~
соответственно. Внутри они реализованы путем обращения значения основной формы. Это означает, что если, например, вы реализовали метод ==
, то метод !=
получаете задаром.
11.1.8. Управление доступом к методам
В Ruby объект определяется, прежде всего, своим интерфейсом: теми методами, которые он раскрывает внешнему миру. Но при написании класса часто возникает необходимость во вспомогательных методах, вызывать которые извне класса опасно. Тут-то и приходит на помощь метод private
класса Module
.
Использовать его можно двумя способами. Если в теле класса или модуля вы вызовете private
без параметров, то все последующие методы будут закрытыми в данном классе или модуле. Если же вы передадите ему список имен методов (в виде символов), то эти и только эти методы станут закрытыми. В листинге 11.5 показаны оба варианта.
class Bank
def open_safe
# ...
end
def close_safe
# ...
end
private :open_safe, :close_safe
def make_withdrawal(amount)
if access_allowed
open_safe
get_cash(amount)
close_safe
end
end
# Остальные методы закрытые.
private
def get_cash
# ...
end
def access_allowed
# ...
end
end
Поскольку методы из семейства attr
просто определяют методы, метод private
определяет и видимость атрибутов.
Реализация метода private
может показаться странной, но на самом деле она весьма хитроумна. К закрытым методам нельзя обратиться, указав вызывающий объект; они вызываются только от имени неявно подразумеваемого объекта self
. То есть вызвать закрытый метод из другого объекта не удастся: просто не существует способа указать объект, от имени которого данный метод вызывается. Заодно это означает, что закрытые методы доступны подклассам того класса, в котором определены, но опять же в рамках одного объекта.
Модификатор доступа protected
налагает меньше ограничений. Защищенные методы доступны только экземплярам того класса, в котором определены, и его подклассов. Для защищенного метода разрешается указывать вызывающий объект, так что к ним можно обращаться из других объектов (при условии, что вызывающий и вызываемый объекты принадлежат одному классу). Обычно защищенные методы применяются для определения методов доступа, чтобы два объекта одного типа могли взаимодействовать. В следующем примере объекты класс Person
можно сравнивать по возрасту, но сам возраст недоступен вне класса Person
:
class Person
def initialize(name, age)
@name, @age = name, age
end
def <=>(other)
age <=> other.age
end
attr_reader :name, :age
protected :age
end
p1 = Person.new('fred', 31)
p2 = Person.new('agnes', 43)
compare = (p1 <=> p2) # -1
x = p1.age # Ошибка!
Чтобы завершить картину, модификатор public
делает метод открытым. Неудивительно!..
И последнее: методы, определенные вне любого класса и модуля (то есть на верхнем уровне программы), по умолчанию закрыты. Поскольку они определены в классе Object
, то видимы глобально, но обращаться к ним с указанием вызывающего объекта нельзя.