2013-06-11 5 views
0

Я думал, что сделаю микширование для регистрации, чтобы сохранить мой код 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 называется до в Примеси включены, в результате чего это для отказа:

class SomeClass 
    include Logging 

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

И я не могу изобразить вокруг него никакой возможности. Я всегда создаю свои зависимости в конструкторе, и мне нужно, чтобы в этот момент был доступен Mixing Logging. Есть идеи?

ответ

0

Это неправильно:

Проблема заключается в том, что, видимо ИНИЦИАЛИЗИРУЙТЕ вызывается до Примеси включены, в результате чего этот сбой:

Вопреки тому, что вы написали, initialize не называется. @subloggers не инициализирован для экземпляра SomeClass. Вы думаете, что @subloggers, назначенный в Logging.included(base), та же переменная, что и у @subloggers, к которой вы обращаетесь с помощью конструктора SomeClass? Это не должно быть так. Невозможно создать переменную экземпляра до создания самого экземпляра.

+0

Любой способ сделать то, что я пытаюсь добиться? – Hubro

+0

Если эти переменные должны быть разделены между экземплярами, вы должны определить их как переменные класса или переменные экземпляров в классе. Если вы хотите, чтобы каждый экземпляр имел разные переменные, вам нужно поместить его в конструктор. – sawa

+0

Итак, нет способа, чтобы mixin определял переменные экземпляра. – Hubro

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