ЗмістНатисність на посилання, щоб перейти до потрібного місця
У Ruby модулі використовуються для повторного використання коду. Метод додавання модуля впливає на де і як методи з модуля стають доступними.
include - додає методи як методи екземпляра
- Методи модуля стають доступними для всіх об’єктів класу.
- Використовують, коли хочуть, щоб методи були у екземплярів класу.
module Greetings
def hello
"Hi!"
end
end
class User
include Greetings
end
u = User.new
u.hello # => "Hi!"
Методи модуля з’являються у ланцюжку предків класу (ancestors) після самого класу, тобто можна перевизначати їх у класі. Але давайте розберемо це детальніше. У Ruby кожен клас має ланцюжок предків (ancestors) - порядок, у якому Ruby шукає методи при виклику на об’єкті.
module Greetings
def hello
"Hi from module"
end
end
class User
include Greetings
def hello
"Hi from class"
end
end
p User.ancestors
# => [User, Greetings, Object, Kernel, BasicObject]
Коли ти робиш include Greetings, Ruby вставляє модуль після класу у ланцюжку предків. Або якщо простіше запам'ятати - вище класу.
Це означає, що методи класу перекривають методи модуля, якщо вони мають однакові імена.
u = User.new u.hello # => "Hi from class"
Ruby спочатку шукає метод у самому класі (User). Потім, якщо не знаходить, перевіряє модулі у ланцюжку (Greetings), далі предків (Object, Kernel).
extend - додає методи як методи класу
- Методи модуля стають доступними безпосередньо на класі, а не на екземплярах.
- Зручно для додавання "класових методів" без явного self.method.
module Tools
def info
"Class method!"
end
end
class User
extend Tools
end
User.info # => "Class method!"
User.new.info # => NoMethodError
Фактично Ruby додає методи в singleton class об’єкта (клас сам по собі - об’єкт).
prepend - додає методи перед класом у ланцюжку предків
- Методи модуля з’являються перед класом у ланцюжку предків.
- Це означає, що методи модуля можуть перевизначати методи класу.
module Greetings
def hello
"Hello from module"
end
end
class User
prepend Greetings
def hello
"Hello from class"
end
end
p User.ancestors
# => [Greetings, User, Object, Kernel, BasicObject]
Ключовий момент: Greetings стоїть перед класом User.
Ruby шукає методи у порядку, який показує ancestors.
Тому коли викликаєш u.hello, Ruby спершу бачить метод у модулі Greetings, а вже потім у класі User.
u = User.new u.hello # => "Hello from module"
Використання super у модулі
Якщо у модуля викликати super, Ruby піде далі по ланцюжку предків і виконає метод класу:
module Greetings
def hello
super + " and module"
end
end
class User
prepend Greetings
def hello
"Hello from class"
end
end
u = User.new
u.hello # => "Hello from class and module"
Чому так?
- Ruby викликає hello у модулі Greetings (бо він перший у ancestors).
- Там є super. Ruby шукає наступний метод у ланцюжку предків, тобто в класі User.
- Метод класу повертає "Hello from class", потім додається " and module".
Якщо коротко
include -> методи модуля стають методами екземплярів класу, модуль після класу у ланцюжку предків.
extend -> методи модуля стають методами класу або конкретного об’єкта (singleton class).
prepend -> методи модуля стають методами екземплярів, але перед класом у ланцюжку предків, тобто мають пріоритет над методами класу.
Цей допис поки що не має жодних доповнень від автора/ки.