Include, extend, and then get fancy.

include: makes instance methods from module as instance methods

When you include a module inside class.

  • All the instance method from the module becomes instance method for the instances of that class.
  • All singleton or class methods from the module are not accessible from either instance or class. We will discuss soon.

extend: makes instance methods from module as class methods

When you extend a module inside class

  • All the instance method from the module becomes singleton method of that class.
  • All the singleton method from the module becomes are not accessible from either instance of class. We will discuss.

Let learn by example.

What happens when we include module A containing both instance method and class method inside class Test

module A 

  def foo
    puts 'foo'
  end

  def self.bar 
    puts 'bar'
  end
end

class Test 
  include A 
end

Test.new.foo 
#=> foo
Test.foo  
#=> undefined method `foo' for Test:Class (NoMethodError)
Test.new.bar 
#=> undefined method `bar' for #<Test:0x000000012984f330> (NoMethodError)
Test.bar
#=> undefined method `bar' for Test:Class (NoMethodError)

What happens when we extend module A inside class Test

module A 

  def foo
    puts 'foo'
  end

  def self.bar 
    puts 'bar'
  end
end

class Test 
  extend A 
end

Test.new.foo 
#=> undefined method `foo' for #<Test:0x000000014a106eb8> (NoMethodError)
Test.foo  
#=> foo
Test.new.bar 
#=> undefined method `bar' for #<Test:0x000000014791b228> (NoMethodError)
Test.bar
#=> undefined method `bar' for Test:Class (NoMethodError)

What if we want to include a module having both instance and class level methods, and include both instance and class level methods. We can do it this way. Explanation after the example.

module A 

  def foo
    puts 'foo'
  end

  # Define all your singleton or class level methods here. Notice that we are not using `self` 
  # reference here.
  module ClassMethods
    def bar 
      puts 'bar'
    end
  end

  # This is a hook which will run when the module is included by another module. `base` is 
  # the class that included the module. Then we just `extend` all methods inside module 
  # `ClassMethods` so that those methods become singleton inside the base class.
  def self.included(base)
    base.extend ClassMethods
  end
end

class Test 
  include A 
end

Test.new.foo
#=> foo 
Test.bar
#=> bar
Test.new.bar
#=> undefined method `bar' for #<Test:0x0000000129186eb8> (NoMethodError)