La meilleure façon dont je comprends les mixins sont les classes virtuelles. Les mixins sont des "classes virtuelles" qui ont été injectées dans la chaîne d'ancêtres d'une classe ou d'un module.
Lorsque nous utilisons "include" et lui passons un module, cela ajoute le module à la chaîne des ancêtres juste avant la classe dont nous héritons:
class Parent
end
module M
end
class Child < Parent
include M
end
Child.ancestors
=> [Child, M, Parent, Object ...
Chaque objet de Ruby a également une classe singleton. Les méthodes ajoutées à cette classe singleton peuvent être directement appelées sur l'objet et agissent donc comme des méthodes de «classe». Lorsque nous utilisons "extend" sur un objet et passons à l'objet un module, nous ajoutons les méthodes du module à la classe singleton de l'objet:
module M
def m
puts 'm'
end
end
class Test
end
Test.extend M
Test.m
Nous pouvons accéder à la classe singleton avec la méthode singleton_class:
Test.singleton_class.ancestors
=> [#<Class:Test>, M, #<Class:Object>, ...
Ruby fournit des hooks pour les modules lorsqu'ils sont mélangés dans des classes / modules. included
est une méthode hook fournie par Ruby qui est appelée chaque fois que vous incluez un module dans un module ou une classe. Tout comme inclus, il existe un extended
crochet associé pour l'extension. Il sera appelé lorsqu'un module est étendu par un autre module ou classe.
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
Cela crée un modèle intéressant que les développeurs pourraient utiliser:
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
Comme vous pouvez le voir, ce module unique ajoute des méthodes d'instance, des méthodes "class", et agit directement sur la classe cible (appelant a_class_method () dans ce cas).
ActiveSupport :: Concern encapsule ce modèle. Voici le même module réécrit pour utiliser 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