views:

118

answers:

2

given:

module A
  class B
  end
end

b = A::B.new

we want to be able to get the module nesting as an array. This can be done if the class is known in advance. eg:

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

But, how to do it for an arbitrary object, so that we could do something like this:

module Nester
  def get_nesting
    Module.nesting
  end
end

b.get_nesting

If we try the above, we get an empty array.

A: 

Are you looking for something like this?

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]
sri
Nice. Almost works... how would it work for an object where you didn't know the modules, etc?Would it be a matter of saying:e = D::E.newall_nestings(e.class).inspect?
suranyami
A: 

I just knocked up Class.hierarchy, which starts at Object and returns each class step all the way down to the class in question.

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

Given this class definition:

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

It returns this:

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

Note, those are the modules and classes themselves, not just strings. For example,

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

An example with a real-world class:

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