Модули
Модули в Ruby служат двум целям: именованным пространствам и функциональности миксинов.
Именованное пространство может использоваться для организации кода по пакетам или функциональности, которая отделяет общие имена от конфликтов с другими пакетами. Например, именованное пространство IRB предоставляет функциональность для irb, предотвращая коллизию для общего имени «Context».
Функциональность миксинов позволяет совместно использовать общие методы между несколькими классами или модулями. Ruby поставляется с модулем миксинов Enumerable, который предоставляет множество методов перечисления, основанных на методе each и Comparable, позволяющем сравнивать объекты на основе метода сравнения <=>.
Обратите внимание, что между модулями и классами много общего. Помимо возможности миксирования модуля, описание модулей ниже также применимо к классам.
Module Определение
Модуль создаётся с помощью ключевого слова module:
module MyModule # ... end
Модуль может быть повторно открыт любое количество раз для добавления, изменения или удаления функциональности:
module MyModule def my_method end end module MyModule alias my_alias my_method end module MyModule remove_method :my_method end
Повторное открытие классов — очень мощная функция Ruby, но лучше всего повторно открывать только классы, которые вы сами создали. Повторное открытие классов, которые вам не принадлежат, может привести к конфликтам имён или трудно диагностируемым ошибкам.
Вложенность
Модули могут быть вложенными:
module Outer module Inner end end
Многие пакеты создают один внешний модуль (или класс) для предоставления именованного пространства для своей функциональности.
Вы также можете определить внутренние модули с помощью :: при условии, что внешние модули (или классы) уже определены:
module Outer::Inner::GrandChild end
Обратите внимание, что это вызовет исключение NameError, если Outer и Outer::Inner ещё не определены.
Этот стиль позволяет автору сократить количество отступов. Вместо 3-х уровней отступа нужен только один. Однако область поиска констант отличается при создании именованного пространства с помощью этого синтаксиса по сравнению с более подробным синтаксисом.
Область видимости
self
self относится к объекту, определяющему текущую область видимости. self изменится при переходе к другому методу или при определении нового модуля.
Константы
Доступные константы отличаются в зависимости от вложенности модулей (какой синтаксис использовался для определения модуля). В следующем примере константа A::Z доступна из B, так как A является частью вложенности:
module A
Z = 1
module B
p Module.nesting #=> [A::B, A]
p Z #=> 1
end
end
Однако, если вы используете :: для определения A::B без вложенности внутри A, будет поднято исключение NameError, потому что вложенность не включает A:
module A Z = 1 end module A::B p Module.nesting #=> [A::B] p Z #=> raises NameError end
Если константа определена на верхнем уровне, вы можете использовать префикс :: для её ссылки:
Z = 0
module A
Z = 1
module B
p ::Z #=> 0
end
end
Методы
Для документации определения методов см. документацию синтаксиса для методов.
Class методы могут вызываться напрямую. (Это немного запутанно, но метод в модуле часто называют «методом класса», а не «методом модуля». См. также Module#module_function, который может преобразовать метод экземпляра в метод класса.)
Когда метод класса ссылается на константу, он использует те же правила, что и при обращении к ней вне метода, поскольку область видимости одинакова.
Методы экземпляров, определённые в модуле, могут вызываться только при включении. Эти методы имеют доступ к константам, определённым при включении через список предков:
module A
Z = 1
def z
Z
end
end
include A
p self.class.ancestors #=> [Object, A, Kernel, BasicObject]
p z #=> 1
Видимость
Ruby имеет три типа видимости. По умолчанию — public. Публичный метод может быть вызван из любого другого объекта.
Вторая видимость — protected. При вызове защищённого метода отправитель должен быть подклассом получателя, или получатель должен быть подклассом отправителя. В противном случае будет возбуждено исключение NoMethodError.
Защищённая видимость чаще всего используется для определения == и других методов сравнения, когда автор не хочет раскрывать состояние объекта любому вызывающему элементу и хочет ограничить доступ только унаследованным классам.
Вот пример:
class A
def n(other)
other.m
end
end
class B < A
def m
1
end
protected :m
end
class C < B
end
a = A.new
b = B.new
c = C.new
c.n b #=> 1 -- C is a subclass of B
b.n b #=> 1 -- m called on defining class
a.n b # raises NoMethodError A is not a subclass of B
Третья видимость — private. Приватный метод может быть вызван только из внутри класса-владельца без получателя или с литералом self в качестве получателя. Если приватный метод вызывается с получателем, отличным от литерала self, будет возбуждено исключение NoMethodError.
class A
def without
m
end
def with_self
self.m
end
def with_other
A.new.m
end
def with_renamed
copy = self
copy.m
end
def m
1
end
private :m
end
a = A.new
a.without #=> 1
a.with_self #=> 1
a.with_other # NoMethodError (private method `m' called for #<A:0x0000559c287f27d0>)
a.with_renamed # NoMethodError (private method `m' called for #<A:0x0000559c285f8330>)
alias и undef
Вы также можете изменять или удалять методы, но эти операции не ограничены модулями или классами. См. раздел синтаксиса дополнительных возможностей для получения документации.
Классы
Каждый класс также является модулем, но в отличие от модулей, класс не может быть миксирован в другой модуль (или класс). Как и модуль, класс может использоваться как именованное пространство. Класс также наследует методы и константы от своего родительского класса.
Определение класса
Используйте ключевое слово class для создания класса:
class MyClass # ... end
Если вы не укажете родительский класс, ваш новый класс унаследует от Object. Вы можете унаследовать от другого класса, используя < за которым следует имя класса:
class MySubclass < MyClass # ... end
Существует специальный класс BasicObject, который разработан как пустой класс и включает в себя минимум встроенных методов. Вы можете использовать BasicObject для создания независимой структуры наследования. См. документацию BasicObject для получения дополнительной информации.
Наследование
Любой метод, определенный в классе, может вызываться из его подкласса:
class A
Z = 1
def z
Z
end
end
class B < A
end
p B.new.z #=> 1
То же самое верно для констант:
class A
Z = 1
end
class B < A
def z
Z
end
end
p B.new.z #=> 1
Вы можете переопределить функциональность метода родительского класса, переопределив метод:
class A
def m
1
end
end
class B < A
def m
2
end
end
p B.new.m #=> 2
Если вы хотите вызвать функциональность родительского класса из метода, используйте super:
class A
def m
1
end
end
class B < A
def m
2 + super
end
end
p B.new.m #=> 3
Когда используется без аргументов, super использует аргументы, переданные методу подкласса. Для передачи нулевых аргументов методу родительского класса используйте super(). Для передачи определённых аргументов методу родительского класса передайте их вручную, как в super(2).
super может вызываться любое количество раз в методе подкласса.
Singleton Классы
Класс одиночки (также известный как метакласс или собственный класс) объекта — это класс, который содержит методы только для этого экземпляра. Вы можете получить доступ к классу одиночки объекта, используя class << object следующим образом:
class C end class << C # self is the singleton class here end
Чаще всего класс одиночки доступен так:
class C
class << self
# ...
end
end
Это позволяет определять методы и атрибуты в классе (или модуле) без необходимости писать def self.my_method.
Поскольку вы можете открыть класс одиночки любого объекта, это означает, что этот блок кода:
o = Object.new def o.my_method 1 + 1 end
эквивалентен этому блоку кода:
o = Object.new
class << o
def my_method
1 + 1
end
end
У обоих объектов будет метод my_method, который возвращает 2.
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.