coderrr

March 11, 2008

Module.nesting and constant name resolution in Ruby

Filed under: ruby — Tags: — coderrr @ 10:31 am

Just finished the new O’Reilly Ruby book. It was mostly review but one thing I liked was their demonstration of constant name resolution. And I learned something new, Module.nesting!

Module.nesting returns the lexically enclosing classes/modules which are searched before Ruby walks up the class/module hierarchy to find the constant. Here’s an example of how Module.nesting doesn’t care about class hierarchy or namespaces, only lexical scope.

class A; end
class B; end
class C; end
class C::D; end
module E; end

class X < A; end
class Y < B; end
class Z < C; end

class ::X
  class ::Y
    class ::Z
      class ::C::D
        module ::M
          include E

          p Module.nesting
        end
      end
    end
  end
end

# => [M, C::D, Z, Y, X]

As you can see, the superclasses of X,Y,Z (A,B,C) are not present. The namespace of class D (C::) is not present either. Neither is the module E, which is included in M. Only the lexical nesting is returned.

The book has a good example which covers the entire lookup chain. Taken from The Ruby Programming Language:

module Kernel
  # Constants defined in Kernel
  A = B = C = D = E = F = "defined in kernel"
end

# Top-level or "global" constants defined in Object
A = B = C = D = E = "defined at toplevel"

class Super
  # Constants defined in a superclass
  A = B = C = D = "defined in superclass"
end

module Included
  # Constants defined in an included module
  A = B = C = "defined in included module"
end

module Enclosing
  # Constants defined in an enclosing module
  A = B = "defined in enclosing module"

  class Local < Super
    include Included

    # Locally defined constant
    A = "defined locally"

    # The list of modules searched, in the order searched
    # [Enclosing::Local, Enclosing, Included, Super, Object, Kernel]
    search = (Module.nesting + self.ancestors + Object.ancestors).uniq
    puts A  # Prints "defined locally"
    puts B  # Prints "defined in enclosing module"
    puts C  # Prints "defined in included module"
    puts D  # Prints "defined in superclass"
    puts E  # Prints "defined at toplevel"
    puts F  # Prints "defined in kernel"
  end
end

5 Comments »

  1. nice work, man

    Comment by Walterae — March 24, 2008 @ 8:45 am

  2. [...] resolve the constant X from the same location we find it in the lexically enclosing module M. See this post for more info on constant [...]

    Pingback by Overloading the parenthesis operator in Ruby « coderrr — November 30, 2008 @ 5:32 pm

  3. [...] we are in the lexical scope of class A, as we can see by the module nesting. (For more info on module nesting see this [...]

    Pingback by Fixing constant lookup in DSLs in Ruby 1.9 « coderrr — June 2, 2009 @ 8:16 pm

  4. [...] — coderrr @ 11:37 pm Wanting to see if it would be possible to somehow dynamically modify Module.nesting I hacked around looking for ways to do this for a long time in 1.8 to no avail. But it seems that [...]

    Pingback by Dynamically adding a constant nesting in Ruby 1.9 « coderrr — June 2, 2009 @ 8:19 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Customized Silver is the New Black Theme Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 28 other followers

%d bloggers like this: