Reputation: 337
consider the following example:
module M
end
class C
include M
end
c = C.new
p c.singleton_class.ancestors
the output is: [#<Class:#<C:0x000055b6b069c5f0>>, C, M, Object, Kernel, BasicObject]
but now if we include the module in singleton_class of object c as following
class << c
include M
p ancestors
end
the output is: [#<Class:#<C:0x000055b6b069c5f0>>, C, M, Object, Kernel, BasicObject]
But The well-grounded Rubyist
books say it should be as follows in chapter 13 Object individual
:
[#<Class:#<C:0x000055b6b069c5f0>>, M, C, M, Object, Kernel, BasicObject]
Upvotes: 0
Views: 47
Reputation: 857
To answer this question we need to understand how include works.
Module#include
Invokes #append_features on each parameter in reverse order.
Module#append_features
add the constants, methods, and module variables of this module to mod if this module has not already been added to mod or one of its ancestors.
If you swap the order in which you include the module you will have the expected result
module M
end
class C
end
c = C.new
p c.singleton_class.ancestors
# -> [#<Class:#<C:0x000056285c79a678>>, C, Object, Kernel, BasicObject]
class << c
include M
end
p c.singleton_class.ancestors
# -> [#<Class:#<C:0x000056285c79a678>>, M, C, Object, Kernel, BasicObject]
# M is not in the ancestors of the class C is ancestors of the singleton class
class C
include M
end
p c.singleton_class.ancestors
# -> [#<Class:#<C:0x000056285c79a678>>, M, C, M, Object, Kernel, BasicObject]
# The include statement put M as first ancestors of C
If we change the order
module M
end
class C
end
c = C.new
p c.singleton_class.ancestors
# [#<Class:#<C:0x000055b278d8a290>>, C, Object, Kernel, BasicObject]
class C
include M
end
p c.singleton_class.ancestors
# [#<Class:#<C:0x000055b278d8a290>>, C, M, Object, Kernel, BasicObject]
# M is ancestor of C and of the singleton class #C
class << c
include M
end
p c.singleton_class.ancestors
# [#<Class:#<C:0x000055b278d8a290>>, C, M, Object, Kernel, BasicObject]
# M is not included
Upvotes: 1