2011-02-04 9 views
9

Chcę przesłonić metodę z modułu A z innego modułu B, która będzie małpa-Patch A.
http://codepad.org/LPMCusztZastąp metoda moduł z innego modułu

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

To był przypadek 'alias_method_chain'. – clyfe

Odpowiedz

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

Rzeczywiście twoje rozwiązanie działa, ale to zachowanie jest denerwujące, nie chcę włączać modułu gdzieś, gdzie nie jest potrzebny. Jakieś pomysły na to, dlaczego ruby ​​zachowuje się w ten sposób? – clyfe

2

tym module umieszcza go powyżej moduł/klasa, która jest uwzględniana w hierarchii klas. Innymi słowy, A # foo nie jest super od B # foo, ale raczej odwrotnie.

Jeśli myślisz o włączeniu modułu jako sposobie dziedziczenia wielokrotnego, ma to sens, include SomeModule to sposób na powiedzenie: "Traktuj SomeModule tak, jakby to była dla mnie klasa rodzicielska".

Aby uzyskać wyjście chciałeś trzeba odwrócić włączenia tak że B zawiera:

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 

Edytowanie w odpowiedzi na komentarz:

wówczas obejmować zarówno A i B C z B zawarta po A:

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

class C 
    include A 
    include B 
end 

lub łatka A w C i nie przejmuj się B.

# A as before, no B. 

class C 
    include A 

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

Jedynym sposobem pracy jest to, że w sposób odnośników C oznacza grupę -> B -> A i nie ma sposobu, aby to zrobić bez włączenia B do C

+0

jest to wymóg, aby C zawierał A, a nie B, a co jest mi potrzebne to łatka z małpką A. – clyfe

+0

Nie mogę zmodyfikować C. Mogę tylko łatkę małpy A. – clyfe

+0

@clyfe Dlaczego nie możesz zmodyfikować C? – Jonathan

0

Innym sposobem w tym celu należy uwzględnić moduł B, gdy moduł A jest zawarty.

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" 
Powiązane problemy