¿Cómo se puede, sin herencia, anular un método de clase y llamar al original desde el nuevo método?
-
08-07-2019 - |
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.
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