Модули
Модули в 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–2020 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.