如何仅从包含的模块列出方法

时间:2013-11-21 08:27:40

标签: ruby

我将一些模块包含并扩展到我的课程中。

我将binding.pry放入其中。使用self.methods列出我拥有的所有方法。 但是列表太长了,我怎么才能在我包含的模块中列出方法。除了我的self.class中的方法和来自inspect to_s之类的祖先的方法,...

include SnapshotsHelper
extend SnapshotsHelper

谢谢

2 个答案:

答案 0 :(得分:2)

我认为您正在寻找以下内容:

何时包含模块

module A
 def meth1;end
 def meth2;end
end

module B
 def meth11;end
 def meth21;end
end

class C
  include A,B
end

list = C.included_modules.each_with_object({}) do |m,ob|
  module_arry = m.instance_methods
  ob[m]=C.instance_methods.select{|e| module_arry.include?(e)} if m != Kernel
end

p list

# >> {A=>[:meth1, :meth2], B=>[:meth11, :meth21]}

何时扩展模块

module A
 def meth1;end
 def meth2;end
end

module B
 def meth11;end
 def meth21;end
end

class C
  extend A,B
end

list = C.singleton_class.included_modules.each_with_object({}) do |m,ob|
  module_arry = m.instance_methods
  class_methods = C.methods - C.instance_methods
  ob[m]= class_methods.select{|e| module_arry.include?(e)} if m != Kernel
end

p list

# >> {A=>[:meth1, :meth2], B=>[:meth11, :meth21]}

答案 1 :(得分:1)

我想你只想要你所在的孩子中包含的模块中的方法,从父母中包含的模块中过滤掉方法。如果你也想要父母提供的模块,那么@Arup的答案就是好的。

没有提供您想要的核心方法,但如果您经常需要,可以创建一个。

先决条件知识

给定类有三种方法来源:

  • 类本身及其猴子补丁中定义的方法
  • 来自父母的方法
  • 模块中的方法

来自模块的方法可以插入类本身或父类中(或者甚至通过模块中的钩子插入,但让我们把它放在一边)。

另请注意,Class继承自Module,因此Class是一个Module。

如何检索模块

现在,拥有所有这些,您要做的是将所有模块包含在当前类中,删除父模块并获取方法。因此基本公式是:

methods_from_module_included_in_current_class = ( modules_in_class - modules_in_parent ).methods

要在课堂上获取所有模块,您可以使用#ancestors方法。它将列出已在当前类中混合的所有类和模块(请记住:类只是一个模块)。

modules_in_class = MyClass.ancestors.reject { |ancestor| Class === ancestor }

在这里,我们拒绝列表中的类(Class === ancestor与执行ancestor.is_a? Class相同),因此我们知道我们只有模块。同样,我们不能只选择模块,因为Class是Module。

最后,我们可以应用相同的模式从父级获取模块:

module_in_parent = MyClass.superclass.ancestors.reject { |ancestor| Class === ancestor }

获取方法

因此,要从当前类中包含的模块中获取所有方法:

( MyClass.ancestors.reject { |ancestor| Class === ancestor } - MyClass.superclass.ancestors.reject { |ancestor| Class === ancestor } ).map( &:instance_methods ).flatten

要获取类方法(因此使用#extend添加方法),请将instance_methods替换为methods

注意,如果在类初始化时声明了一些匿名模块,那么你可能仍然有一些不熟悉的方法,就像在ActiveRecord :: Base上的rails一样。

保理

如果您经常使用此功能,可以使用方法对其进行分解:

class Object
  def inner_module_methods
    ( self.class.ancestors.reject { |ancestor| Class === ancestor } - self.class.superclass.ancestors.reject { |ancestor| Class === ancestor } ).map( &:instance_methods ).flatten
  end
end

您现在可以:

obj.inner_module_methods

或撬内:

inner_module_methods

替代

您可能还想要filter methods by source file。从长远来看,如果发现这种情况更有效,更不稳定。