Cara terbaik saya memahami mixin adalah sebagai kelas virtual. Mixin adalah "kelas virtual" yang telah disuntikkan dalam rantai leluhur kelas atau modul.
Ketika kita menggunakan "include" dan memberikannya sebuah modul, modul itu menambahkan modul ke rantai leluhur tepat sebelum kelas yang kita warisi dari:
class Parent
end
module M
end
class Child < Parent
include M
end
Child.ancestors
=> [Child, M, Parent, Object ...
Setiap objek di Ruby juga memiliki kelas tunggal. Metode yang ditambahkan ke kelas singleton ini dapat langsung dipanggil pada objek dan karenanya mereka bertindak sebagai metode "kelas". Ketika kita menggunakan "extended" pada objek dan meneruskan objek modul, kami menambahkan metode modul ke kelas tunggal objek:
module M
def m
puts 'm'
end
end
class Test
end
Test.extend M
Test.m
Kita dapat mengakses kelas singleton dengan metode singleton_class:
Test.singleton_class.ancestors
=> [#<Class:Test>, M, #<Class:Object>, ...
Ruby menyediakan beberapa kait untuk modul ketika mereka dicampur ke dalam kelas / modul. included
adalah metode kait yang disediakan oleh Ruby yang dipanggil setiap kali Anda memasukkan modul dalam beberapa modul atau kelas. Sama seperti yang disertakan, ada extended
kait terkait untuk memperpanjang. Ini akan dipanggil ketika modul diperluas oleh modul atau kelas lain.
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
Ini menciptakan pola menarik yang dapat digunakan pengembang:
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
Seperti yang Anda lihat, modul tunggal ini menambahkan metode instance, metode "class", dan bertindak langsung pada kelas target (memanggil a_class_method () dalam kasus ini).
ActiveSupport :: Concern merangkum pola ini. Berikut modul yang sama ditulis ulang untuk menggunakan 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