Получить класс по имени в Ruby?
Наличие строки с модулем и именем класса, например:
"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 >
Ответы
Ответ 1
Если вам нужно что-то простое, которое обрабатывает только ваш специальный случай, вы можете написать
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
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
Ответ 3
В Ruby 2.x вы можете просто сделать это:
Object.const_get('Admin::MetaDatasController')
=> Admin::MetaDatasController
Ответ 4
Я мог бы быть вне базы, но не мог бы вернуть класс?
eval("Admin::MetaDatasController")
поэтому eval("Admin::MetaDatasController").new
будет таким же, как Admin::MetaDatasController.new