Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

defined? for autoloadable classes

In a Rails app, I'd like to check if a constant is defined, autoloading it if necessary. The defined? operator returns false until the autoloading has happened.

defined? Foo # => false :(
Foo # => Foo
defined? Foo # => true

My current workaround is this:

begin
  Foo # try to autoload
  true
rescue NameError
  false
end

Is there a better way to check if a constant is defined, but also autoload it if necessary?


Rationale by request:

The Konacha JS testing framework for Rails should automatically pick up a fixtures Ruby file if it exists. The loading should happen with Rails's auto-loading mechanism, so it benefits from automatic reloading (with config.cache_classes = false).

like image 792
Jo Liss Avatar asked Sep 26 '26 14:09

Jo Liss


2 Answers

It sounds like you're trying to create a could_be_defined? method which attempts to auto-load and then returns true or false as you've indicated.

There's no way to know for sure if a class exists until you try to use it. This is one of the advantages of a highly dynamic language. The down-side is uncertainty.

Your method of force-loading and testing is the only way to know for sure. Some modules may not be declared via autoload but in fact generated on the fly as required. Trying to predict what may or may not exist will be unreliable at best.

like image 107
tadman Avatar answered Sep 28 '26 04:09

tadman


I had a similar problem, where I was loading inferred constants based on conventions. The problem I had was that any errors in the definition of those classes were being swallowed up.

I came up with this:

def const_presence(const_name)
  const_name.constantize
rescue NameError => e
  raise e unless e.message =~ /uninitialized constant #{const_name}/
end

This returns nil if the constant is not defined, or the constant if it is, but crucially allows any errors encountered while loading the constant to be raised.

like image 24
i2w Avatar answered Sep 28 '26 02:09

i2w



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!