Ich verstehe Mixins am besten als virtuelle Klassen. Mixins sind "virtuelle Klassen", die in die Ahnenkette einer Klasse oder eines Moduls eingefügt wurden.
Wenn wir "include" verwenden und ihm ein Modul übergeben, wird das Modul der Ahnenkette direkt vor der Klasse hinzugefügt, von der wir erben:
class Parent
end
module M
end
class Child < Parent
include M
end
Child.ancestors
=> [Child, M, Parent, Object ...
Jedes Objekt in Ruby hat auch eine Singleton-Klasse. Zu dieser Singleton-Klasse hinzugefügte Methoden können direkt für das Objekt aufgerufen werden und fungieren daher als "Klassen" -Methoden. Wenn wir für ein Objekt "verlängern" verwenden und dem Objekt ein Modul übergeben, fügen wir die Methoden des Moduls der Singleton-Klasse des Objekts hinzu:
module M
def m
puts 'm'
end
end
class Test
end
Test.extend M
Test.m
Wir können mit der Methode singleton_class auf die Singleton-Klasse zugreifen:
Test.singleton_class.ancestors
=> [#<Class:Test>, M, #<Class:Object>, ...
Ruby bietet einige Hooks für Module, wenn diese in Klassen / Module gemischt werden. included
ist eine von Ruby bereitgestellte Hook-Methode, die aufgerufen wird, wenn Sie ein Modul in ein Modul oder eine Klasse aufnehmen. Genau wie im Lieferumfang enthalten ist ein extended
Haken zum Ausfahren. Es wird aufgerufen, wenn ein Modul um ein anderes Modul oder eine andere Klasse erweitert wird.
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
Dies schafft ein interessantes Muster, das Entwickler verwenden könnten:
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
Wie Sie sehen können, fügt dieses einzelne Modul Instanzmethoden, "Klassen" -Methoden hinzu und wirkt direkt auf die Zielklasse (in diesem Fall Aufruf von a_class_method ()).
ActiveSupport :: Concern kapselt dieses Muster. Hier ist das gleiche Modul, das für die Verwendung von ActiveSupport :: Concern umgeschrieben wurde:
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