sakovias
sakovias

Reputation: 1434

How to monkey patch a class using a module?

I have a couple of files. In one I'd like to extend some Ruby classes, e.g.

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

In the other file I define a class and mix in my custom module.

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

For some reason, I can't exercise my custom Array#styled method:

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

What am I doing wrong?

Edit: While a solution from @MarekLipka below works in Ruby 2+. I have to do this on Ruby 1.9.3 / Rails 3. Is there a way to do this, or I have to use a global class extension without a module wrapper?

Upvotes: 2

Views: 1540

Answers (1)

Marek Lipka
Marek Lipka

Reputation: 51151

You're looking for a feature like 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

The advantage of using refinements is that this monkey-patch works only in scope of Printer class, so it's less likely to break something.

The reason your original approach doesn't work is that instead of monkey-patching ::Array class, you implemented a new Stylable::Array class (note the namespace).

If you're running Ruby < 2.0 and you don't want to monkey-patch Array globally, you could create custom class that inherits from array:

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

and use it in your Printer file:

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

The other way is monkey-patching Array globaly, which isn't recommended.

Upvotes: 4

Related Questions