一次定义类和实例方法 - Ruby

时间:2013-08-07 05:28:07

标签: ruby

我想:

module MyLog

  def log
    unless @log
      @log = Logger.new(log_path)
      @log.formatter =  proc do |severity, datetime, progname, msg|
        "#{datetime} #{msg}\n"
      end
    end
    @log
  end

end

要在其他类之间重用:

Class A
  def self.log_path; 'log/a.log' end
  def log_path; 'log/a.log' end
  include MyLog
  extend  MyLog

  def some_method
    log.debug 'some thing'
  end

  def self.some_class_method
    log.debug 'in a class method'
  end

end

在A级开始时,是否有比这四行短的方式?

另一件事

我想按批次登录:

def expire
  expired_ids = []
  failed_ids  = []

  all.each do |event|
    if event.expire # saves record
      expired_ids << event.id
    else
      failed_ids << event.id
    end
  end

  log.debug "These ids were expired: #{ expired_ids }"
  log.debug "These ids failed to expire: #{ failed_ids }"
end

有没有办法可以干净利落地做到这一点?从方法逻辑中分离日志记录?

3 个答案:

答案 0 :(得分:5)

这是我在遇到像你这样的问题时一直在做的事情:

class A
  class << self
    include MyLog

    def log_path
      'log/a.log'
    end
  end

  delegate :log_path, :log, to: "self.class"
end

否则,选择最佳编程方法取决于您的情况,您重复使用脚本的频率,在其生命周期内需要重构多少次,等等。但无论如何,请不要尝试保存代码的,尝试在下次自己阅读代码后为自己省去麻烦。

关于你的第二个问题,你面临的主要困境是,是否值得你介绍事件类:

class Events < Array
  def foobar
    each_with_object [[], []] do |event, (expired_ids, failed_ids)| 
      ( event.expire ? expired_ids : failed_ids ) << event.id
    end
  end
end

然后到时候:

def expire
  expired_ids, failed_ids = Events[ all ].foobar
  log.debug "These ids were expired: #{ expired_ids }"
  log.debug "These ids failed to expire: #{ failed_ids }"
end

答案 1 :(得分:3)

您可以使用included挂钩自动定义类方法和实例方法:

module MyLog

  def self.included(base)
    base.extend(Methods)
    base.send(:include, Methods)
  end

  module Methods
    def log_path; 'log/a.log' end

    def log
      unless @log
        @log = Logger.new(log_path)
        @log.formatter =  proc do |severity, datetime, progname, msg|
          "#{datetime} #{msg}\n"
        end
      end
      @log
    end
  end

end

像这样,一旦包含模块,类和实例方法都会自动定义。

对于第二个问题,请使用partition并返回值,然后记录它们:

def expire
  all.partition(&:expire)
end

然后,在您调用expire的地方,您可以记录返回值:

def call_something
  expired, failed = expire
  log.debug "These ids were expired: #{expired.map(&:id)}"
  log.debug "These ids failed to expire: #{failed.map(&:id)}"
end

答案 2 :(得分:2)

如果您的日志路径始终应该是log/<lower_case_class>.log,那么您可以在模块中实现它,您应该没问题。当执行模块的方法时,self仍然是调用该方法的对象,因此您可以说self.class并获取A而不是您的模块名称。

查看此问题的已接受答案,了解如何为您的班级以及该班级的对象添加方法

Why 'self' method of module cannot become a singleton method of class?

您可以使用Enumerable#partition来分解您的所有&#34; (你实际上没有说明你发布的代码中的位置)

expired, failed = all.partition(&:expire)