代码之家  ›  专栏  ›  技术社区  ›  Derek Ekins

我怎样才能知道哪些模块已经混合到一个类中?

  •  33
  • Derek Ekins  · 技术社区  · 16 年前

    我有一个类,它包含许多模块,这些模块基于一些运行时条件与之混合在一起。

    我想能够得到这个类中混合了哪些模块的列表。你怎么能做到?

    更新

    所以当我说类时,我的意思是对象,因为它是在运行时使用以下方法扩展的对象:

    obj.extend(MyModule)
    

    obj.included_modules和obj.祖先不存在,因此无法从中获取混合的模块。

    7 回复  |  直到 11 年前
        1
  •  39
  •   Daniel Lucraft    16 年前

    尝试:

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

    例如:

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

    更新

    要在运行时将模块混合到对象实例中,您需要检索实例的特征类。在Ruby中没有明确的方法可以做到这一点,但是一个相当常见的习惯用法是:

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

    如果你发现自己经常使用它,你可以使它普遍可用:

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

    解决方法是:

    obj.eigenclass.included_modules
    
        2
  •  39
  •   Swanand    16 年前

    这可能是个更好的主意:

    MyClass.included_modules
    irb(main):001:0> Array.included_modules
    => [Enumerable, Kernel]
    
        3
  •  22
  •   Community CDub    8 年前

    如果你在找整个名单, Swanand's answer 是你最好的选择。

    另一方面,如果要检查类是否包含 特定的 模块 < 接线员是你的朋友:

    module Foo
    end
    
    class Bar
      include Foo
    end
    
    Bar < Foo
    # => true
    
        4
  •  19
  •   Alexander Paramonov    12 年前
    obj.singleton_class.included_modules
    

    如果您想检查模块是否包括:

    obj.singleton_class.include? MyModule
    
        5
  •  6
  •   Batkins    12 年前

    下面是另一种有效的方法来查看模块是否 包括 扩展的 通过一个班级。

    正如其他人提到的,您可以通过检查 included_modules Ruby中所有类上都存在的类方法。

    所以如果你有一个名为 MyClass 你想看看 包括 这个 Comparable 模块您可以这样做:

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

    如果你想确定你的班级是否 扩展的 这个 ActiveRecord::Querying 模块,和所有Rails模型类一样,您实际上可以使用它:

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

    为什么会这样?引用这本书 Eloquent Ruby, by Russ Olsen :

    当您将一个模块混合到一个类中时,Ruby将类的层次结构重新布线一点,并将该模块作为类的一种伪超类插入。

    这也意味着确定模块是否 包括 进入你的课堂就是做这样的事情(尽管我还是喜欢 包括\模块 方法:

    # will also return true if MyClass.include(Comparable)
    MyClass.new.kind_of?(Comparable)
    
        6
  •  3
  •   David Billskog    16 年前

    只有类可以描述方法,当您向实例添加方法时,实际上是将它添加到对象元类中。您要查找的模块将在这个元类祖先列表中。

    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]
    
        7
  •  2
  •   dasnixon    11 年前

    我喜欢@alexparamonov的解决方案,但我四处游玩,发现这也很有效:

    obj.class.include? MyModule

    MyClass.include? MyModule

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

    推荐文章