mudasobwa mudasobwa - 8 months ago 37
Ruby Question

Is it possible to narrow ruby constant lookup

I have a module, that contains class named

(amongst others.) I need to lookup the class by name and gracefully fall back if there is no such a class.

module Mod1
module String
Mod1.const_get 'String'
#⇒ Mod1::String
Kernel.const_get '::Mod1::String'
#⇒ Mod1::String

so far, so good. I am expectedly receiving a
when I try to lookup non-existing class, which is fine. The problem is that if there is a class with the given name existing in global namespace, it is being returned:

Mod1.const_get 'Fixnum'
#⇒ Fixnum < Integer
Kernel.const_get '::Mod1::Fixnum'
#⇒ Fixnum < Integer

I understand the reasons, but my question would be: is there an out-of-the-box method to lookup a constant in the given namespace only?

Now I check the result with


but this is definitely not the fanciest way to narrow a lookup.


The answer is:

Mod1.const_get 'Fixnum', false

Here's the doc:

 *  call-seq:
 *     mod.const_get(sym, inherit=true)    -> obj
 *     mod.const_get(str, inherit=true)    -> obj
 *  Checks for a constant with the given name in <i>mod</i>.
 *  If +inherit+ is set, the lookup will also search
 *  the ancestors (and +Object+ if <i>mod</i> is a +Module+).
 *  The value of the constant is returned if a definition is found,
 *  otherwise a +NameError+ is raised.
 *     Math.const_get(:PI)   #=> 3.14159265358979
 *  This method will recursively look up constant names if a namespaced
 *  class name is provided.  For example:
 *     module Foo; class Bar; end end
 *     Object.const_get 'Foo::Bar'
 *  The +inherit+ flag is respected on each lookup.  For example:
 *     module Foo
 *       class Bar
 *         VAL = 10
 *       end
 *       class Baz < Bar; end
 *     end
 *     Object.const_get 'Foo::Baz::VAL'         # => 10
 *     Object.const_get 'Foo::Baz::VAL', false  # => NameError
 *  If the argument is not a valid constant name a +NameError+ will be
 *  raised with a warning "wrong constant name".
 *  Object.const_get 'foobar' #=> NameError: wrong constant name foobar