While browsing through the source code of a gem recently, I came across something I hadn't seen in a while: refinements.
Refinements were introduced in Ruby 2.4 as a better alternative to monkey-patching. It allows to override a core class method in a limited scope. On the other hand, monkey patching changes the method across the whole program.
Here's the example I saw:
# frozen_string_literal: true
module Isolator
module ThreadFetch
refine Thread do
def fetch(key, fallback = :__undef__)
raise KeyError, "key not found: #{key}" if !key?(key) && fallback == :__undef__
self[key] || fallback
end
end
end
end
This overrides Thread's fetch method.
Later in the same gem, it's used like this
module Isolator
using Isolator::ThreadFetch
class ThreadStateProxy
# Only within this scope, Thread#fetch behaves as defined above
...
end
end
What's nice here is that Thread#fetch
isn't changed globally. The override only applies inside the Isolator::ThreadStateProxy
module. Other parts of the app that use Thread won't be affected.