2010-10-30 3 views
1

Je voudrais ajouter quelque chose comme une fonction de rappel à un tableau Ruby, de sorte que lorsque des éléments sont ajoutés à ce tableau, cette fonction est appelée. Une chose que je peux penser est de surcharger toutes les méthodes (comme < <, =, insérer, ...) et appeler ce rappel à partir de là.Ajouter une fonction de rappel à un tableau Ruby pour faire quelque chose quand un élément est ajouté

Existe-t-il une solution plus simple?

+1

Juste une note. Je vois que vous avez mis '=' à une liste de méthodes. L'assignation n'est pas un appel de méthode dans Ruby, donc quand vous affectez un autre tableau avec la taille différente à une variable, ce n'est plus le même objet. –

Répondre

5

Le code suivant n'invoque le hook size_changed que lorsque la taille du tableau a changé et que la nouvelle taille du tableau lui a été transmise:

a = [] 

class << a 
    Array.instance_methods(false).each do |meth| 
    old = instance_method(meth) 
    define_method(meth) do |*args, &block| 
     old_size = size 
     old.bind(self).call(*args, &block) 
     size_changed(size) if old_size != size 
    end if meth != :size 
    end 
end 

def a.size_changed(a) 
    puts "size change to: #{a}" 
end 

a.push(:a) #=> size change to 1 
a.push(:b) #=> size change to 2 
a.length 
a.sort! 
a.delete(:a) #=> size change to 1 
+0

En tant qu'ancien développeur Java, je dois admettre que ... J'aime vraiment Ruby ... et votre réponse. Merci! – Zardoz

+0

Magnifique! Cependant, je n'ai jamais vu la syntaxe «class <<» auparavant. Qu'est-ce que cela signifie techniquement? Une recherche rapide sur google n'a rien révélé, mais c'est quelque chose de difficile à chercher ... –

2

Vous devriez probablement créer votre propre classe qui encapsule un tableau. Vous ne voulez pas remplacer une classe de base avec un rappel comme vous le décrivez, non seulement cela rend le code cassant, mais il devient moins expressif pour les futurs développeurs qui ne s'attendent pas à ce que Array effectue un rappel.

+0

Je pourrais aussi simplement remplacer les méthodes pour les instances qui m'intéressent. Mais je cherche un autre moyen d'ajouter cette fonctionnalité, car je n'aime pas remplacer toutes les méthodes qui pourraient ajouter un élément. Mais d'un autre côté, l'instance doit avoir la fonctionnalité à traiter comme un tableau. Merci pour votre aide, aussi. – Zardoz

+0

Je dois appuyer cette réponse. Vous pouvez même utiliser le même code que la balise fournie, mais l'affecter à une classe personnalisée. De cette façon, la classe Array conserve son comportement original. –

2

Utilisez le modèle « Observer » pour être informé de l'évolution de la taille du tableau que vous souhaitez observateur: Ruby Observer Cela vous évite d'avoir à remplacer toutes les méthodes qui ajoutent un élément au tableau

+2

Merci pour l'aide. Autant que je comprends la documentation dans l'observateur.rb je dois appeler "changé" pour informer les auditeurs. Mais cela me ramène au problème d'origine .. comment puis-je savoir que la taille de la matrice a changé? D'où puis-je appeler "changé"? – Zardoz

Questions connexes