Модули
Модули служат двум целям в 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. Если приватный метод вызывается с получателем, будет поднято исключение NoMethodError.
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.