Featured image

One of the most powerful and at the same time crazy ideas in Ruby is Monkey patching. However, its main drawback is that its effects apply globally across your entire project and all the gems you are currently using. The great advantage of Ruby, though, is that it allows for a compromise by scoping monkey patching to a limited context. To achieve this, you can use Refinements: define methods in a module using the refine Class do ... end construct and activate it with using. Starting with Ruby 3.1, you can also import methods directly from a module using import_methods:

module StringExt
  module Methods
    def blank? = self.nil? || self.empty?
    def present? = !blank?
  end

  refine String do
    import_methods Methods
  end
end

class SomeClass
  using StringExt

  def some_method
    "".blank?
  end
end

SomeClass.new.some_method # => true

Do you use Refinements in your projects? Or do you still patch classes globally?

String.class_eval do
  def blank? = self.nil? || self.empty?
  def present? = !blank?
end

# The `blank?` and `present?` methods will be available
# throughout the project and in other gems being used
"hello".present? # => true


module StringExt
  refine String do
    def blank? = self.nil? || self.empty?
    def present? = !blank?
  end
end

module Validator
  using StringExt
  def self.valid?(text) = text.present?
end

# The `blank?` / `present?` methods will be available only in this module
Validator.valid?("") # => false
"".blank? # => undefined method 'blank?' for an instance of String (NoMethodError)