Как можно - без наследования - переопределить метод класса и вызвать оригинал из нового метода?
-
08-07-2019 - |
Вопрос
Я нашел один источник, который успешно переопределил Time.strftime
, например:
class Time
alias :old_strftime :strftime
def strftime
#do something
old_strftime
end
end
Проблема в том, что strftime
является методом экземпляра. Мне нужно переопределить Time.now
- метод класса - таким образом, чтобы любой вызывающий получил мой новый метод, в то время как новый метод все еще вызывает оригинальный метод .now
. Я посмотрел на alias_method
и не добился успеха.
Решение
Иногда бывает сложно разобраться, но вам нужно открыть " eigenclass " который является синглтоном, связанным с конкретным объектом класса. синтаксис для этого класса < < Я делаю ... конец. Р>
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
Другие советы
Методы класса - это просто методы. Я настоятельно рекомендую против этого, но у вас есть два эквивалентных варианта:
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
Если вам нужно переопределить его для целей тестирования (причина, по которой я обычно хочу переопределить Time.now), среды Ruby mocking / stubbing сделают это для вас легко. Например, с RSpec (который использует flexmock):
Time.stub!(:now).and_return(Time.mktime(1970,1,1))
Кстати, я настоятельно рекомендую избегать необходимости заглушать Time.now, предоставляя вашим классам переопределяемые часы:
class Foo
def initialize(clock=Time)
@clock = clock
end
def do_something
time = @clock.now
# ...
end
end
Я пытался выяснить, как переопределить метод экземпляра с помощью модулей.
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