Я найкраще розумію міксин - це віртуальні класи. Міксини - це "віртуальні класи", які були введені в ланцюжок предків класу або модуля.
Коли ми використовуємо "включати" і передаємо йому модуль, він додає модуль до ланцюга предків прямо перед класом, який ми успадковуємо:
class Parent
end
module M
end
class Child < Parent
include M
end
Child.ancestors
=> [Child, M, Parent, Object ...
Кожен об’єкт у Ruby також має однотонний клас. Методи, додані до цього класу синглтон, можна безпосередньо викликати на об'єкт, і тому вони діють як "клас" методи. Коли ми використовуємо "розширити" на об'єкт і передаємо об'єкт модулю, ми додаємо методи модуля до однотонного класу об'єкта:
module M
def m
puts 'm'
end
end
class Test
end
Test.extend M
Test.m
Ми можемо отримати доступ до класу синглтон методом singleton_class:
Test.singleton_class.ancestors
=> [#<Class:Test>, M, #<Class:Object>, ...
Ruby забезпечує деякі гачки для модулів, коли вони змішуються в класи / модулі. included
це метод гака, що надається Ruby, який викликає кожен раз, коли ви включаєте модуль у якийсь модуль чи клас. Як і в комплекті, є пов'язаний extended
гачок для розширення. Він буде викликаний, коли модуль розширений іншим модулем або класом.
module M
def self.included(target)
puts "included into #{target}"
end
def self.extended(target)
puts "extended into #{target}"
end
end
class MyClass
include M
end
class MyClass2
extend M
end
Це створює цікавий зразок, який розробники могли використовувати:
module M
def self.included(target)
target.send(:include, InstanceMethods)
target.extend ClassMethods
target.class_eval do
a_class_method
end
end
module InstanceMethods
def an_instance_method
end
end
module ClassMethods
def a_class_method
puts "a_class_method called"
end
end
end
class MyClass
include M
# a_class_method called
end
Як бачимо, цей єдиний модуль додає методи екземпляра, "class" методи та діє безпосередньо на цільовий клас (в цьому випадку викликає a_class_method ()).
ActiveSupport :: Концерн інкапсулює цей шаблон. Ось такий же модуль переписаний для використання ActiveSupport :: Concern:
module M
extend ActiveSupport::Concern
included do
a_class_method
end
def an_instance_method
end
module ClassMethods
def a_class_method
puts "a_class_method called"
end
end
end