Module#prepend in Ruby 2.0
The best way to understand how
Module#prepend works is to figure out method lookup process in Ruby.
If it's a simple inheritance and method is present in parent class but not in a main class:
class Human def hi "Hi from Human!" end end class Man < Human end Man.new.hi # => Hi from Human!
It's the easiest and most obvious case. Method in parent class
Human is being called.
Let's see more interesting case, when methods with the same name present in both: parent class and module:
class Human def hi "Hi from Human!" end end module Greetable def hi "Hi from Module!" end end class Man < Human include Greetable end Man.new.hi # => "Hi from Module!"
As we can see, in this case method from module
Greetable is being called. So in hierarchy of ancestors - modules have higher priority than parent classes. We can check that using
Man.ancestors # => [Man, Greetable, Human, ...]
It shows us that to find method, Ruby will look into
Man class itself, then it will go to module
Greetable and only after that it will look into parent class
Let's get back to
Let's check what will happen if we change
include Greetable to
ancestors shows impact from changing
Man.ancestors # => [Greetable, Man, Human, ...]
As we can see, module
Greetable is the first element of ancestors' chain now. It means that even if we add
hi method to main class
Man - it will not be called. The first place to look for methods is a
Greetable module now.
Simple example to prove the impact:
module Greetable def hi "Hi from Module!" end end class Man prepend Greetable def hi "Hi from Man" end end Man.new.hi # => "Hi from Module!" Man.ancestors.inspect # => [Greetable, Man, Object]
It's unusual to change method lookup in Ruby this way, because it makes code more implicit and harder to understand. So you should use this option carefully. Usually it's better to change design of your classes to avoid using
But in rare cases
prepend works just perfectly and can save your from even more "hacky" approaches.
Thanks for reading!