How to check if a class is defined?

How to turn a string into a class name, but only if this class already exists?

If Amber is already a class, I can get from string to class via:

Object.const_get("Amber") 

or (in Rails)

 "Amber".constantize 

But any of them will not work with NameError: uninitialized constant Amber if Amber is not a class yet.

My first thought is to use the defined? method defined? , but it does not distinguish between existing classes and those that do not:

 >> defined?("Object".constantize) => "method" >> defined?("AClassNameThatCouldNotPossiblyExist".constantize) => "method" 

So, how do I check if a string names a class before I try to convert it? (Okay, what about the begin / rescue block to catch NameError errors? Too ugly? I agree ...)

+58
ruby class ruby-on-rails-3 defined
Apr 22 2018-11-18T00:
source share
6 answers

What about const_defined? ?

Remember that Rails has autoload in development mode, so when testing this can be difficult:

 >> Object.const_defined?('Account') => false >> Account => Account(id: integer, username: string, google_api_key: string, created_at: datetime, updated_at: datetime, is_active: boolean, randomize_search_results: boolean, contact_url: string, hide_featured_results: boolean, paginate_search_results: boolean) >> Object.const_defined?('Account') => true 
+103
Apr 22 2018-11-18T00:
source share

In rails, it is very simple:

 amber = "Amber".constantize rescue nil if amber # nil result in false # your code here end 
+11
Sep 30 '15 at 15:23
source share

Inspired by @ctcherry's answer above, here is the "send class safe method", where class_name is a string. If class_name does not name the class, it returns nil.

 def class_send(class_name, method, *args) Object.const_defined?(class_name) ? Object.const_get(class_name).send(method, *args) : nil end 

An even safer version that calls method only if class_name answers it:

 def class_send(class_name, method, *args) return nil unless Object.const_defined?(class_name) c = Object.const_get(class_name) c.respond_to?(method) ? c.send(method, *args) : nil end 
+10
Apr 22 2018-11-18T00:
source share

It looks like all the answers using the Object.const_defined? method Object.const_defined? wrong. If the class in question is not yet loaded due to lazy loading, this statement will fail. The only way to achieve this permanently:

  validate :adapter_exists def adapter_exists # cannot use const_defined because of lazy loading it seems Object.const_get("Irs::#{adapter_name}") rescue NameError => e errors.add(:adapter_name, 'does not have an IrsAdapter') end 
+2
Mar 21 '16 at 11:33
source share

Another approach if you want to get a class. Will return nil if the class is not defined, so you do not need to catch an exception.

 class String def to_class(class_name) begin class_name = class_name.classify (optional bonus feature if using Rails) Object.const_get(class_name) rescue # swallow as we want to return nil end end end > 'Article'.to_class class Article > 'NoSuchThing'.to_class nil # use it to check if defined > puts 'Hello yes this is class' if 'Article'.to_class Hello yes this is class 
+1
Sep 03 '15 at 18:00
source share

I created a validator to check if a string is a valid class name (or a list of valid class names separated by commas):

 class ClassValidator < ActiveModel::EachValidator def validate_each(record,attribute,value) unless value.split(',').map { |s| s.strip.constantize.is_a?(Class) rescue false }.all? record.errors.add attribute, 'must be a valid Ruby class name (comma-separated list allowed)' end end end 
0
Aug 22 '14 at 18:14
source share



All Articles