2011-02-04 12 views
9

Quiero reemplazar un método de un módulo A de otro módulo B que va a mono-patch A.
http://codepad.org/LPMCusztOverride de otro módulo

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

Este fue un caso 'alias_method_chain'. De hecho – clyfe

Respuesta

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

su solución funciona, pero este comportamiento molesto, no quiero para incluir el módulo en un lugar donde no se necesita. ¿Alguna idea sobre por qué el rubí se comporta así? – clyfe

2

incluye un módulo de lugares que anteriormente el módulo/clase que está incluida en la jerarquía de clases. En otras palabras, A # foo no es super de B # foo sino más bien al revés.

Si se piensa que incluye un módulo como una forma de hacer herencia múltiple que esto tenga sentido, include SomeModule es una forma de decir, "Tratar SomeModule como es una clase padre para mí".

Para obtener el resultado que quería tener que anular la inclusión de manera que B incluye R:

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 

Editar en respuesta a comentar:

Entonces, o incluyen tanto A como B en C con B incluido después de A:

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

class C 
    include A 
    include B 
end 

o parche A en C y no molestar con B.

# A as before, no B. 

class C 
    include A 

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

La única manera para que esto funcione es que si la búsqueda método en C es C -> B -> A y no hay manera de hacer esto sin incluir B en C.

+0

es un requisito para C incluyen a A y no B, y lo que necesito es a mono parche A. – clyfe

+0

No puedo modificar C. Puedo único parche mono A. – clyfe

+0

@clyfe ¿Por qué no puede modificarse de C? – Jonathan

0

Otra forma de lograr esto es incluir el módulo B cuando se incluye el módulo a.

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" 
Cuestiones relacionadas