如何使用模块猴子修补 class?

How to monkey patch a class using a module?

我有几个文件。在一个中,我想扩展一些 Ruby classes,例如

module Stylable
  class Array
    def styled
      "\n" << "*"*72 << self.to_s << "*"*72 << "\n"
    end
  end
end

在另一个文件中,我定义了一个 class 并混入了我的自定义模块。

require './stylable'

class Printer
  include Stylable

  def initialize(object)
    @object = object
  end

  def print
    puts @object.styled
  end
end

Printer.new([1,2,3]).print

出于某种原因,我无法使用我的自定义 Array#styled 方法:

$ ruby printer.rb 
printer.rb:10:in `print': undefined method `styled' for [1, 2, 3]:Array (NoMethodError)
  from array_printer.rb:14:in `<main>'

我做错了什么?

编辑: 虽然下面@MarekLipka 的解决方案适用于 Ruby 2+。我必须在 Ruby 1.9.3 / Rails 3 上执行此操作。有没有办法执行此操作,或者我必须使用没有模块包装器的全局 class 扩展?

您正在寻找类似 refinements 的功能:

stylable.rb:

module Stylable
  refine Array do
    def styled
      "\n" << "*"*72 << self.to_s << "*"*72 << "\n"
    end
  end
end

printer.rb:

require './stylable'
class Printer
  using Stylable
  # ...
end
Printer.new([1,2,3]).print

使用改进的好处是这个猴子补丁只在 Printer class 的范围内工作,所以不太可能破坏某些东西。

你原来的方法不起作用的原因是你实现了一个新的Stylable::Arrayclass而不是猴子补丁::Arrayclass(注意命名空间).

如果您 运行 Ruby < 2.0 并且您不想全局使用猴子补丁 Array,您可以创建自定义 class 继承自数组:

class StylableArray < Array
  def styled
    "\n" << "*"*72 << self.to_s << "*"*72 << "\n"
  end
end

并在您的 Printer 文件中使用它:

Printer.new(StylableArray.new([1,2,3]))

另一种方法是全局猴子修补 Array,不推荐这样做。