Получить класс по имени в Ruby? - программирование
Подтвердить что ты не робот

Получить класс по имени в 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 > 
4b9b3361

Ответ 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