2010-09-09 5 views
4

Je veux que le module suivant à inclure dans une classe I ont:Ruby métaprogrammation, définissant plusieurs « hérité » fonctions

module InheritanceEnumerator 
    def self.included(klass) 
     klass.instance_eval do 
     instance_variable_set('@subclasses',[]) 
     def self.subclasses 
      @subclasses 
     end 
     original_method = self.respond_to?(:inherited) ? self.public_method(:inherited) : nil 
     instance_variable_set('@original_inherited_method', original_method) 
     def self.inherited(subclass) 
      @original_inherited_method.call(subclass) if @original_inherited_method 
      @subclasses<<subclass 
     end 
     end 
    end 
end 

Ce que je suis en train de réaliser est que je veux que ma classe parente d'avoir des références diriger les enfants. J'ai également besoin de toutes les autres méthodes "héritées" définies sur ma classe par d'autres choses pour rester en place. Qu'est-ce que je fais mal?

+0

Quelle erreur obtenez-vous exactement? – horseyguy

+0

La méthode d'origine n'est pas appelée. –

Répondre

2

Votre code fonctionne dans cette situation (pour moi):

class C; include InheritanceEnumerator; end 
C.subclasses #=> [] 
class C1 < C; end 
class C2 < C; end 
C.subclasses #=> [C1, C2] 

Mais échoue dans la situation suivante:

class C11 < C1; end 
C1.subclasses => NoMethodError: undefined method `<<' for nil:NilClass 

Ceci est parce que vous n'initialisez @subclasses quand est inclus le module; mais vous oubliez que les sous-classes de C ont également accès aux méthodes des modules mais ne les expliquent pas explicitement include.

Vous résoudre ce problème en procédant comme suit:

def self.subclasses 
    @subclasses ||= [] 
    @subclasses 
end 

def self.inherited(subclass) 
    @original_inherited_method.call(subclass) if @original_inherited_method 

    @subclasses ||= [] 
    @subclasses << subclass 
end 

EDIT:

D'accord, à l'avenir, s'il vous plaît indiquer ce que votre problème est plus pleinement et fournir le code de test que vous utilisez; car c'était un exercice de frustration.

Les travaux suivants bien avec votre code:

class C 
    def self.inherited(s) 
     puts "inherited by #{s}!" 
    end 

    include InheritanceEnumerator 
end 

class D < C; end #=> "inherited by D!" 
C.subclasses #=> [D] 

Peut-être la raison pour laquelle il ne fonctionnait pas pour vous est que vous avez inclus InheritanceEnumeratoravant que vous aviez défini la méthode inherited?

+0

C'est le comportement attendu, je ne veux pas nécessairement une sous-classe pour garder une trace de ses sous-classes. Cela fonctionne-t-il même si vous déclarez une autre fonction "héritée"? –

+0

@MrZombie, la réponse mise à jour répond-elle à votre problème? :) – horseyguy