Skip to content

Oh Right, Ruby Refinements Exist

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.