Модули
Модули в 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. При вызове защищенного метода отправитель должен унаследовать Class или Module, которые определяют метод. В противном случае будет выброшено исключение 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–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.