Приведение между строкой и именем класса - PullRequest
1 голос
/ 19 сентября 2009

У меня есть строка, содержащая имя класса. Это, например, строка, содержащая «Статья». Эта строка возникла из параметров []. Что я должен сделать, чтобы работать с этой строкой, как если бы это было имя класса? Например, я хочу сделать:

Article.all

и т. Д.

Есть идеи?

Ответы [ 3 ]

4 голосов
/ 19 сентября 2009

Это решение лучше, чем eval , поскольку вы оцениваете хэш params , который может быть изменен пользователем и может содержать вредоносные действия. Как правило: Никогда не оценивайте пользовательский ввод напрямую, это большая дыра в безопасности.

# Monkey patch for String class
    class String
      def to_class
        klass = Kernel.const_get(self)
        klass.is_a?(Class) ? klass : nil
      rescue NameError
        nil
      end
    end

# Examples
"Fixnum".to_class #=> Fixnum
"Something".to_class #=> nil

Обновление - лучшая версия, которая работает с пространствами имен:

 # Monkey patch for String class
    class String
      def to_class
        chain = self.split "::"
        klass = Kernel
        chain.each do |klass_string|
          klass = klass.const_get klass_string
        end
        klass.is_a?(Class) ? klass : nil
      rescue NameError
        nil
      end
    end
3 голосов
/ 19 сентября 2009
class Abc
end #=> nil
klass = eval("Abc") #=> Abc
klass.new #=> #<Abc:0x37643e8>

Предполагается, что класс с указанным именем действительно существует ...

В ActiveSupport было String # constantize , которое делало то же самое, но я считаю, что после 2.1 оно устарело.

РЕДАКТИРОВАТЬ: это реализация constantize из ActiveSupport 2.1.2:

  def constantize(camel_cased_word)
    names = camel_cased_word.split('::')
    names.shift if names.empty? || names.first.empty?

    constant = Object
    names.each do |name|
      constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
    end
    constant
  end
0 голосов
/ 19 сентября 2009

Я не уверен, правильно ли я понимаю ваше намерение. Здесь я предполагаю, что all - это метод класса Article, а all возвращает массив статей.

class Article
    def self.all
       ["Peopleware" , "The Mythical Man-Month"]
    end

end

s = "Article"
all_of_article = []
eval("all_of_article = #{s + ".all"}")
puts all_of_article.inspect  # ["Peopleware", "The Mythical Man-Month"]
...