如何判断哪些模块已混合到一个类中?

Der*_*ins 34 ruby

我有一个类,它有许多模块,它们根据一些运行时标准与它混合在一起.

我希望能够获得已经混合到这个类中的模块的列表.你怎么能这样做?

UPDATE

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

obj.extend(MyModule)
Run Code Online (Sandbox Code Playgroud)

obj.included_modules和obj.ancestors不存在,因此您无法从那里获取已混入的模块.

Dan*_*aft 40

尝试:

MyClass.ancestors.select {|o| o.class == Module }
Run Code Online (Sandbox Code Playgroud)

例如:

>> Array.ancestors.select {|o| o.class == Module}
=> [Enumerable, Kernel]
Run Code Online (Sandbox Code Playgroud)

UPDATE

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

(class << obj; self; end).included_modules
Run Code Online (Sandbox Code Playgroud)

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

module Kernel
  def eigenclass
    class << self
      self
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

然后解决方案是:

obj.eigenclass.included_modules
Run Code Online (Sandbox Code Playgroud)

  • 有一种现成的方法,叫做"included_modules". (11认同)
  • 读者注意到,这个答案来自2009年.Ruby 1.9引入了`Object#singleton_class`,它与上面的猴子修补的`Kernel#eigenclass`实现相同. (2认同)

Swa*_*and 39

这可能是一个更好的主意:

MyClass.included_modules
irb(main):001:0> Array.included_modules
=> [Enumerable, Kernel]
Run Code Online (Sandbox Code Playgroud)


Jam*_*sen 22

如果您正在寻找整个列表,Swanand的答案是您最好的选择.

另一方面,如果您想检查某个类是否包含特定模块,那么该<运算符就是您的朋友:

module Foo
end

class Bar
  include Foo
end

Bar < Foo
# => true
Run Code Online (Sandbox Code Playgroud)


Ale*_*nov 19

obj.singleton_class.included_modules
Run Code Online (Sandbox Code Playgroud)

如果你想检查是否包含模块:

obj.singleton_class.include? MyModule
Run Code Online (Sandbox Code Playgroud)


Bat*_*ins 6

这是查看某个模块是否已被类包含扩展的另一种有效方法.

正如其他人所提到的,您可以通过检查included_modulesruby中所有类上存在的类方法来确定模块是否包含在类中.

因此,如果您有一个名为的类,MyClass并且您想要查看它是否包含Comparable模块,您可以执行以下操作:

# will return true if MyClass.include(Comparable)
MyClass.included_modules.include?(Comparable)
Run Code Online (Sandbox Code Playgroud)

如果你想确定你的类是否扩展ActiveRecord::Querying模块,就像所有rails模型类一样,你可以实际使用它:

# will return true if MyClass.extend(ActiveRecord::Querying)
MyClass.kind_of?(ActiveRecord::Querying)
Run Code Online (Sandbox Code Playgroud)

为什么这样做?引用Russ Olsen的书Eloquent Ruby:

当您将模块混合到一个类中时,Ruby会稍微重新编写类层次结构,将模块作为类的一个伪超类插入.

这也意味着确定模块是否已包含在您的类中的另一种方法是执行类似的操作(尽管我仍然更喜欢该included_modules方法):

# will also return true if MyClass.include(Comparable)
MyClass.new.kind_of?(Comparable)
Run Code Online (Sandbox Code Playgroud)