2011-02-04 13 views
9

voglio ignorare un metodo da un modulo A da un altro modulo B che vi scimmia-toppa A.
http://codepad.org/LPMCusztOverride da un altro modulo

module A 
    def foo; puts 'A' end 
end 

module B 
    def foo; puts 'B'; super; end 
end 

A.module_eval { include B } # why no override ??? 

class C 
    include A 
end 

# must print 'A B', but only prints 'A' :(
C.new.foo 
+0

Questo era un caso "alias_method_chain'. – clyfe

risposta

5
module A 
    def foo 
    puts 'A' 
    end 
end 

module B 
    def foo 
    puts 'B' 
    super 
    end 
end 

include A # you need to include module A befor you can override method 

A.module_eval { include B } 

class C 
    include A 
end 

C.new.foo # => B A 
+1

In effetti la tua soluzione funziona ma questo comportamento è fastidioso, non voglio includere il modulo da qualche parte dove non è necessario. Qualche idea sul perché il rubino si comporta in questo modo? – clyfe

2

Compreso un modulo lo mette sopra il modulo/classe che lo include nella gerarchia di classi. In altre parole, A # foo non è super di B # pippo ma piuttosto il contrario.

Se si pensa di includere un modulo come modo di fare ereditarietà, questo ha senso, include SomeModule è un modo per dire "Tratta SomeModule come se fosse una classe genitore per me".

per ottenere il risultato che volevi è necessario invertire l'inserimento in modo che B comprende una:

module A 
    def foo; puts 'A' end 
end 

module B 
    def foo; puts 'B'; super; end 
end 

B.module_eval { include A } # Reversing the inclusion 

class C 
    include B # not include A 
end 

puts C.new.foo 

Modifica in risposta al commento:

Allora o includono sia A che B in C con B incluso dopo A:

# A and B as before without including B in A. 

class C 
    include A 
    include B 
end 

o patch A in C e non disturbare con B.

# A as before, no B. 

class C 
    include A 

    def foo; puts 'B'; super; end 
end 

L'unico modo per far funzionare tutto è se il metodo di ricerca su C è C -> B -> A e non c'è modo di fare questo senza includere B in C.

+0

è un requisito per C includere A e non B, e quello che mi serve è patch di scimmia A. – clyfe

+0

Non riesco a modificare C. Posso solo patch di scimmia A. – clyfe

+0

@clyfe Perché non puoi modificare C? – Jonathan

0

Un altro modo per realizzare questo è includere il modulo B quando il modulo A è incluso.

module A 
    def foo 
    puts "this should never be called!" 
    "a" 
    end 
end 

module B 
    def foo 
    "b" 
    end 
end 

module A 
    def self.included(base) 
    base.class_eval do 
     include B 
    end 
    end 
end 

class C 
    include A 
end 

C.new.foo # "b" 
Problemi correlati