Skip to Content
Course content

19: Open Classes and Monkey Patching

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you just bought a house. It's a great house, but the previous owner didn't install a dishwasher, and you really want one. In most languages, that house is a sealed concrete box—you can't change the layout once it's built. But Ruby is different. In Ruby, the walls are more like drywall. If you decide the kitchen needs a new appliance, you just cut a hole in the wall, slide the dishwasher in, and suddenly, your house has a feature it wasn't born with.

This is exactly how "Open Classes" work. In Ruby, classes are never truly closed. Even the core classes that come built-in—like String, Integer, or Array—can be reopened at any time. When you reopen a class and add a method to it, we call that "Monkey Patching." You're essentially patching new functionality into a class that someone else wrote.

Giving Strings a New Superpower

Let's say you're building a blog, and you find yourself constantly converting article titles into URL-friendly "slugs" (like turning "Hello Ruby World!" into "hello-ruby-world"). Instead of writing a helper method that you have to pass a string into every single time, you can just teach the String class how to do it itself.

class String
  def to_slug
    self.downcase.strip.gsub(/\s+/, '-').gsub(/[^\w-]/, '')
  end
end

# Now, every single string in your entire application has this method
title = "My First Ruby Lesson!"
puts title.to_slug 
# Output: "my-first-ruby-lesson"

"  Monkey Patching is Wild  ".to_slug 
# Output: "monkey-patching-is-wild"

Notice that I didn't inherit from String to create a SlugString subclass. I just opened the existing String class and added a method. Now, to_slug feels like it was always part of the language. It's incredibly elegant, and it makes your code read like a natural sentence.

The Danger of Stepping on Toes

Now, I have to give you a warning. I've seen monkey patching bring down production environments in ways that are a nightmare to debug. Because these classes are global, you are changing the behavior of that class for every single piece of code in your project, including the libraries (gems) you've installed.

Imagine you decide to "improve" the Integer class by changing how the + method works because you think it would be "cooler" if it always rounded up. Suddenly, a gem you're using for payment processing—which relies on Integer math—starts calculating totals incorrectly. You've just broken a third-party library by changing the ground it stands on.

The rule of thumb I follow is this: Monkey patch sparingly. If you're adding a brand new, uniquely named method (like to_slug), you're usually safe. If you're overriding a method that already exists (like gsub or each), you're playing with fire. Only do it if you absolutely have to, and document it heavily so the next developer doesn't lose their mind trying to figure out why String is behaving strangely.




📋 Practical Task

Building a Currency Formatter for Integers

In this exercise, you're going to extend the built-in Integer class to make financial formatting easier. Instead of calling a separate formatter class, you want to be able to call a method directly on any number to turn it into a formatted currency string.

Your Task:

  • Reopen the Integer class.
  • Add a method called to_usd.
  • The method should return a string that starts with a "$" sign, and uses commas as thousands separators (for example: 1250000 should become "$1,250,000").
  • Test your implementation with a few different numbers, including a small number (like 50) and a very large one (like 10000000).
Rating
0 0

There are no comments for now.

to be the first to leave a comment.