Skip to content
AgileLogics
5 min read

Open Classes, Monkey Patching, and Refinements

Prerequisites: Modules and mixins

Ruby classes are open: you can reopen any class — even String or Integer — and add or change methods.

class Integer
  def minutes = self * 60
end

p 5.minutes
300

Changing a class you don't own is called monkey patching. It's powerful — Rails' 5.minutes and "title".titleize work this way — and dangerous:

  • It's global: every file, every gem in the process sees the change.
  • Two libraries adding the same method name silently overwrite each other.
  • A future Ruby version may add a method with the same name but different behavior.

Refinements — scoped patches

Refinements limit a patch to the files that ask for it:

module StringExtras
  refine String do
    def shout = upcase + "!"
  end
end

module Loud
  using StringExtras
  def self.greet = "hello".shout
end

p Loud.greet
p "hello".respond_to?(:shout)
"HELLO!"
false

using StringExtras activates the refinement only from that point to the end of the file (or of the module body). Everywhere else, String is untouched.

Guidelines

  • In application code, prefer a plain helper method or a small wrapper class over patching core classes.
  • If you must patch, use a refinement, or put the patch in a module and prepend it so it shows up in ancestors and can call super.
  • Never monkey patch inside a gem you publish — you'd be changing every user's application.