Reputation: 221
I have this code:
module M
def m
"hello"
end
end
include M
m # => hello
M.m # => hello
By including M
at the top level, I can call m
. How come I can call M.m
?
Upvotes: 0
Views: 80
Reputation: 114208
Invoking include M
at the top level includes your module in Object
:
module M
def m
"hello"
end
end
include M
Object.included_modules #=> [M, Kernel]
You can achieve the same with:
class Object
include M
end
And because everything in Ruby is an object, you can send m
to every object1, including instances and classes and modules (like M
):
123.m #=> "hello"
'foo'.m #=> "hello"
String.m #=> "hello"
Object.m #=> "hello"
Enumerable.m #=> "hello"
M.m #=> "hello"
1 an object in the sense of is_a? Object
Upvotes: 4
Reputation: 121000
Even more weird example:
▶ module M ; end
▶ def m ; puts '¡Hola!' ; end
#⇒ :m
▶ M.m
#⇒ ¡Hola!
So, let’s dig into object inheritance. The execution context is main
. main
is apparently a “special” instance of Object
, propagating all the methods defined on it to be visible everywhere. Since Module
instance (M
) is in fact an instance of Object
, it all of a sudden responds to each Object
method. But we just have an Object
extended with m
method.
Note: module M ; def m ; end ; end; include M
and def m ; end
on a top level do almost the same thing: both extend Object
with m
method (the latter makes this method private
on Object
, though.)
Hope it helps.
Upvotes: 0
Reputation: 369526
The "default definee" (i.e. the module that methods defined with def
and include
d mixins end up in) at the top-level is Object
.
This means that M
gets included into Object
, i.e. M
becomes a superclass of Object
, inserted underneath Kernel
. Since M
is an instance of module, and Module
is a subclass of Object
and Object
now is a subclass of M
, it is possible to call M.m
.
The ancestry chain of Module
is:
[Module, Object, M, Kernel, BasicObject]
ergo, M
is in the method lookup path for M
, and therefore M.m
finds the method defined in M
.
Upvotes: 1