2017-03-28 1 views
1

Je sais que nous pouvons définir le rappel included pour un module individuel.Rappel Ruby lorsqu'un module est inclus

Existe-t-il un moyen de définir un rappel qui est invoqué chaque fois qu'un module est inclus dans un autre module ou une autre classe? Le rappel aurait alors de préférence accès à la fois au module inclus et à la classe/module où il est inclus.

+0

callback 'inclus' est ce que vous voulez, je ne comprends pas quelle est votre confusion – Tsao

+0

@Tsao, ce n'est pas si coupé-et-séché. Si la classe 'C' inclut le module' M' et 'M' utilise' included' pour inclure 'M' dans une autre classe' D' ('D.include (M)'), le rappel de 'M'' inclus' fera que 'M' sera inclus dans' D' une seconde fois, puis une troisième fois, et ainsi de suite. –

Répondre

3

Je ne peux pas penser ou trouver un moyen intégré dans Ruby pour le faire.

Une alternative serait de modifier directement la classe Module pour créer le rappel. Pour ce faire, nous pouvons ajouter des méthodes wrapper autour des méthodes originales include et extend pour forcer l'exécution de nos callbacks définis chaque fois que les méthodes include ou extend sont appelées.

Quelque chose le long des lignes devrait fonctionner:

class Module 

    def self.before 
    m_include = instance_method(:include) 
    m_extend = instance_method(:extend) 

    define_method(:include) do |*args, &block| 
     included_callback(args[0]) 
     m_include.bind(self).call(*args, &block) 
    end 

    define_method(:extend) do |*args, &block| 
     extend_callback(args[0]) 
     m_extend.bind(self).call(*args, &block) 
    end 
    end 

    def included_callback(mod_name) 
    puts "#{self} now has included Module #{mod_name}" 
    end 

    def extend_callback(mod_name) 
    puts "#{self} now has extended Module #{mod_name}" 
    end 

    before 
end 

Un exemple pour vérifier que cela fonctionne:

module Awesome 

    def bar 
    puts "bar" 
    end 

    def self.baz 
    puts "baz" 
    end 
end 

class TestIncludeAwesome 
    include Awesome 
end 

class TestExtendAwesome 
    extend Awesome 
end 

Le code exemple doit imprimer en sortie les éléments suivants:

> TestIncludeAwesome now has included Module Awesome 
> TestExtendAwesome now has extended Module Awesome 
+0

Merci! Cela ressemble à ce que je veux. – user3712482

+0

Pas de soucis ..:) !!! Si ma solution résout votre problème, pourriez-vous le marquer comme accepté? – Aegis

0
class D 
    def self.callback(mod) 
    include mod 
    end 
end 

module M 
    def hello 
    puts 'hi' 
    end 

    def self.included(klass) 
    D.callback(self) unless klass == D 
    end 
end 

class C 
    include M 
end 

C.new.hello #=> 'hi' 
D.new.hello #=> 'hi' 

Whe n C comprend M, M::included est exécuté avec klass#=>C. Puisque klass == D est false, D.callback(M) est exécuté. callback inclut M dans la classe D, puis M::included est exécuté avec klass#=>D. Puisque klass == D est maintenant vrai, M n'est pas inclus dans D une deuxième fois.