在Ruby中如何通过类名获取一个类?

56

有一个包含类的模块和名称的字符串,例如:

"Admin::MetaDatasController"

如何获取实际类?

如果没有模块,以下代码可以正常工作:

Kernel.const_get("MetaDatasController")

但它与模块不兼容:

ruby-1.8.7-p174 > Kernel.const_get("Admin::MetaDatasController")
NameError: wrong constant name Admin::MetaDatasController
        from (irb):34:in `const_get'
        from (irb):34
ruby-1.8.7-p174 > 

Ruby中字符串转类名的方法是什么? - Andrew Grimm
4个回答

101

如果您想要一个简单的东西,只处理您的特殊情况,您可以编写

Object.const_get("Admin").const_get("MetaDatasController")

但是如果您需要更通用的方法,可以在::处将字符串拆分,并逐个解析名称:

def class_from_string(str)
  str.split('::').inject(Object) do |mod, class_name|
    mod.const_get(class_name)
  end
end

the_class = class_from_string("Admin::MetaDatasController")

在第一次迭代中,Object 被要求返回常量 Admin 并返回 Admin 模块或类,然后在第二次迭代中,该模块或类被要求返回常量 MetaDatasController,并返回该类。由于没有更多的组件,因此从该方法返回该类(如果有更多组件,则会迭代直到找到最后一个)。


2
你使用Kernel作为接收器的原因是什么?顶层常量定义在Object上而不是Kernel上。 - horseyguy
OP 用了它,而我没有停下来查找可能定义顶级常量的实际模块。我已经进行了更改。 - Theo

49

ActiveSupport提供了一个叫做constantize的方法,可以实现这一点。如果你正在使用Rails,根据你所提供的常量名称,我认为你已经加载了ActiveSupport。

require 'active_support/core_ext/string'

class Admin
  class MetaDatasController
  end
end

"Admin::MetaDatasController".constantize # => Admin::MetaDatasController

要查看该方法的实现,请查看https://github.com/rails/rails/blob/85c2141fe3d7edb636a0b5e1d203f05c70db39dc/activesupport/lib/active_support/inflector/methods.rb#L230-L253


2
在添加 GitHub 文件的链接时,按 y 键可以获取到该特定提交的直接链接。 - Ashitaka
1
你也可以使用 ActiveSupport::Inflector#constantize,它不需要你要求整个字符串核心扩展。 - hololeap

24

在Ruby 2.x中,你可以这样做:

Object.const_get('Admin::MetaDatasController')
=> Admin::MetaDatasController

2
请注意,如果您不知道常量是否存在,您可以使用Object.const_get(str) rescue nilObject.const_defined?(str) && Object.const_get(str) - Phrogz

1
我可能完全错了,但是 eval 不会返回类吗?
eval("Admin::MetaDatasController")

所以 eval("Admin::MetaDatasController").newAdmin::MetaDatasController.new 是一样的。


8
是的,但它带来了许多负面影响,特别是安全和速度方面。一个好的常规原则是避免轻率地使用 eval。此外,请注意向谁建议此方法,否则你可能会因与恶魔交往而被烧在火刑柱上(这往往是一个敏感话题)。 - Joshua Cheek
24
我明白了。"eval"是一个拼写错误,它应该是"evil"。 - potatopeelings

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接