如何检查Ruby中是否已存在类

问题描述 投票:59回答:13

如何检查Ruby中是否已存在类?

我的代码是:

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

我在考虑使用:

eval "#{nameofclass}ancestors.     ....."
ruby class
13个回答
71
投票

您可以使用Module.const_get来获取字符串引用的常量。它将返回常量(通常类由常量引用)。然后,您可以检查常量是否为类。

我会沿着这些方向做点什么:

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

另外,如果可能的话,我总是避免在接受用户输入时使用eval;我怀疑这将用于任何严肃的应用,但值得了解安全风险。


1
投票

我用它来查看是否在运行时加载了一个类:

def class_exists?(class_name)
  ObjectSpace.each_object(Class) {|c| return true if c.to_s == class_name }
  false
end

0
投票

我假设如果没有加载类,你会采取一些行动。

如果你的意思是要求一个文件,为什么不检查require的输出?

require 'already/loaded'  
=> false

0
投票

如果你想要包装的东西,finishing_moves宝石添加了class_exists?方法。

class_exists? :Symbol
# => true
class_exists? :Rails
# => true in a Rails app
class_exists? :NonexistentClass
# => false

0
投票

上面的答案都没有对我有用,可能是因为我的代码存在于子模块的范围内。

我决定在我的模块中创建一个class_exists?方法,使用Fred Wilmore's reply to "How do I check if a class is defined?"中的代码并最终停止诅咒。

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

完整代码,对于好奇:

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

我使用它作为工厂,根据作为参数传递的对象的类来构建对象:

Some::Thing.build(something)
=> # A Some::Thing::Base object
Some::Thing.build(something_else)
=> # Another object, which inherits from Some::Thing::Base

45
投票

也许你可以用定义来做到这一点?

例如:

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

注意:需要进行类检查,例如:

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

回答原来的问题:

puts "enter the name of the Class to see if it exists"
nameofclass=gets.chomp
eval("defined?(#{nameofclass}) == 'constant' and #{nameofclass}.class == Class")

25
投票

如果通过调用Module.const_get查看某个范围内的常量,则可以避免从Module#const_defined?("SomeClass")中解除NameError。

调用它的常见范围是Object,例如:Object.const_defined?("User")

见:“Module”。


11
投票
defined?(DatabaseCleaner) # => nil
require 'database_cleaner'
defined?(DatabaseCleaner) # => constant

8
投票

类名是常量。您可以使用defined?方法查看是否已定义常量。

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

如果您有兴趣,可以阅读更多关于defined?的工作原理。


6
投票

这是一个更简洁的版本:

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

6
投票
Kernel.const_defined?("Fixnum") # => true

4
投票

这是我有时会采取的措施来解决这个问题。您可以将以下方法添加到String类中,如下所示:

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

然后:

'String'.to_class
=> String
'unicorn'.to_class
=> nil
'puppy'.is_a_defined_class?
=> false
'Fixnum'.is_a_defined_class?
=> true

2
投票

在一行中,我会写:

!!Module.const_get(nameofclass) rescue false

如果给定的true属于一个定义的类,它将返回nameofclassonly。

© www.soinside.com 2019 - 2024. All rights reserved.