Comment peut-on - sans héritage - remplacer une méthode de classe et appeler l'original à partir de la nouvelle méthode?

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

Question

J'ai trouvé une source qui a remplacé avec succès Time.strftime comme ceci:

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

Le problème est que strftime est une méthode d'instance. Je dois remplacer Time.now - une méthode de classe - de manière à ce que tout appelant reçoive ma nouvelle méthode, tandis que la nouvelle méthode appelle toujours la méthode .now d'origine. J'ai consulté alias_method et je n'ai rencontré aucun succès.

Était-ce utile?

La solution

C’est un peu difficile à comprendre, mais vous devez ouvrir la & "eigenclass &"; qui est le singleton associé à un objet de classe spécifique. la syntaxe est la classe < < faire soi-même ... fin

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

Autres conseils

Les méthodes de classe ne sont que des méthodes. Je le recommande vivement, mais vous avez deux choix équivalents:

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 vous devez le remplacer à des fins de test (la raison pour laquelle je souhaite généralement remplacer Time.now), les frameworks de moquage / stub de Ruby le feront facilement pour vous. Par exemple, avec RSpec (qui utilise flexmock):

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

En passant, je vous recommande vivement d'éviter de remplacer Time.now en donnant à vos classes une horloge qui peut être remplacée:

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

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

J'ai essayé de comprendre comment remplacer une méthode d'instance à l'aide de modules.

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top