Подтвердить что ты не робот

Как узнать, какие модули были добавлены в класс?

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

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

ОБНОВЛЕНИЕ

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

obj.extend(MyModule)

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

4b9b3361

Ответ 1

Try:

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

например:

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

ОБНОВЛЕНИЕ

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

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

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

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

и решение тогда:

obj.eigenclass.included_modules

Ответ 2

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

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

Ответ 3

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

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

module Foo
end

class Bar
  include Foo
end

Bar < Foo
# => true

Ответ 4

obj.singleton_class.included_modules

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

obj.singleton_class.include? MyModule

Ответ 5

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

Как уже упоминалось, вы можете определить, включен ли модуль в класс, проверяя метод класса 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, Russ Olsen:

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

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

# will also return true if MyClass.include(Comparable)
MyClass.new.kind_of?(Comparable)

Ответ 6

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

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]