如何包含扩展classmethods并正确引用class var的模块

时间:2013-03-07 14:30:19

标签: ruby include extend

我的期望是在评论中。

require 'logger'

module Logging
  attr_accessor :logger

  def logger
    return @logger if @logger # allow items to have own loggers
    @@logger ||= Logger.new(STDERR)
    puts "Instance Class REF ID#{@@logger.__id__}"
    puts "Class ID #{self.class.logger.__id__}"
    @@logger
  end

  module ClassMethods
    def logger= logger
      @logger = logger
    end

    def logger
      @logger ||= Logger.new(STDERR)
      puts "Class Instance REF ID #{@logger.__id__}"
      @logger
    end
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

class Test

  include Logging

  def wow
    logger.info 'wow'
  end
end

t = Test.new

# should be the same
puts "Loggers are #{t.logger.__id__ == Test.logger.__id__ ? '' : 'not '}the same"

Test.logger = Logger.new('/dev/null')

# should still be the same
puts "Loggers are #{t.logger.__id__ == Test.logger.__id__ ? '' : 'not '}the same"

lg = Test.logger.__id__
t.logger =  Logger.new(STDERR)

# class logger should be same
puts "Class Logger is #{Test.logger.__id__ == lg ? 'still the' : 'not'} same"

# class and instance logger should be different
puts "Loggers are #{t.logger.__id__ == Test.logger.__id__ ? '' : 'not '}the same"

执行时:

➜  sandbox  irb
1.9.3-p392 :001 > load 'test_l.rb'
Instance Class REF ID70203753590760
Class Instance REF ID 70203753590500
Class ID 70203753590500
Class Instance REF ID 70203753590500

Loggers are not the same  # I expected to be same... :(

Instance Class REF ID70203753590760
Class Instance REF ID 70203753590000
Class ID 70203753590000
Class Instance REF ID 70203753590000

Loggers are not the same  # I expected to be same... :(

Class Instance REF ID 70203753590000
Class Instance REF ID 70203753590000

Class Logger is still the same

Class Instance REF ID 70203753590000

Loggers are not the same 

1 个答案:

答案 0 :(得分:6)

我故意忘记了如何使用@@变量,因为它们很混乱,很少需要。

相反,请考虑仅使用实例变量,但如果需要,则委托给类级别:

module Logging
  attr_writer :logger

  def logger
    defined?(@logger) ? @logger : self.class.logger
  end

  module ClassMethods
    def logger=(logger)
      @logger = logger
    end

    def logger
      @logger ||= Logger.new(STDERR)
    end
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

class Test
  include Logging

  # ...
end