如何从对象动态获取嵌套模块?

时间:2009-10-21 02:46:52

标签: ruby metaprogramming

下式给出:

module A
  class B
  end
end

b = A::B.new

我们希望能够将模块嵌套为数组。如果提前知道了这个类,就可以这样做。例如:

module A
  class B
    def get_nesting
      Module.nesting  # => [A::B, A]
    end
  end
end

但是,如何为任意对象执行此操作,以便我们可以执行以下操作:

module Nester
  def get_nesting
    Module.nesting
  end
end

b.get_nesting

如果我们尝试上述操作,我们会得到一个空数组。

2 个答案:

答案 0 :(得分:1)

你在找这样的东西吗?

module D
  A = 10
  class E
    module F
    end
  end
end

def all_nestings(top)
  result = []
  workspace = [top]
  while !workspace.empty?
    item = workspace.shift
    result << item
    item.constants.each do |const|
      const = item.const_get(const)
      next unless const.class == Class || const.class == Module
      workspace.push const
    end
  end
  result
end

puts all_nestings(D).inspect # => [D, D::E, D::E::F]

答案 1 :(得分:0)

我刚刚敲了Class.hierarchy,从Object开始,并将每个课程步骤一直返回到相关课程。

class Class
  def hierarchy
    name.split('::').inject([Object]) {|hierarchy,name|
      hierarchy << hierarchy.last.const_get(name)
    }
  end
end

鉴于此类定义:

module A
  module B
    module C
      class D
        def self.hello
          "hello world!"
        end
      end
    end
  end
end

它返回:

A::B::C::D.hierarchy # => [Object, A, A::B, A::B::C, A::B::C::D]

注意,这些是模块和类本身,而不仅仅是字符串。例如,

A::B::C::D.hierarchy.last.hello # => "hello world!"

真实世界类的一个例子:

require 'net/smtp'
Net::SMTP.hierarchy # => [Object, Net, Net::SMTP]