Question

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?

Was it helpful?

Solution

There are two differences:

  1. 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.)

  2. 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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top