37

Ruby 中有没有办法将符号或字符串转换为同名的类?

例如,如果我有一个类,如

class Bob
  def talk
     puts "Hi, I'm bob"
  end
end

我在代码中其他地方的方法传递了一个符号:bob,我可以以某种方式将它变成类 Bob 吗?也许像

b = :Bob.new
b.talk

或者有没有办法做类似的事情?

4

7 回答 7

55

有很多方法可以做到这一点。您缺乏上下文使得无法选择“最佳”方式。这里有几个。

Kernel.const_get(:Bob)

eval(:Bob.to_s)

Kernel.const_get(:bob.to_s.capitalize)
于 2009-08-05T21:30:21.363 回答
44

导轨

仅用于 Rails。

用一个字符串:

"Module".constantize #=> Module
"Class".constantize #=> Class

带符号:

:module.to_s.classify.constantize #=> Module
:open_struct.to_s.classify.constantize #=> OpenStruct

如果您正在处理多字符号,那么您需要添加#classify到链中以正确处理常量所有部分的大写。

http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-constantize

于 2009-08-05T20:53:38.830 回答
10

如果你想把 :foo_bar 变成 FooBar,我见过的解决方案都没有。如果这就是你要找的东西:

:foo_bar.to_s.split("_").collect(&:capitalize).join.constantize
=> FooBar

希望对某人有所帮助。

于 2010-11-27T05:03:29.567 回答
5

NameSpace.const_get(classname)将返回类对象(假设 classname 包含类的名称 - 如果它包含不是类的常量的名称,它将返回该常量的值)。顶层命名空间是 Object,所以你可以这样做Object.const_get(:Bob).new

于 2009-08-05T20:39:39.267 回答
3
class Bob
end

def create(name)
  return eval("#{name}.new")
end

b = create(:Bob)
puts b.class
于 2009-08-05T20:42:57.900 回答
2

这是我在寻找包含模块/命名空间支持的类似内容时想到的:

['foo', 'bar'].inject {|r,e| "#{r.classify}::#{e.classify}"}.constantize

生产

=> Foo::Bar

然而,这需要 Rails,当然它只适用于数组包含多个元素的情况。

这看起来很简单,所以我确定我错过了一些东西,有人愿意告诉我为什么这不是一个好方法吗?

谢谢!

于 2012-08-15T17:37:14.983 回答
0

就我而言,下面的两个示例都有效,但您也不必忘记命名空间:

  Object.const_get("ModuleName::#{class_model_name}")

或者

  Kernel.const_get("ModuleName::#{class_model_name}").
于 2016-11-11T09:01:22.407 回答