【问题标题】:Open classes in a module在模块中打开类
【发布时间】:2011-08-07 00:17:12
【问题描述】:

我知道我可以执行以下向 String 类添加方法

class String
  def do_something
    puts self.size
  end
end

var = "test"
var.do_something

这将返回4

我希望能够拥有一个带有接收字符串的函数的模块,但能够在该字符串上调用do_something 方法(例如,请参见下文)- 有可能吗?

编辑:添加了不起作用的示例代码

module TestModule
  class String
    def do_something
      puts self.size
    end
  end

  def self.test(str)    
    str.do_something
  end
end

这给出了错误:undefined method 'do_something' for "hello":String (NoMethodError)

【问题讨论】:

  • 是的。您的代码完全按照编写的方式工作。当您在 String 中定义 doSomething 时,它适用于所有字符串,在所有范围内。
  • @John Douthat 它不起作用,我已经编辑了问题以显示我正在运行的代码
  • 你是想让字符串在你的模块范围内有这个功能吗?
  • Ruby不使用camelCase,所以应该是do_something。只是说':)
  • Ruby 也使用 2 个空格缩进。也只是说。

标签: ruby monkeypatching ruby-1.9.2


【解决方案1】:

也许是这个?

module TestModule
  module_function
  def test(str)
    str.instance_eval{doSomething}
  end
end

Test.test(str)

编辑由于问题的变化而改变

只需将doSomething 的定义放在TestModule 类之外。

class String
  def doSomething
    puts size
  end
end

module TestModule
  module_function
  def test(str)  
    str.doSomething
  end
end

【讨论】:

    【解决方案2】:

    按照您的代码编写方式,您定义了一个名为 TestModule::String 的新类。如果要修改内置的 Ruby String 类,如果要将声明保留在模块中,则需要使用 String 的完全限定名称(带有“”::“)。

    module TestModule
      class ::String
        def do_something
          puts self.size
        end
      end
    
      def self.test(str)  
        str.do_something
      end
    end
    

    添加 "::" 告诉 Ruby 你想要的 String 类不是 TestModule 的一部分。

    在同一个文件中在 TestModule 之外声明 String 可能更简洁。

    如果您不想污染全局 String 类,您可以只修改要添加方法的特定 String 实例。

    module TestModule
      def self.test(str)  
        do_somethingify!(str)
        str.do_something
      end
    
      def self.do_somethingify!(str)
        unless str.respond_to? :do_something
          str.instance_eval do
            def do_something
              puts size
            end
          end
        end
      end      
    end          
    

    【讨论】:

    • 我们不应该使用class_eval吗?您能否评论一下使用 instance_eval/class_eval 与仅修改全局类字符串之间的性能差异?无论哪种方式 +1 并接受答案
    • 它使用的是 instance_eval 因为你正在修改一个特定的对象,而不是一个类。你也可以使用str.define_singleton_method(:do_something) { puts size }。修改全局类可能会表现得更好。您可以使用标准基准库来衡量差异。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-31
    • 1970-01-01
    • 2011-10-26
    • 1970-01-01
    • 2011-02-24
    • 2021-10-12
    • 1970-01-01
    相关资源
    最近更新 更多