Ответ 1
Есть много способов сделать это. Отсутствие контекста не позволяет выбрать "лучший" способ. Вот несколько из них.
Kernel.const_get(:Bob)
eval(:Bob.to_s)
Kernel.const_get(:bob.to_s.capitalize)
Есть ли способ в Ruby взять символ или строку и превратить ее в класс с тем же именем?
Например, если у меня есть класс, например
class Bob
def talk
puts "Hi, I'm bob"
end
end
И метод, который у меня есть где-то еще в коде, передается символ: bob, могу ли я каким-то образом превратить это в класс Bob? Может быть, что-то вроде
b = :Bob.new
b.talk
Или есть способ сделать что-то подобное этому?
Есть много способов сделать это. Отсутствие контекста не позволяет выбрать "лучший" способ. Вот несколько из них.
Kernel.const_get(:Bob)
eval(:Bob.to_s)
Kernel.const_get(:bob.to_s.capitalize)
Только для 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
Ни одно из решений, которые я видел, не работает, если вы хотите повернуть: foo_bar в FooBar. Если это то, что вы ищете:
.: foo_bar.to_s.split( "_" ) собрать (&: капитализировать).join.constantize
= > FooBar
Надеюсь, что это поможет кому-то.
NameSpace.const_get(classname)
вернет объект класса (предполагая, что имя класса содержит имя класса - если он содержит имя константы, которая не является классом, она вернет значение этой константы). Пространство имен toplevel - это Object, поэтому вы можете сделать Object.const_get(:Bob).new
class Bob
end
def create(name)
return eval("#{name}.new")
end
b = create(:Bob)
puts b.class
Вот что я придумал, ища что-то подобное, включая поддержку модулей/пространств имен:
['foo', 'bar'].inject {|r,e| "#{r.classify}::#{e.classify}"}.constantize
Выдает
=> Foo::Bar
Однако для этого требуется Rails и, конечно, он работает только там, где массив имеет более одного элемента.
Это кажется довольно простым, поэтому я уверен, что мне что-то не хватает, кто-нибудь захочет сообщить, почему это не будет хорошим подходом?
Спасибо!
в моем случае, оба примера ниже работали, но вы также не должны забывать пространство имен:
Object.const_get("ModuleName::#{class_model_name}")
или
Kernel.const_get("ModuleName::#{class_model_name}").