Say I want to patch the Kernel
module with one method I just came up with:
module Kernel
def say_hello
puts "hello world"
end
end
I can now certainly do this:
Object.new.say_hello # => hello world
but I can also do the following which I normally shouldn't be able to do:
Object.say_hello # => hello world
Since Object
includes Kernel
it takes its instance methods and thus all Object
instances should respond to say_hello
. So far so good.
However Object.say_hello
seems to be a class method which could only be justified if we had done something similar to this:
class << Object
def say_hello
puts "hello world"
end
end
Storing say_hello
in Object
's singleton class would allow us to use it as a class method but instead Kernel
in just included in Object
which shouldn't allow this behavior. But it does. Does anybody have a clue why?
Thanks
Kernel
is just included inObject
[...]
That is correct.
[...] which shouldn't allow this behavior.
You overlook that classes are objects, too.
Let's see where the say_hello
method comes from if obj
is an instance of Object
:
obj = Object.new
obj.method(:say_hello)
#=> #<Method: Object(Kernel)#say_hello>
Just as expected. obj
is an instance of Object
and Object
includes Kernel
:
obj.class.include? Kernel
#=> true
obj.class.ancestors
#=> [Object, Kernel, BasicObject]
Now let's see what happens if obj
is the class Object
:
obj = Object
obj.method(:say_hello)
#=> #<Method: Class(Kernel)#say_hello>
This time obj
is an instance of Class
and Class
also includes Kernel
:
obj.class.include? Kernel
#=> true
obj.class.ancestors
#=> [Class, Module, Object, Kernel, BasicObject]
Ruby's documentation notes that class methods are in fact just instance methods defined on the class object: (emphasis added)
class C def self.my_method # ... end end
However, this is simply a special case of a greater syntactical power in Ruby, the ability to add methods to any object. Classes are objects, so adding class methods is simply adding methods to the Class object.