¿Cómo se puede, sin herencia, anular un método de clase y llamar al original desde el nuevo método?

StackOverflow https://stackoverflow.com/questions/288020

Pregunta

Encontré una fuente que anuló con éxito Time.strftime como esto:

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

El problema es, strftime es un método de instancia.necesito anular Time.now - un método de clase - de tal manera que cualquier persona que llama obtiene mi nuevo método, mientras que el nuevo método sigue llamando al original .now método.he mirado alias_method y no han tenido éxito.

¿Fue útil?

Solución

Esto es un poco difícil de entender a veces, pero necesita abrir la " eigenclass " que es el singleton asociado con un objeto de clase específico. la sintaxis para esto es class < < auto hacer ... final.

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

Otros consejos

Los métodos de clase son solo métodos. Le recomiendo esto, pero 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

Si necesita anularlo con fines de prueba (la razón por la que normalmente quiero anular Time.now), los marcos de burlas / trozos de Ruby lo harán fácilmente. Por ejemplo, con RSpec (que usa flexmock):

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

Por cierto, recomiendo evitar la necesidad de eliminar Time.now dándoles a sus clases un reloj anulable:

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

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

He estado tratando de 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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top