# Ruby Hooks: Extending Class Functionality with the included Hook

## Introduction

In the world of Ruby programming, we often rely heavily on Rails due to its abundant support and convenient features. Rails concerns are commonly used in models or controllers to abstract and provide the necessary functionality. However, when working with pure Ruby code, we may find ourselves in situations where we need to extend class functionality without the aid of Rails. This is where Ruby hooks, particularly the included hook, come into play.

## The Problem: Adding Class Methods in a Module

Recently, while working on a Ruby project, I encountered a scenario where I needed to write class methods within a module. Initially, I attempted to accomplish this using the `self` keyword, as shown in the following code snippet:

```ruby
module LearnIncluded
  def self.echo_class_name
    puts "I am called from #{self.class}"
  end
end

class User
  include LearnIncluded
end

User.echo_class_name  # => NoMethodError: undefined method `echo_class_name' for User:Class
```

Unfortunately, this approach did not work as expected. It resulted in an error stating that the **echo\_class\_name** method was undefined for the User class.

## The Solution: Leveraging the included Hook

Fortunately, I soon discovered the power of Ruby hooks, specifically the included hook. Ruby hooks allow us to execute code when specific events occur. In our case, the included hook enables us to extend class functionality when a module is included in a class.

To utilize the included hook, we define a method with the same name within the module that we want to include. This method will be called automatically when the module is included in a class, giving us the opportunity to modify the class's behavior in any desired way.

### Example Implementation

Let's see an example that demonstrates the usage of the included hook:

```ruby
module LearnIncluded
  def instance_method
    puts "I am an instance method"
  end

  def self.included(base)
    base.extend(MyClassMethods)
  end

  module MyClassMethods
    def echo_class_name
      puts "I am called from #{self.name}"
    end
  end
end

class User
  include LearnIncluded
end

user = User.new
user.instance_method        # => "I am an instance method"
User.echo_class_name        # => "I am called from User"
```

In this example, we define the **LearnIncluded** module, which adds functionality to classes that include it. The included hook within the module is triggered when the module is included in a class. In our case, it extends the class with a submodule called **MyClassMethods**. This submodule contains a class-level method called **echo\_class\_name**, which echoes the class name.

We then create an example class called **User** that includes the **LearnIncluded** module. By doing so, the class inherits both the instance method **instance\_method** and the class-level method **echo\_class\_name**.

Finally, we demonstrate the usage of both the instance method and the class-level method. We create an instance of the **User** class, invoke the **instance\_method**, and observe the output "I am an instance method." Subsequently, we call the class-level method **echo\_class\_name** on the **User** class, which produces the output "I am called from User."

## Additional Example: Utilizing the included Hook

To further illustrate the usage of the included hook, let's consider a scenario where we want to track the number of instances created for each class that includes a specific module.

```ruby
module InstanceCounter
  def self.included(base)
    base.extend(ClassMethods)
    base.include(InstanceMethods)
    base.initialize_counter
  end

  module ClassMethods
    attr_accessor :instance_count

    def initialize_counter
      @instance_count = 0
    end
  end

  module InstanceMethods
    def initialize(*args)
      self.class.instance_count += 1
      super
    end
  end
end

class Person
  include InstanceCounter

  def initialize(name)
    @name = name
  end
end

class Animal
  include InstanceCounter

  def initialize(species)
    @species = species
  end
end

Person.new("Alice")       # Person instance_count: 1
Person.new("Bob")         # Person instance_count: 2
Animal.new("Dog")         # Animal instance_count: 1

puts Person.instance_count # => 2
puts Animal.instance_count # => 1
```

In this example, we have defined a module called **InstanceCounter** that tracks the number of instances created for each class that includes it.

The included method extends the class with the **ClassMethods** submodule and includes the **InstanceMethods** submodule. Additionally, it initializes the instance counter for the class.

The **ClassMethods** submodule defines an **instance\_count** attribute accessor and a method called **initialize\_counter** that sets the **instance\_count** to 0.

The **InstanceMethods** submodule overrides the initialize method to increment the **instance\_count** every time a new instance is created.

We then create two example classes, **Person** and **Animal**, that include the **InstanceCounter** module. This automatically triggers the included hook, extending the classes with the required functionality and initializing their instance counters.

Finally, we create instances of the Person and Animal classes and output the instance count for each class. The output will display the number of instances created for each class.

## All Available Ruby Hooks

**Method-related hooks:**

* method\_added
    
* method\_missing
    
* method\_removed
    
* method\_undefined
    
* singleton\_method\_added
    
* singleton\_method\_removed
    
* singleton\_method\_undefined
    

**Class and module-related hooks:**

* append\_features
    
* const\_missing
    
* extend\_object
    
* extended
    
* included
    
* inherited
    
* initialize\_clone
    
* initialize\_copy
    
* initialize\_dup
    

**Object marshaling hooks:**

* marshal\_dump
    
* marshal\_load
    

**Coercion hooks:**

* coerce
    
* induced\_from
    
* to\_xxx
    

## Conclusion

Ruby hooks are a powerful feature that allows us to extend class and module functionality dynamically. The included hook is particularly useful when we need to add both instance and class methods to a class through a module. By understanding and leveraging Ruby hooks effectively, we can write more flexible and maintainable code that adapts to the needs of our applications.

Whether you're building Rails applications or working with pure Ruby, mastering Ruby hooks will significantly enhance your ability to create elegant and extensible solutions.
