2013-08-20 14 views
0

我有幾個文件定義嵌套模塊,說:獲得一個模塊下的所有類

文件1:

module A 
    module B 
    class B1 
     class B1Error < Exception ; end 
    end 
    end 
end 

文件2:

module A 
    module B 
    class B2 
     class B2Error < Exception ; end 
     class B2_inner 
     end 
    end 
    end 
end 

我需要一種方法來獲取所有在給定模塊下定義的類。

def get_all_classes_under_module_hier(hier) 
    ??? 
end 
get_all_classes_under_module_hier(A::B) 
#=> A::B::B1, A::B::B1::B1Error, A::B::B2, A::B::B2::B2Error, A::B::B2::B2_inner. 

我該如何達到目的?

我需要這個的原因是:我正在嘗試使用log4r。我有幾個類,我正在每個類上創建classNames的記錄器。在YAML配置中,需要再次指出所有定義的記錄器名稱以進一步配置。我正在嘗試使用通用代碼來提取模塊層次結構下的所有類並進行動態配置。

關於我的log4r方法(或任何更簡單的方法)的任何輸入也表示讚賞。

回答

0

您可以使用Module::nesting如下:

返回嵌套在呼叫點的模塊列表。

module A 
    module B 
    class B2 
     class B1Error < Exception ; $b = Module.nesting ;end 
     class B2_inner 
     $a = Module.nesting 
     end 
    end 
    end 
end 

$a # => [A::B::B2::B2_inner, A::B::B2, A::B, A] 
$b # => [A::B::B2::B1Error, A::B::B2, A::B, A] 

,或者

Module::constants

從返回調用點訪問的所有常量的名稱的數組。

module A 
    module B 
    class B2 
     class B1Error < Exception ;end 
     class B2_inner 
     $a = Module.constants 
     end 
    end 
    end 
end 

$a - Module.constants 
# => [:B1Error, :B2_inner, :B2, :B] 
0
def get_all_modules_under_module_hier(hier) 
    a = hier 
    .constants 
    .map{|e| hier.const_get(e)} 
    .select{|e| e.kind_of?(Module)} 
    a + a.flat_map{|klass| get_all_classes_under_module_hier(klass)} 
end 
def get_all_classes_under_module_hier(hier) 
    get_all_modules_under_module_hier(hier) 
    .select{|e| e.instance_of?(Class)} 
end 

get_all_classes_under_module_hier(A::B) 
# => [A::B::B1, A::B::B2, A::B::B1::B1Error, A::B::B2::B2Error, A::B::B2::B2_inner] 
0

澤的答案是確定的,也可以使用像this的方法,爲每個類動態創建記錄器。

但是,我並不希望獲得模塊下的所有類。爲了能夠爲每個班級創建記錄器,您可以按照以下方式進行操作。

module Kernel 

    ####### 
    private 
    ####### 

    def logger 
    Log4r::Logger[logger_name] 
    end 

    def logger_name 
    clazz = self.class 
    unless clazz.respond_to? :logger_name 
     name = clazz.module_eval 'self.name' 
     clazz.define_singleton_method(:logger_name) { name } 
    end 
    clazz.logger_name 
    end 

end 

module A 
    module B 
    class C 

     def hello 
     logger.debug logger_name 
     end 

    end 
    end 
end 

A::B::C.new.hello 

對於一個具體的模塊中,你可以寫在logger_name方法的過濾器,例如類:

module Kernel 

    ####### 
    private 
    ####### 

    def logger 
    Log4r::Logger[logger_name] 
    end 

    def logger_name 
    clazz = self.class 
    unless clazz.respond_to? :logger_name 
     name = clazz.module_eval 'self.name' 
     name = 'root' unless name.start_with?('A::B') 
     clazz.define_singleton_method(:logger_name) { name } 
    end 
    clazz.logger_name 
    end 

end 

module A 
    module B 

    class C 

     def hello 
     logger.debug logger_name 
     end 

     class << self 
     def hello 
      logger.debug logger_name 
     end 
     end 

    end 
    end 

    class D 
    def hello 
     logger.debug logger_name 
    end 
    end 
end 

A::B::C.new.hello # A::B::C 
A::B::C.hello # A::B::C 
A::D.new.hello # root 

而且還可以緩存記錄器:

def logger 
    _logger = Log4r::Logger[logger_name] 
    self.class.send(:define_method, :logger) { _logger } 
    self.class.define_singleton_method(:logger) { _logger } 
    return _logger 
end 

希望它有助於。

相關問題