Как украсить метод в Ruby без alias_method_chain - PullRequest
4 голосов
/ 04 декабря 2010

Мы все знаем, что если целевой класс состоит из модулей, вы можете просто вызвать super в новом модуле.Но что, если это обычный метод в классе?

class Logger
  def message(msg)
    puts msg
  end
end

Скажем, Logger - это класс, который я не могу изменить (например, он находится в геме).И я хочу, чтобы Logger ставил строку "================" перед каждым сообщением.Как мне это сделать красоты образом?Наследование?Агрегация?Как?

Ответы [ 4 ]

3 голосов
/ 04 марта 2015

Вы можете сохранить исходный метод как объект несвязанного метода вместо сохранения его в псевдониме.

Затем вы можете использовать define_method с блоком. Блок будет захватывать несвязанный method_object в замыкании, что позволит вам использовать его в новом методе, не загрязняя ваш модуль / класс.

Единственным недостатком является то, что вы, вероятно, не можете определить метод, который уступает или принимает блок следующим образом:

module Mod
  unbound_method = instance_method(:original_method)
  define_method :original_method do |*args|
    #do something before
    #call the original method
    unbound_method.bind(self).call(*args)
    #do something after
  end
end
2 голосов
/ 04 декабря 2010

Вы можете наследовать от логгера и использовать пространство имен для его использования:

class LinedLogger < Logger
  def message(*)
    puts "=" * 15
    super
  end
end

И когда вы хотите его использовать:

class Post
  Logger = LinedLogger
end

Только в пространстве имен Post вы получите LinedLogger вместо Logger. Это хороший способ ограничить ваши патчи. Хотя это не будет работать глобально.

2 голосов
/ 04 декабря 2010

Я бы выполнил создание подклассов (за ответ @ iain) или включение пользовательских модулей в ваши собственные экземпляры:

module LoggerLiner
  def message(*args)
    puts "="*15
    super
  end
end

log = Logger.new(STDOUT)
log.extend(LoggerLiner)
2 голосов
/ 04 декабря 2010

Возможно, это не то, что вы подразумеваете под "красотой", но, возможно, самый простой способ - это где-то в вашем коде:

class Logger
  alias message old_message
  def message(msg)
    puts "================"
    old_message(msg)
  end
end
...