Ruby refinements for scoped monkey patching

Sarah Mitchell Feb 2026
2 tabs
# Define refinements in a module
module StringExtensions
  refine String do
    def titleize
      split.map(&:capitalize).join(' ')
    end

    def to_bool
      self =~ /^(true|yes|1)$/i ? true : false
    end

    def truncate(length, omission: '...')
      return self if size <= length
      self[0...(length - omission.length)] + omission
    end
  end
end

# Without using refinements
"hello world".titleize  # NoMethodError!

# Activate refinements
using StringExtensions

"hello world".titleize  # => "Hello World"
"yes".to_bool           # => true
"long text".truncate(5) # => "lo..."

# Refinements are scoped to current file/module
module MyModule
  using StringExtensions

  def self.format(text)
    text.titleize  # Works here
  end
end

# Won't work outside the module
"test".titleize  # NoMethodError (unless using is called here too)

# Multiple refinements
module ArrayExtensions
  refine Array do
    def second
      self[1]
    end

    def third
      self[2]
    end

    def average
      return 0 if empty?
      sum.to_f / size
    end
  end
end

module HashExtensions
  refine Hash do
    def deep_symbolize_keys
      transform_keys(&:to_sym).transform_values do |value|
        value.is_a?(Hash) ? value.deep_symbolize_keys : value
      end
    end
  end
end

using ArrayExtensions
using HashExtensions

[1, 2, 3].average              # => 2.0
{ "a" => 1 }.deep_symbolize_keys  # => { a: 1 }
2 files · ruby Explain with highlit

Refinements provide scoped modifications to existing classes without global monkey patching. I use refinements to add methods to core classes safely. Refinements activate with using statement—scope-limited to file or module. Unlike monkey patches, refinements don't affect other code. Refinements are lexically scoped—only active where explicitly used. I prefer refinements over monkey patching for maintainability. Refinements enable extending libraries without side effects. Understanding refinement scope rules prevents surprises. Refinements work in modules, classes, and at file scope. They're Ruby's solution to safe class extension. Refinements balance Ruby's flexibility with predictability.