72

How do I check if a class already exists in Ruby?

My code is:

puts "enter the name of the Class to see if it exists"   
nameofclass=gets.chomp  
eval (" #{nameofclass}......  Not sure what to write here")

I was thinking of using:

eval "#{nameofclass}ancestors.     ....."
the Tin Man
  • 158,662
  • 42
  • 215
  • 303

14 Answers14

88

You can use Module.const_get to get the constant referred to by the string. It will return the constant (generally classes are referenced by constants). You can then check to see if the constant is a class.

I would do something along these lines:

def class_exists?(class_name)
  klass = Module.const_get(class_name)
  return klass.is_a?(Class)
rescue NameError
  return false
end

Also, if possible I would always avoid using eval when accepting user input; I doubt this is going to be used for any serious application, but worth being aware of the security risks.

Olly
  • 3,409
  • 3
  • 24
  • 28
  • 2
    For me, it was good if the named thing was a Module as well. Used `klass.is_a?(Class) || klass.is_a?(Module)`. A namespace qualified name worked with this method. For example `class_exists?('Delayed::Worker')` Very nice. – Douglas Lovell May 24 '15 at 21:48
54

perhaps you can do it with defined?

eg:

if defined?(MyClassName) == 'constant' && MyClassName.class == Class  
   puts "its a class" 
end

Note: the Class check is required, for example:

Hello = 1 
puts defined?(Hello) == 'constant' # returns true

To answer the original question:

