获取Ruby中任何给定模块的嵌套层次结构

时间:2019-07-08 20:14:33

标签: ruby metaprogramming

我有一种方法,该方法需要能够访问模块定义的嵌套层次结构。假设我有这个定义:

module A
  module B
    module C
    end
  end
end

我正在尝试编写一种方法,以便如果对方法C的引用传递给该方法,它就可以返回Module.nesting的结果,就像在定义内被调用一样。例如:

get_nesting(A::B::C) # => [A::B::C, A::B, A]

但是,我不知道如何在不同的上下文中调用Module.nesting。我尝试使用instance_exec,但这只会返回当前作用域中的嵌套。

module X
  def self.get_nesting(m)
    m.instance_exec { Module.nesting }
  end
end

X.get_nesting(A::B::C) # => [X]

我希望它返回[A::B::C, A::B, A]

是否有一种使用Module.nesting或其他方式以这种方式获取模块嵌套的方法?

1 个答案:

答案 0 :(得分:1)

尝试一下:

module A
  module B
    module C
      Module.nesting
    end
  end
end
  #=> [A::B::C, A::B, A]

module A::B
  module C
    Module.nesting
  end
end
  #=> [A::B::C, A::B] 

最后一个返回值中不包含A的原因是nesting取决于代码的结构(“词法”),而不取决于模块的父子关系。因此,我认为导致self等于给定模块(该方法的参数)然后执行Module.nesting的任何方法注定会失败。

但是,您可以执行以下操作。

def get_nesting(mod)
  a = mod.to_s.split('::')
  a.size.times.map { |i| Module.const_get(a[0..i].join('::')) }.reverse
end

get_nesting(A)       #=> [A] 
get_nesting(A::B)    #=> [A::B, A] 
get_nesting(A::B::C) #=> [A::B::C, A::B, A] 

get_nesting(A::B::C).map { |m| m.class } 
  #=> [Module, Module, Module]

考虑到这取决于Module#to_s,这将被归类为冲突。