是否可以在调用构造函数之前进行mixin?

时间:2013-06-11 10:39:25

标签: ruby mixins ruby-2.0

我以为我会使用mixin进行日志记录以保持我的代码DRY。这是它的外观:

# Mixin that provides shortcuts for logging methods.
module Logging
  def self.included(base)
    base.class_exec {
      @logger_name = base.to_s
      @subloggers = []
      @logger = Logger.new(STDOUT)
      @logger.level = Logger::FATAL
    }
  end

  def logger=(logger)
    @logger = logger
    @subloggers.each { |obj| obj.logger = logger }
  end

  def debug(&block)
    @logger.debug(@logger_name, &block)
  end

  def info(&block)
    @logger.info(@logger_name, &block)
  end

  def warn(&block)
    @logger.warn(@logger_name, &block)
  end

  def error(&block)
    @logger.error(@logger_name, &block)
  end

  def fatal(&block)
    @logger.fatal(@logger_name, &block)
  end
end

理论上,我现在应该能够做到这一点:

class SomeClass
  include Logging

  def foo_bar
    debug { "foo_bar is being executed" }
    fatal { "IT'S A TRAP" }
  end
end

问题是显然initialize在包含mixin之前被称为,导致此失败:

class SomeClass
  include Logging

  def initialize
    @cache = CacheClass.new
    @subloggers << @cache   # @subloggers is nil
  end
end

我无法想象任何方式。我总是在构造函数中创建我的依赖项,并且我需要Logging mixin在那时可用。有什么想法吗?

2 个答案:

答案 0 :(得分:0)

这是错误的:

  

问题是在包含mixin之前调用了显然初始化,导致失败:

与您所写的内容相反,initialize未被调用。 @subloggers实例未初始化SomeClass。您是否认为@subloggers中分配的Logging.included(base)与您从@subloggers构造函数中访问的SomeClass变量相同?情况应该不是这样。在创建实例本身之前无法创建实例变量。

答案 1 :(得分:0)

我认为当你在该类中混合时,这些变量将成为类中的实例变量。不要与类变量或常规实例变量混淆。看看这个小小的irb对话:

1.9.3p194 :012 > class Foo
1.9.3p194 :013?>   def self.bar
1.9.3p194 :014?>     @bar
1.9.3p194 :015?>     end
1.9.3p194 :016?>    def self.bar=(x)
1.9.3p194 :017?>     @bar=x
1.9.3p194 :018?>     end
1.9.3p194 :019?>    def self.show
1.9.3p194 :020?>     puts @bar
1.9.3p194 :021?>     end
1.9.3p194 :022?>   end
 => nil
1.9.3p194 :023 > Foo.bar=5
 => 5
1.9.3p194 :024 > Foo.bar
 => 5
1.9.3p194 :025 > Foo.show
5
 => nil
1.9.3p194 :026 > a=Foo.new
 => #<Foo:0x007fe9038e5dc0>
1.9.3p194 :029 > a.instance_variables
 => []
1.9.3p194 :030 > a.class.instance_variables
 => [:@bar]

比较课程结果:

SomeClass.instance_variables
SomeClass.new.instance_variables
SomeClass.new.class.instance_variables