Search code examples
rubymoduleextend

How do I extend a Ruby module in class context?


I have the following Ruby script, in which class Foo includes module Baz, module Baz has a included hook to make Bar extended by the including class (Foo). I am just wondering why:

class << klass
  extend Bar #this doesn't work. Why?
end

does not work while:

klass.extend(Bar) works.

Here is my code:

#! /usr/bin/env ruby

module Baz
  def inst_method
    puts "dude"
  end 

  module Bar
    def cls_method
      puts "Yo"
    end
  end

  class << self
    def included klass
      # klass.extend(Bar) this works, but why the other approach below doesn't?
      class << klass
        extend Bar #this doesn't work. Why?
        def hello
          puts "hello"
        end
      end
    end
  end
end

class Foo
  include Baz
end

foo = Foo.new
foo.inst_method
Foo.hello
Foo.cls_method

Solution

  • Within the body of class << klass, self refers to the singleton class of klass, not klass itself, whereas in klass.extend(Bar), the receiver is klass itself. The difference comes from there.

    class A
    end
    
    class << A
      p self  # => #<Class:A>   # This is the singleton class of A, not A itself.
    end
    
    p A # => A     # This is A itself.
    

    And since you want to apply extend to klass, doing it within the body of class << klass does not work.