2009-09-19 9 views
1

J'ai une chaîne contenant un nom de classe. C'est, par exemple, une chaîne contenant "Article". Cette chaîne est venue des params []. Que dois-je faire pour travailler avec cette chaîne comme s'il s'agissait d'un nom de classe? Par exemple, je veux faire:Transmettre entre chaîne et nom de classe

Article.all 

et ainsi de suite.

Une idée?

Répondre

4

Cette solution est meilleure que eval que vous évaluez params hachage qui pourrait être manipulé par l'utilisateur et peut contenir des actions nuisibles. En règle générale: Ne jamais évaluer directement les entrées de l'utilisateur, c'est un gros trou de sécurité.

# 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 

Mise à jour - une meilleure version qui fonctionne avec les espaces de noms:

# 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

Cela ne fonctionnera pas avec les classes namespaced, comme 'MyModule :: MyClass'. Pour cela, vous devez diviser sur "::" puis, par exemple, utiliser injec avec const_get. – sepp2k

+0

Oui, il a besoin de plus de raffinement ... Merci! – khelll

+0

Bon point. J'ai ajouté le def de active_support, qui est beaucoup plus en accord avec votre (meilleure) suggestion. –

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

il est vraiment Suppose une classe avec le nom fourni ...

En ActiveSupport, il y avait String#constantize, qui fait la même chose, mais je crois qu'il est dépréciée après 2.1.

EDIT: ceci est la mise en œuvre de constantize de 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

Il est un peu dangereux d'utiliser eval pour params car il peut contenir un code malveillant. Je ne recommande pas cette solution – khelll

+0

Wow! Merci beaucoup! – gmile

+0

khell, des solutions sécurisées? – gmile

0

Je ne sais pas si je comprends votre intention correctement. Ici, je suppose all est une méthode de classe de Article et all retourner un tableau d'articles.

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"] 
Questions connexes