When learning ruby people usually explain
extend as follows. Use include if you want to add instance methods:
And use extend if you want to add class method:
While these code examples work, they don’t really explain what is going on. A better way to understand the difference is that
extend is used to add a module’s methods to a specific instance while
include is like copying and pasting the instance methods from the module into the place where you call it.
To clarify, in the first example above using
include, it is as if the
def do_it code from the module
DoIt was inside the class
Doer as a regular
def. That means it is applied to instances of the
Doer class. In the
extend example, on the other hand, the methods are added to that particular instance of the class
Class, in this case the
Doer class. That means the methods are added to the class
Doer itself as class methods.
Similarly, if you have an instance of a class, you can call extend on it to apply a module to that instance only:
That means you can use
extend to methods to an instance of a class, the exact opposite of how people usually explain
extend working. You can also use
include to add class methods like so:
You can even do something similar to use
include to add methods to a single instance of a class:
So you can see that
include have nothing really to do with whether instance or class methods are added to a class, but more how those methods are applied.
How is any of this useful? Besides being a lot (A LOT) of fun, this can frequently be helpful knowledge when dealing with a DSL, usually from a gem. Recently I needed to edit some code in a rails codebase that used a DSL to generate a sitemap. Most of the code appeared in a block and for some reason all of the rails url helpers were available, but not some custom url-related helpers we’d defined in other rails helpers. We determined that the DSL was most likely using some sort of
instance_eval-based magic so we were able to use
extend inside the block to get the other helper methods we needed by adding them to the instance that the code was being evaluated in.
I hope you found this closer look at
extend illuminating or interesting and can use it next time you need to deal with some overly-metaprogrammed ruby code.