2009-08-25 4 views
32

У меня есть класс, который имеет несколько модулей, которые смешиваются с ним на основе некоторых критериев времени исполнения.Как узнать, какие модули были добавлены в класс?

Я хочу, чтобы получить список того, какие модули были смешаны с этим классом. Как вы можете это сделать?

UPDATE

Так что, когда я сказал, я имел в виду класс объекта, как это объект, который расширяется во время выполнения с помощью:

obj.extend(MyModule) 

obj.included_modules и obj.ancestors не существует, поэтому вам не могут получить модули, которые были смешаны оттуда.

ответ

38

Try:

MyClass.ancestors.select {|o| o.class == Module } 

, например:

>> Array.ancestors.select {|o| o.class == Module} 
=> [Enumerable, Kernel] 

UPDATE

Чтобы получить модули, смешанные в экземпляр объекта во время выполнения вы должны извлечь eigenclass экземпляра , Там нет чистого способа сделать это в Ruby, но достаточно распространенной идиомой является следующее:

(class << obj; self; end).included_modules 

Если вы будете использовать это много, вы можете сделать его доступность:

module Kernel 
    def eigenclass 
    class << self 
     self 
    end 
    end 
end 

и раствор затем:

obj.eigenclass.included_modules 
+10

Существует готовый метод, что называется 'included_modules '. – Swanand

+0

Так есть. Спасибо за совет. –

+0

Оказывается, я прыгнул с пистолета. Я еще раз уточнил этот вопрос. –

39

Это может быть лучшей идеей:

MyClass.included_modules 
irb(main):001:0> Array.included_modules 
=> [Enumerable, Kernel] 
21

Если вы ищете полный список, то Swanand's answer - ваш лучший выбор.

Если, с другой стороны, вы хотите, чтобы проверить, содержит ли класс в конкретный модуль, оператор < является вашим другом:

module Foo 
end 

class Bar 
    include Foo 
end 

Bar < Foo 
# => true 
3

только классы могут методы сюжетные и при добавлении метода к экземпляру, который вы фактически добавляете к метаклассу объектов. Модуль, который вы ищете, будет находиться в списке предков метакласса.

module TestModule; end 

obj = "test" 
obj.extend(TestModule) 

class Object 
    def metaclass 
    class << self; self; end 
    end 
end 

obj.metaclass.ancestors 
# => [TestModule, String, Comparable, Object, Kernel, BasicObject] 
6

Вот еще один эффективный способ увидеть, если модуль был включен или расширенный классом.

Как уже упоминалось, вы можете определить, включен ли модуль в класс, проверив метод класса included_modules, который существует для всех классов в ruby.

Так что, если вы имели класс с именем MyClass и вы хотите, чтобы увидеть, если он включен в Comparable модуль, который вы могли бы сделать что-то вроде этого:

# will return true if MyClass.include(Comparable) 
MyClass.included_modules.include?(Comparable) 

Если вы хотите, чтобы определить, имеет ли ваш класс продлен на ActiveRecord::Querying модуль, как и все классы рельсы модели, вы можете использовать это:

# will return true if MyClass.extend(ActiveRecord::Querying) 
MyClass.kind_of?(ActiveRecord::Querying) 

Почему это работает? Цитирую книгу Eloquent Ruby, by Russ Olsen:

Когда вы смешиваете модуль в класс, Ruby повторно едет иерархии классов немного, вставляя модуль в качестве своего рода псевдо суперкласс класса.

Это также означает, что еще один способ, чтобы определить, был ли модуль включен в ваш класс, чтобы сделать что-то вроде этого (хотя я до сих пор предпочитаю метод included_modules):

# will also return true if MyClass.include(Comparable) 
MyClass.new.kind_of?(Comparable) 
17
obj.singleton_class.included_modules 

И если вы хотите проверить, включен ли модуль:

obj.singleton_class.include? MyModule 
+0

AFAIK, это определенно сейчас предпочтительный способ проверить это. – xiy

2

I как @ AlexParamonov, решение которого, но я играл и обнаружил, что это работает точно так же:

obj.class.include? MyModule

MyClass.include? MyModule

http://www.ruby-doc.org/core-2.1.2/Module.html#method-i-include-3F

+0

Если вы не изменили объект singleton. Например: 'a = []; a.extend (MyAwesomeModule) '. В этом случае 'a.class.included_modules' не будет включать' MyAwesomeModule', но 'a.singleton_class.included_modules' будет – AlexParamonov

Смежные вопросы