puts "enter the name of the Class to see if it exists"
nameofclass=gets.chomp
eval("defined?(#{nameofclass}) == 'constant' and #{nameofclass}.class == Class")
Sam Saffron
  • 128,308
  • 78
  • 326
  • 506
  • This is the best way to do it. Lot of cases in gems you need to do things like this as well. defined? ::Rails – User128848244 Oct 22 '14 at 13:24
  • 1
    `defined?(MyClassName) == 'constant' && MyClassName.is_a?(Class)` looks more intuitive. – Jignesh Gohel Mar 08 '16 at 06:40
  • Why `defined? Object.const_get("array".capitalize)` is returning "method", while i run `defined? Array` return "constant" ? – kamal Mar 13 '16 at 13:18
  • Just a warning from some recent problems with this, defined? will throw an error if MyClassName does not exist. At least in current versions of Ruby. For more info you can check out the docs: (http://ruby-doc.org/docs/keywords/1.9/Object.html#method-i-defined-3F) – srussking Feb 19 '19 at 20:23
  • ``` irb(main):003:0> defined? TestingTesting::Testing => nil irb(main):004:0> RUBY_VERSION => "2.6.1" ``` – Sam Saffron Feb 25 '19 at 03:35
  • Note, it may return nil when autoload not yet loaded class in Rails – x'ES Dec 15 '20 at 16:06
32

You can avoid having to rescue the NameError from Module.const_get if you are looking the constant within a certain scope by calling Module#const_defined?("SomeClass").

A common scope to call this would be Object, eg: Object.const_defined?("User").

See: "Module".

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
stcorbett
  • 613
  • 6
  • 5
  • 13
    this will only return true if the class has been loaded. >> Object.const_defined?("MyClass") # false >> MyClass # MyClass >> Object.const_defined?("MyClass") # true this is at least the case in a Rails console, YMMV. – carpeliam Nov 30 '11 at 23:56
11

Class names are constants. You can use the defined? method to see if a constant has been defined.

defined?(String)    # => "constant"
defined?(Undefined) # => nil

You can read more about how defined? works if you're interested.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Tate Johnson
  • 3,910
  • 1
  • 23
  • 21
10
defined?(DatabaseCleaner) # => nil
require 'database_cleaner'
defined?(DatabaseCleaner) # => constant
Rob
  • 7,039
  • 4
  • 44
  • 75
8
Kernel.const_defined?("Fixnum") # => true
random-forest-cat
  • 33,652
  • 11
  • 120
  • 99
  • 3
    This will only return true only if the class has been loaded ```$ rails c test Loading test environment (Rails 4.2.5.1) 2.2.1 :001 > Kernel.const_defined?('ApiProvider') => false 2.2.1 :002 > ApiProvider => ApiProvider 2.2.1 :003 > Kernel.const_defined?('ApiProvider') => true ``` – Jignesh Gohel Mar 08 '16 at 07:01
6

Here's a more succinct version:

def class_exists?(class_name)
  eval("defined?(#{class_name}) && #{class_name}.is_a?(Class)") == true
end

class_name = "Blorp"
class_exists?(class_name)
=> false

class_name = "String"
class_exists?(class_name)
=> true
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
6

Here's something I sometimes do to tackle this very issue. You can add the following methods to the String class like so:

class String
    def to_class
        my_const = Kernel.const_get(self)
        my_const.is_a?(Class) ? my_const : nil
    rescue NameError 
        nil
    end

    def is_a_defined_class?
        true if self.to_class
    rescue NameError
        false
    end
end

Then:

'String'.to_class
=> String
'unicorn'.to_class
=> nil
'puppy'.is_a_defined_class?
=> false
'Fixnum'.is_a_defined_class?
=> true
Afz902k
  • 191
  • 1
  • 4
  • This is a really cool way of going about this, especially if you're dealing with user input in the form of strings (ex Rails). Thanks for this cool idea! – thegravian May 03 '12 at 17:29
4

In just one line, I would write:

!!Module.const_get(nameofclass) rescue false

that will return trueonly if the given nameofclass belongs to a defined class.

Andrea Salicetti
  • 2,423
  • 24
  • 37
  • That will return true for any constant in Module (which may be all, I don't know), not just for classes. `Bla="some string" ; !!Module.const_get(:Bla) rescue false` returns true. – nash Jan 17 '14 at 16:09
2

If it is a simple standalone class e.g.

class Foo
end

then we can use Object.const_defined?("Foo"). And, if your class is inside any module e.g.

module Bar
  class Foo
  end
end

then we can use Module.const_get("Bar::Foo").

Please note that if Module.const_get('Bar::Foo') doesn't find the class then it will raise exception. While, Object.const_defined?('Foo') will return true or false.

Neeraj Kumar
  • 6,045
  • 2
  • 31
  • 23
1

I used this to see if a class was loaded at runtime:

def class_exists?(class_name)
  ObjectSpace.each_object(Class) {|c| return true if c.to_s == class_name }
  false
end
Hugh
  • 11
  • 1
  • I used this method because in my scenario I didn't know if the constant had been previously created, and it was important that it only compared against Class objects. Being able to just pass in a string was perfect. Thanks for sharing you helped me out heaps, very much appreciated. – Dom Jan 15 '15 at 22:03
1

None of the answers above worked for me, maybe because my code lives in the scope of a submodule.

I settled on creating a class_exists? method in my module, using code found in Fred Wilmore's reply to "How do I check if a class is defined?" and finally stopped cursing.

def class_exists?(name)
   name.constantize.is_a?(Class) rescue false # rubocop:disable Style/RescueModifier
end

Full code, for the curious:

module Some
  module Thing
    def self.build(object)
      name = "Some::Thing::#{object.class.name}"
      class_exists?(name) ? name.constantize.new(object) : Base.new(object)
    end

    def self.class_exists?(name)
      name.constantize.is_a?(Class) rescue false # rubocop:disable Style/RescueModifier
    end

    private_class_method :class_exists?
  end
end

I use it as a factory which builds objects depending on the class of the object passed as argument:

Some::Thing.build(something)
=> # A Some::Thing::Base object
Some::Thing.build(something_else)
=> # Another object, which inherits from Some::Thing::Base
Goulven
  • 777
  • 9
  • 20
0

If you want something packaged, the finishing_moves gem adds a class_exists? method.

class_exists? :Symbol
# => true
class_exists? :Rails
# => true in a Rails app
class_exists? :NonexistentClass
# => false
Frank Koehl
  • 3,104
  • 2
  • 29
  • 37
0

I assume you'll take some action if the class is not loaded.

If you mean to require a file, why not just check the output of require?

require 'already/loaded'  
=> false
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
stackdump
  • 718
  • 6
  • 9