May 28, 2025
Monkey patching is a powerful and controversial technique in Ruby. It involves reopening existing classes and modifying or adding methods directly. Let’s dive into what it is, why it can be problematic, and some better ways to achieve similar goals.
What is Monkey Patching?
In Ruby, you can add or change the behavior of any class at runtime:
class String
def shout
upcase + "!"
end
end
puts "hello".shout # => "HELLO!"
While this flexibility can be tempting, it also comes with risks.
Need to Extend Class Behavior Safely?
If you’re looking to extend class behavior in your application following best practices, I can help!
The Problems with Monkey Patching
The Problems with Monkey Patching
Global Impact : Changes to core classes affect all parts of your application, including libraries that depend on them. This can lead to subtle bugs and maintenance nightmares.
Unexpected Behavior : Other developers (or your future self) might not expect your modifications, especially when debugging issues in seemingly unrelated code.
Compatibility Issues : If a gem or Ruby itself later adds a method with the same name, you could break things in unpredictable ways.
A Better Alternative: Refinements
Introduced in Ruby 2.0, Refinements provide a way to modify classes locally instead of globally:
class String
def greet
"Hello, " + self
end
end
module ShoutRefinement
refine String do
def greet
"HELLO, " + upcase
end
end
end
using ShoutRefinement
puts "world".greet # => "HELLO, WORLD"
The beauty of refinements is that they only affect the scope where using is declared, preventing unintended global changes.
Decorators: Another Clean Approach
For situations where you want to extend behavior without changing the class itself , the Decorator Pattern can be a great fit. A decorator wraps the original object, adding behavior while delegating to the original methods:
class User
def name
"Alice"
end
end
class UserDecorator
def initialize(user)
@user = user
end
def name
@user.name.upcase
end
end
user = User.new
decorated_user = UserDecorator.new(user)
puts decorated_user.name # => "ALICE"
With decorators, you avoid changing core classes and keep your code flexible and maintainable.
Conclusion
While monkey patching can be handy, it’s often better to use refinements or decorators for local and explicit changes. These techniques keep your code clean and avoid hidden side effects.
Have you used monkey patching or refinements in your work? Let me know your thoughts!
Top comments (0)