【发布时间】:2010-11-29 17:11:42
【问题描述】:
我有一个字符串,其中包含一个类名。例如,它是一个包含“Article”的字符串。该字符串来自 params[]。我应该如何处理这个字符串,就好像它是一个类名一样?例如,我想做:
Article.all
等等。
有什么想法吗?
【问题讨论】:
标签: ruby string class constants
我有一个字符串,其中包含一个类名。例如,它是一个包含“Article”的字符串。该字符串来自 params[]。我应该如何处理这个字符串,就好像它是一个类名一样?例如,我想做:
Article.all
等等。
有什么想法吗?
【问题讨论】:
标签: ruby string class constants
class Abc
end #=> nil
klass = eval("Abc") #=> Abc
klass.new #=> #<Abc:0x37643e8>
假设确实有一个具有所提供名称的类...
在 ActiveSupport 中,有 String#constantize,它做了同样的事情,但我相信它在 2.1 之后已被弃用。
编辑:这是来自 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
【讨论】:
我不确定我是否正确理解了您的意图。这里我假设all 是Article 的一个Class 方法,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"]
【讨论】:
此解决方案优于 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
【讨论】:
MyModule::MyClass。为此,您必须在“::”上拆分,然后,例如,将注入与 const_get 一起使用。