Модули
Модули в 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 C end class D < C end # OK class D < C end # OK class D end # TypeError: superclass mismatch for class D class D < String end
Наследование
Любой метод, определённый в классе, вызываем из его подкласса:
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–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.