Reputation: 1434
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
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