To help you understand that, ruby provides you with Module#ancestors
:
Object.ancestors # => [Object, Kernel, BasicObject]
This is the order, in which an instance method of Object
will be searched for. So lets test your examples.
First, two modules included:
module M; end
module N; end
class C
include M
include N
end
C.ancestors # => [C, N, M, Object, Kernel, BasicObject]
So the methods will first be searched for in C
. If a method with the given name is not found, it is searched for first in N
and then in M
. In other words - the reverse order of which you included the modules.
Second, module, including a module, included in a class:
module X; end
module Y
include X
end
class K
include Y
end
K.ancestors # => [K, Y, X, Object, Kernel, BasicObject]
So we can see that the same rule applies for including in modules. Just as in the previous example a method will first be searched for in C
and only then in the modules included in C
, here a method will first will be searched for in a module, and only then in the included modules in that module.
The reason for that, other than consistency, is that classes are actually modules in Ruby:
Class.superclass # => Module
There are a lot of rules. For example including the same module twice in the hierarchy, singleton classes, #prepend
, #method_missing
and so on. But you can deduce all of it knowing how to use #ancestors
.