In the discussion of the difference between
extend in Ruby, there is a misconception that
extend would add methods to the singleton class of a ruby object as stated in many posts on this topic. But in fact, it is added to the ancestors chain of the singleton class! Even though it is technically not the same, practically this can be considered the same in most use cases.
This means, that we are able to overwrite these methods or call the parent version with
super depending in which order and in which way they were added to singleton class.
Consider the following code:
module A def foo puts "Foo!!" end end module B def self.included(base) base.extend(ClassMethods) end module ClassMethods def foo puts "Foo!" super end end end class User singleton_class.include(A) include B end User.instance_eval do def foo puts 'Foo' super end end User.foo # => "Foo Foo! Foo!!" User.singleton_class.ancestors # => [#<Class:User>, B::ClassMethods, A, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject] User.singleton_class.class # => Class User.singleton_class.ancestors.class # => Module
#<Class:User> is the singleton class and as we have seen the parent versions of
foo have only been added to the ancestor chain of the singleton class and not to the singleton class itself.
extendinclude class methods in this example?
The reason why the singleton class defines it's methods as class methods (and not as instance methods) is, because now it is a Module of the singleton class of the actual
Userclass object and not on an instance of
User. You can also use this to extend the singleton class of an user to add instance methods.
This is also the reason why
all parameter to decide whether methods on the singleton inheritance chain should be included.
For example, if module
A defined method
#bar and Module
B defines method
User.singleton_methods # => [:foo, :bar, :baz] User.singleton_methods(false) # => [:foo]
For the technical details have a look at this great card on the Ruby object model.