2008-11-13 27 views
9

He encontrado una fuente de la que hizo caso omiso de éxito Time.strftime así:¿Cómo puede uno, sin herencia, anular un método de clase y llamar al original desde el nuevo método?

class Time 
    alias :old_strftime :strftime 
    def strftime 
    #do something 
    old_strftime 
    end 
end 

El problema es que strftime es un método de instancia. Necesito anular Time.now - un método de clase - de tal manera que cualquier persona que llama obtenga mi nuevo método, mientras que el nuevo método todavía llama al método original .now. Miré alias_method y no tuve éxito.

Respuesta

11

Esto es un poco difícil de conseguir su cabeza en torno a veces, pero hay que abrir el "eigenclass", que es el producto único asociado a un objeto de clase específica . la sintaxis para esto es clase < < self do ... end.

class Time 
    alias :old_strftime :strftime 

    def strftime 
    puts "got here" 
    old_strftime 
    end 
end 

class Time 
    class << self 
    alias :old_now :now 
    def now 
     puts "got here too" 
     old_now 
    end 
    end 
end 

t = Time.now 
puts t.strftime 
2

Los métodos de clase son solo métodos. Yo recomendaría altamente contra de esto, pero usted tiene dos opciones equivalentes:

class Time 
    class << self 
    alias_method :old_time_now, :now 

    def now 
     my_now = old_time_now 
     # new code 
     my_now 
    end 
    end 
end 

class << Time 
    alias_method :old_time_now, :now 

    def now 
    my_now = old_time_now 
    # new code 
    my_now 
    end 
end 
1

Si el que necesita para anularlo para propósitos de prueba (la razón por la que normalmente se quieren anular Time.now), Ruby burlarse/marcos stubbing lo hará por usted fácilmente. Por ejemplo, con RSpec (que utiliza flexmock):

Time.stub!(:now).and_return(Time.mktime(1970,1,1)) 

Por cierto, le recomiendo evitando la necesidad de apagar Time.now dando a sus clases de un reloj overrideable:

class Foo 
    def initialize(clock=Time) 
    @clock = clock 
    end 

    def do_something 
    time = @clock.now 
    # ... 
    end 
end 
0

I He estado intentando descubrir cómo anular un método de instancia usando módulos.

module Mo 
    def self.included(base) 
    base.instance_eval do 
     alias :old_time_now :now 
     def now 
     my_now = old_time_now 
     puts 'overrided now' 
     # new code 
     my_now 
     end 
    end 
    end 
end 
Time.send(:include, Mo) unless Time.include?(Mo) 

> Time.now 
overrided now 
=> Mon Aug 02 23:12:31 -0500 2010 
Cuestiones relacionadas