Search code examples
ruby-on-railsrubymoduleclass-methodinstance-methods

Ruby self.extended gets called as instance method


module Country
  def location
    puts "location"
  end

  def self.included(base)
    def cities
      puts "cities"
    end
  end

  def self.extended(base)
    def animals
      puts "animals"
    end
  end
end

class Test
  include Country
end

class Test2
  extend Country
end

As far as I understand, self.included will be invoked when the module is being included as instance method where as self.extended will be invoked when the module is being extended as static class method.

But when I have two class in the same file, why it's not throwing error

Test.new.animals

=>animals

And If I removed the Test 2 class,

 # class Test2
  # extend Country
# end

Test.new.animals

=>No method error


Solution

  • def bar without an explicit definee (i.e. def foo.bar) defines bar in the closest lexically enclosing module. The closest lexically enclosing module for all three of your defs is always Country, so all three methods are defined in the Country module.

    If you want to define a singleton method, you could use

    module Country
      def self.extended(base)
        def base.animals
          puts "animals"
        end
      end
    end
    

    See Ruby what class gets a method when there is no explicit receiver? for more details.