【问题标题】:Cast between String and Classname在字符串和类名之间转换
【发布时间】:2010-11-29 17:11:42
【问题描述】:

我有一个字符串,其中包含一个类名。例如,它是一个包含“Article”的字符串。该字符串来自 params[]。我应该如何处理这个字符串,就好像它是一个类名一样?例如,我想做:

Article.all

等等。

有什么想法吗?

【问题讨论】:

    标签: ruby string class constants


    【解决方案1】:
    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
    

    【讨论】:

    • 对参数使用 eval 有点危险,因为它可能包含有害代码。我不推荐这种解决方案
    • @khellll:既然你的答案被接受了,现在是“你的解决方案”!
    【解决方案2】:

    我不确定我是否正确理解了您的意图。这里我假设allArticle 的一个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"]
    

    【讨论】:

      【解决方案3】:

      此解决方案优于 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 一起使用。
      • 是的,它需要进一步完善...谢谢!
      • 好点。我添加了 active_support def,这更符合您的(更好的)建议。
      • 我已经添加了一个关于它的新帖子stackoverflow.com/questions/1448670/ruby-stringtoclass
      • 现在,您发布的代码对我来说有点“黑暗物质”:P 非常感谢!
      猜你喜欢
      • 2014-10-01
      • 2011-11-06
      • 2021-09-13
      • 1970-01-01
      • 1970-01-01
      • 2017-09-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多