我如何检查一个类是否被定义?
如何将string转换为类名,但只有当该类已经存在?
如果琥珀已经是一个类,我可以通过以下方式从一个string中获得:
Object.const_get("Amber")
或(在Rails中)
"Amber".constantize
但是其中的任何一个都会因为NameError: uninitialized constant Amber
而失败NameError: uninitialized constant Amber
如果琥珀色还不是一个类,那么就是NameError: uninitialized constant Amber
。
我的第一个想法是使用defined?
方法,但它不区分已经存在的类和不存在的类:
>> defined?("Object".constantize) => "method" >> defined?("AClassNameThatCouldNotPossiblyExist".constantize) => "method"
那么在我尝试转换它之前,如何testing一个string是否可以命名一个类呢? (好吧,如何begin
/ rescue
块赶上NameError错误?太丑了?我同意…)
怎么样const_defined?
?
在Rails中记住,在开发模式下会自动加载,所以在testing时可能会非常棘手:
>> Object.const_defined?('Account') => false >> Account => Account(id: integer, username: string, google_api_key: string, created_at: datetime, updated_at: datetime, is_active: boolean, randomize_search_results: boolean, contact_url: string, hide_featured_results: boolean, paginate_search_results: boolean) >> Object.const_defined?('Account') => true
在铁轨中,这非常简单:
amber = "Amber".constantize rescue nil if amber # nil result in false # your code here end
受上述@ ctcherry的回应的启发,这里有一个“安全类方法send”,其中class_name
是一个string。 如果class_name
没有命名一个类,它返回nil。
def class_send(class_name, method, *args) Object.const_defined?(class_name) ? Object.const_get(class_name).send(method, *args) : nil end
一个更安全的版本只有在class_name
响应时才会调用method
:
def class_send(class_name, method, *args) return nil unless Object.const_defined?(class_name) c = Object.const_get(class_name) c.respond_to?(method) ? c.send(method, *args) : nil end
它会出现所有的答案使用Object.const_defined?
方法有缺陷。 如果有问题的类尚未加载,由于延迟加载,则断言将失败。 实现这一目标的唯一方法就是这样:
validate :adapter_exists def adapter_exists # cannot use const_defined because of lazy loading it seems Object.const_get("Irs::#{adapter_name}") rescue NameError => e errors.add(:adapter_name, 'does not have an IrsAdapter') end
另一种方法,如果你想获得课程。 如果类没有定义,将会返回nil,所以你不必捕获exception。
class String def to_class(class_name) begin class_name = class_name.classify (optional bonus feature if using Rails) Object.const_get(class_name) rescue # swallow as we want to return nil end end end > 'Article'.to_class class Article > 'NoSuchThing'.to_class nil # use it to check if defined > puts 'Hello yes this is class' if 'Article'.to_class Hello yes this is class
我创build了一个validation器来testing一个string是否是一个有效的类名(或逗号分隔的有效类名):
class ClassValidator < ActiveModel::EachValidator def validate_each(record,attribute,value) unless value.split(',').map { |s| s.strip.constantize.is_a?(Class) rescue false }.all? record.errors.add attribute, 'must be a valid Ruby class name (comma-separated list allowed)' end end end