如何使用模块修补类?

时间:2015-01-30 14:44:45

标签: ruby ruby-on-rails-3 monkeypatching

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

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

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

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.有没有办法做到这一点,或者我必须使用没有模块包装器的全局类扩展?

1 个答案:

答案 0 :(得分:4)

您正在寻找像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类的范围内工作,因此它不太可能破坏某些东西。

您的原始方法不起作用的原因是,您实现了一个新的::Array类(请注意命名空间),而不是使用猴子修补Stylable::Array类。

如果您正在运行Ruby&lt; 2.0并且你不想全局地修补Array,你可以创建从数组继承的自定义类:

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

并在Printer文件中使用它:

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

另一种方法是修补Array全球的猴子,这是不推荐的。