# 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`

```ruby
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`

```ruby
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.

```ruby
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)
``` 



