How to check if a class already exists in Ruby

Viewed 47531

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.     ....."
14 Answers

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.

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")

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.

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

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.

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
Related