如何检查Ruby中是否已存在类
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何检查Ruby中是否已存在类相关的知识,希望对你有一定的参考价值。
如何检查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. ....."
您可以使用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
;我怀疑这将用于任何严肃的应用,但值得了解安全风险。
我用它来查看是否在运行时加载了一个类:
def class_exists?(class_name)
ObjectSpace.each_object(Class) {|c| return true if c.to_s == class_name }
false
end
我假设如果没有加载类,你会采取一些行动。
如果你的意思是要求一个文件,为什么不检查require
的输出?
require 'already/loaded'
=> false
如果你想要包装的东西,finishing_moves
宝石添加了class_exists?
方法。
class_exists? :Symbol
# => true
class_exists? :Rails
# => true in a Rails app
class_exists? :NonexistentClass
# => false
上面的答案都没有对我有用,可能是因为我的代码存在于子模块的范围内。
我决定在我的模块中创建一个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
也许你可以用定义来做到这一点?
例如:
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")
如果通过调用Module.const_get
查看某个范围内的常量,则可以避免从Module#const_defined?("SomeClass")
中解除NameError。
调用它的常见范围是Object,例如:Object.const_defined?("User")
。
见:“Module”。
defined?(DatabaseCleaner) # => nil
require 'database_cleaner'
defined?(DatabaseCleaner) # => constant
类名是常量。您可以使用defined?
方法查看是否已定义常量。
defined?(String) # => "constant"
defined?(Undefined) # => nil
如果您有兴趣,可以阅读更多关于defined?
的工作原理。
这是一个更简洁的版本:
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
Kernel.const_defined?("Fixnum") # => true
这是我有时会采取的措施来解决这个问题。您可以将以下方法添加到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
在一行中,我会写:
!!Module.const_get(nameofclass) rescue false
如果给定的true
属于一个定义的类,它将返回nameofclass
only。
以上是关于如何检查Ruby中是否已存在类的主要内容,如果未能解决你的问题,请参考以下文章