Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constantize raises Uninitialized Constant Error

I'm working on this pretty thorny problem and decided I might be able to dynamically create a class that inherits from StandardError by doing this:

something = "JustForBelow"
error_class = "#{something}Error".constantize
error_class = StandardError.new

But I'm getting a really weird error (in my opinion), which is:

Uninitialized constant JustForBelowError

Aren't I initializing it right there?

(Essentially) same error comes up when I try this:

StandardError.const_get "#{something}Error"
# => NameError: uninitialized constant StandardError::JustForBelowClass

This feels really weird, because a) these are super random names; there aren't any conflicts, and b) I'm pretty sure I've used constantize like in the first example before. Any ideas what's going wrong?

like image 659
Sasha Avatar asked Dec 19 '13 17:12

Sasha


1 Answers

ActiveSupport's constantize method just looks up a constant. It's a fancier version of const_get that does nice things like traverse a nested module structure.

To create a new error, you'll want to do something like this:

2.0.0-p247 :013 > Object.const_set("MyNewError", Class.new(StandardError))
 => MyNewError
2.0.0-p247 :014 > MyNewError.ancestors
 => [MyNewError, StandardError, Exception, Object, Kernel, BasicObject]

At which point, you can do "MyNewError".constantize and get back that new class object.

Edit Also note that const_get in your second example error is looking inside the namespace it was called on. In that case, inside of StandardError's scope.

For instance, if you have a class structure like:

module A
  class B
    CONSTANT = "hello world"
  end
end

Then you could get at that with "A::B::CONSTANT".constantize, or by doing Object.const_get("A").const_get("B").const_get("CONSTANT"). Same thing, just ActiveSupport made is smoother to do.

like image 73
cschneid Avatar answered Sep 28 '22 18:09

cschneid