Получить класс по имени в Ruby? - PullRequest
49 голосов
/ 02 июля 2010

Наличие строки с модулем и именем класса, например:

"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 > 

Ответы [ 4 ]

90 голосов
/ 02 июля 2010

Если вы хотите что-то простое, которое обрабатывает только ваш особый случай, вы можете написать

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 и возвращает этот класс.Поскольку больше нет компонентов, этот класс возвращается из метода (если бы было больше компонентов, он итерировал бы, пока не нашел последний).

44 голосов
/ 02 июля 2010

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

21 голосов
/ 26 июня 2014

В Ruby 2.x вы можете просто сделать это:

Object.const_get('Admin::MetaDatasController')
=> Admin::MetaDatasController
1 голос
/ 02 июля 2010

Я мог бы быть не в своей тарелке, но разве не смог бы вернуть класс?

eval("Admin::MetaDatasController")

так что eval("Admin::MetaDatasController").new будет таким же, как Admin::MetaDatasController.new

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...