Модули группируют имена и позволяют повторно использовать методы без наследования от общего прикладного класса. include добавляет методы экземплярам, prepend помещает модуль перед классом в поиске методов, extend добавляет методы конкретному объекту. Сам модуль является объектом Module, но обычные экземпляры как у класса через MyModule.new не создаёт.
Для чего используются модули в Ruby?
Пространства имён и mixin-модули решают разные задачи. Разбираем include, prepend и extend, а также порядок поиска методов.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Модуль в Ruby используют как пространство имён и как mixin — набор методов для подмешивания в другие объекты.
Пространство имён предотвращает конфликт одноимённых классов:
module MyFramework
class Validator
def valid?(value)
!value.nil?
end
end
end
p MyFramework::Validator.new.valid?('data') # true
Для повторного использования поведения применяют include:
module Loggable
def log(message)
puts "[LOG] #{message}"
end
end
class Processor
include Loggable
def call
log('Processing data')
end
end
Processor.new.call
Методы включённого модуля доступны экземплярам. Метод экземпляра, определённый непосредственно в классе, с тем же именем имеет приоритет над методом, добавленным обычным include.
prepend помещает модуль перед классом. Это удобно для обёрток, которые вызывают исходную реализацию через super:
module GreetingPrefix
def greet
"Module: #{super}"
end
end
class Greeter
prepend GreetingPrefix
def greet
'hello'
end
end
puts Greeter.new.greet # Module: hello
extend Loggable добавит методы конкретному объекту; если этот объект — класс, их можно вызывать как методы класса. Цепочку поиска помогает увидеть ancestors.
Нельзя говорить, что «модули не являются объектами»: модуль — объект класса Module, и Module.new создаёт новый модуль. Но у обычного модуля нет механизма создания экземпляров через MyModule.new, как у класса. Документация Module