Reputation:
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. ....."
Upvotes: 73
Views: 51745
Reputation: 7511
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
.
Upvotes: 3
Reputation: 191
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
Upvotes: 6
Reputation: 889
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
Upvotes: 1
Reputation: 3176
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
Upvotes: 0
Reputation: 3950
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.
Upvotes: 11
Reputation: 613
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".
Upvotes: 32
Reputation: 748
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
Upvotes: 0
Reputation: 2483
In just one line, I would write:
!!Module.const_get(nameofclass) rescue false
that will return true
only if the given nameofclass
belongs to a defined class.
Upvotes: 4
Reputation:
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
Upvotes: 5
Reputation: 11
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
Upvotes: 1
Reputation: 7099
defined?(DatabaseCleaner) # => nil
require 'database_cleaner'
defined?(DatabaseCleaner) # => constant
Upvotes: 10
Reputation: 3437
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.
Upvotes: 88
Reputation: 131112
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")
Upvotes: 55