Рубиновый символ в классе

Есть ли способ в Ruby взять символ или строку и превратить их в одноименный класс?

Например, если у меня есть такой класс, как

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

А методу, который у меня есть где-то еще в коде, передается символ :bob, могу ли я каким-то образом превратить его в класс Bob? Может быть, что-то вроде

b = :Bob.new
b.talk

Или есть способ сделать что-то подобное?


person intargc    schedule 05.08.2009    source источник


Ответы (6)


Есть много способов сделать это. Ваше отсутствие контекста делает невозможным выбор «лучшего» пути. Вот несколько вариантов.

Kernel.const_get(:Bob)

eval(:Bob.to_s)

Kernel.const_get(:bob.to_s.capitalize)
person August Lilleaas    schedule 05.08.2009
comment
Ну, к счастью, я не просил лучший способ, а просто способ... ;) - person intargc; 06.08.2009
comment
на всякий случай, если Bob определено в модуле People и вы это знаете, вы можете People.const_get(:Bob) - person phil pirozhkov; 18.10.2012

Рельсы

Только для использования с 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

person Dan Frade    schedule 05.08.2009
comment
Извините, я, вероятно, должен добавить, что это только для Rails. - person Dan Frade; 06.08.2009
comment
Если вы используете Rails, это, вероятно, лучшее решение. - person superluminary; 11.06.2013
comment
Вопрос конкретно касается символов, а константизация не существует в классе Symbol в Rails. Ответ должен быть :Module.to_s.constantize. - person tjbp; 10.08.2016

Ни одно из решений, которые я видел, не работает, если вы хотите превратить :foo_bar в FooBar. Если это то, что вы ищете:

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

надеюсь, что это поможет кому-то.

person Lance Olsen    schedule 27.11.2010
comment
Вот для чего нужен Camelize: :foo_bar.to_s.camelize - person Dave Sims; 18.07.2012
comment
@DaveSims camelize является расширением ActiveRecord: api.rubyonrails.org/ classs/ActiveSupport/, хотя constantize тоже. - person Ross Allen; 30.07.2012
comment
Да, как и Дэн Фрейд, я должен был упомянуть об этом. :) - person Dave Sims; 30.07.2012

NameSpace.const_get(classname) вернет объект класса (при условии, что имя класса содержит имя класса — если оно содержит имя константы, которая не является классом, оно вернет значение этой константы). Пространство имен верхнего уровня — Object, поэтому вы можете сделать Object.const_get(:Bob).new

person sepp2k    schedule 05.08.2009

Вот что я придумал, когда искал что-то похожее с поддержкой модуля/пространства имен:

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

Производит

=> Foo::Bar

Однако для этого требуется Rails, и, конечно, это работает только там, где массив содержит более одного элемента.

Это кажется довольно простым, поэтому я уверен, что что-то упускаю, может ли кто-нибудь посоветовать, почему это не будет хорошим подходом?

Спасибо!

person Joe    schedule 15.08.2012
comment
Вы задаете вопрос внутри ответа? Позор! ;) - person JustinStolle; 21.08.2012
comment
@JustinStolle, я не думаю, что это новый вопрос, больше рекомендаций относительно исходного вопроса? :) - person Joe; 19.09.2012

в моем случае работали оба приведенных ниже примера, но вы также не должны забывать о пространстве имен:

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

or

  Kernel.const_get("ModuleName::#{class_model_name}").
person FredyK    schedule 11.11.2016