2009-09-19 1 views
1

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

Article.all 

и так далее.

Любая идея?

ответ

4

Это решение лучше, чем 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 

Update - это лучший вариант, который работает с пространствами имен:

# 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 
+2

Это не будет работать с классами с именами, такими как 'MyModule :: MyClass'. Для этого вам придется разделить на «::», а затем, например, использовать инъекцию с помощью const_get. – sepp2k

+0

Да, он нуждается в дальнейшей доработке ... Спасибо! – khelll

+0

Хорошая точка. Я добавил active_support def, который намного больше соответствует вашему (лучшему) предложению. –

3
class Abc 
end #=> nil 
klass = eval("Abc") #=> Abc 
klass.new #=> #<Abc:0x37643e8> 

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

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

EDIT: это реализация 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 
+1

Это немного опасно использовать Eval для Params причина может содержать вредоносный код. Я не рекомендую это решение – khelll

+0

Wow! Большое спасибо! – gmile

+0

khell, любые защищенные решения? – gmile

0

Я не уверен, понимаю ли я свое намерение правильно. Здесь я предполагаю, что 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"] 
Смежные вопросы