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
nice work, man
Comment by Walterae — March 24, 2008 @ 8:45 am
[...] 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
[...] 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
[...] — 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
[...] better read: http://coderrr.wordpress.com/2008/03/11/constant-name-resolution-in-ruby/ [...]
Pingback by determine if a constant is defined | myrubylearning — April 2, 2013 @ 11:23 pm