Read more

Ruby: How to use prepend for cleaner monkey patches

Emanuel
July 31, 2018Software engineer at makandra GmbH

Let's say you have a gem which has the following module:

module SuperClient

  def self.foo
    'Foo'
  end
  
  def bar
    'Bar'
  end

end
Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show archive.org snapshot

For reasons you need to override foo and bar.

Keep in mind: Your code quality is getting worse with with each prepend (other developers are not happy to find many library extensions). Try to avoid it if possible.

  1. Add a lib/ext/super_client.rb to your project (see How to organize monkey patches in Ruby on Rails projects)
  2. Add the extension, which overrides both methods (prepend is available since Ruby >=2)
module SuperClientExtension

  def self.prepended(base)
    base.singleton_class.send(:prepend, ClassMethods)
  end

  module ClassMethods
    def foo
      'New foo'
    end
  end
  
  def bar
    'New bar'
  end
  
end

module SuperClient
  prepend SuperClientExtension
end

Test

class Test; include SuperClient; end

Test.foo => 'New foo'
Test.new.bar => 'New bar'

Good practice

If you do monkey patches, you could raise if the version you monkey patched changes. So that someone who does an update will be notified and can check if the monkey patch is still necessary.

Why you should do it this way (instead of doing regular monkey patches)

  • you can still call super to get the original implementation of the method
  • the prepended class will appear in the list of ancestors
Emanuel
July 31, 2018Software engineer at makandra GmbH
Posted by Emanuel to makandra dev (2018-07-31 14:59)