Recently I had to add a method to Redmine's core class. I was unable to use inheritance, so I've done something like this:
require_dependency 'time_entry_query'
class TimeEntryQuery < Query
def my_new_method(foo, bar)
end
end
and it works perfectly - my method is added to all new objects. However, I've seen someone declaring the new method in their own module instead and then sending :include to class, so it become a mixin. Here's an example:
module Patches
module SomeClassPatch
def my_new_method
end
end
and somewhere in app's initialization:
SomeClass.send(:include, Patches::SomeClassPatch) unless SomeClass.include? (Patches::SomeClassPatch)
What's difference between these two methods and which one should I use?
There are two differences:
When you use a mixin, there is a clear place where your "patch" methods can live. If I wonder "Hmm, where's this my_new_method
" coming from, and I look at, say, TimeEntryQuery.ancestors
or TimeEntryQuery.instance_method(:my_new_method).owner
, that will return Patches::SomeClassPatch
. So I know I have to look for a file named lib/patches/some_class_patch.rb
somewhere to find where it is probably defined. (I could try source_location
as well, but that is not always reliable.)
Mixing in a module into a class makes the module the superclass of the class it is being mixed into. So, if there already is a my_new_method
defined in TimeEntryQuery
, your first option will overwrite it, whereas in your second option, your method will become the super
method of that method. IOW: with your second option, your new method won't be called unless the already existing method calls super
.