Let's say you have a gem which has the following module:
# within the imaginary super gem
module SuperClient
def self.foo
'Foo'
end
def bar
'Bar'
end
end
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.
- Add a
lib/ext/super_client.rbto your project (see How to organize monkey patches in Ruby on Rails projects) - Add the extension, which overrides both methods (
prependis available since Ruby >=2)
# lib/ext/super_client.rb
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
prependadds methods before the actual class
prependinserts a module into the class’s ancestor chain before the class itself and will define these as instance methods. Because of this we can callsuperwithin the prepended module and we need to prepend the class to define class methods.
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
superto get the original implementation of the method. - The prepended class will appear in the list of ancestors.
Posted by Emanuel to makandra dev (2018-07-31 12:59)