我以为我会使用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在那时可用。有什么想法吗?
答案 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