In che modo uno, senza ereditarietà, sostituisce un metodo di classe e chiama l'originale dal nuovo metodo?
-
08-07-2019 - |
Domanda
Ho trovato una fonte che ha superato con successo Time.strftime
in questo modo:
class Time
alias :old_strftime :strftime
def strftime
#do something
old_strftime
end
end
Il problema è che strftime
è un metodo di istanza. Devo sostituire Time.now
- un metodo di classe - in modo tale che qualsiasi chiamante ottenga il mio nuovo metodo, mentre il nuovo metodo chiama ancora il metodo .now
originale. Ho esaminato alias_method
e non ho riscontrato alcun successo.
Soluzione
A volte è difficile capovolgere la testa, ma è necessario aprire " eigenclass " che è il singleton associato a un oggetto classe specifico. la sintassi per questo è class < < 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
Altri suggerimenti
I metodi di classe sono solo metodi. Lo sconsiglio vivamente, ma hai due opzioni equivalenti:
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
Se hai bisogno di sovrascriverlo a scopo di test (il motivo per cui normalmente voglio ignorare Time.now), i framework di derisione / stub Ruby lo faranno facilmente per te. Ad esempio, con RSpec (che utilizza flexmock):
Time.stub!(:now).and_return(Time.mktime(1970,1,1))
A proposito, consiglio vivamente di evitare la necessità di stub time.now dando alle tue classi un orologio irreversibile:
class Foo
def initialize(clock=Time)
@clock = clock
end
def do_something
time = @clock.now
# ...
end
end
Ho cercato di capire come sovrascrivere un metodo di istanza usando i moduli.
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