0
0
Rubyprogramming~15 mins

Included hook in Ruby - Deep Dive

Choose your learning style9 modes available
Overview - Included hook
What is it?
The Included hook in Ruby is a special method called automatically when a module is included in a class or another module. It lets you run custom code right at the moment your module becomes part of another class. This helps you set up things like adding methods, setting variables, or modifying behavior dynamically. It's a way for modules to prepare or adjust the class that includes them.
Why it matters
Without the Included hook, modules would be passive and unable to customize or prepare the classes that use them. This would make it harder to write flexible, reusable code that adapts itself when mixed in. The Included hook solves the problem of modules needing to do setup work automatically, making Ruby code more powerful and modular. Without it, developers would have to manually call setup methods, increasing errors and boilerplate.
Where it fits
Before learning the Included hook, you should understand Ruby modules and how to include them in classes. After this, you can explore advanced Ruby metaprogramming techniques like extending classes, prepending modules, and using other hooks like extended. This topic fits in the journey of mastering Ruby's mixin and metaprogramming capabilities.
Mental Model
Core Idea
The Included hook is Ruby's way for a module to say 'Hey, I just joined you!' and run setup code inside the class that included it.
Think of it like...
Imagine a new team member joining a project team. The Included hook is like the team member introducing themselves and setting up their workspace automatically as soon as they join, so they can start working smoothly.
Module A
  │ includes
  ▼
Class B
  └─> Included hook runs inside Module A with Class B as argument
      └─> Module A can add methods or setup Class B dynamically
Build-Up - 7 Steps
1
FoundationUnderstanding Ruby Modules
🤔
Concept: Modules are containers for methods and constants that can be shared across classes.
In Ruby, a module groups related methods and constants. You cannot create objects from modules directly, but you can include them in classes to share their behavior. Example: module Greetings def hello "Hello!" end end class Person include Greetings end p = Person.new puts p.hello # Outputs: Hello!
Result
The Person class gains the hello method from the Greetings module.
Understanding modules as reusable method containers is key to grasping how the Included hook can customize classes when modules are included.
2
FoundationHow Including Modules Works
🤔
Concept: Including a module inserts its methods into the class's method lookup chain.
When you include a module in a class, Ruby inserts the module into the class's inheritance chain. This means the class can use the module's methods as if they were its own. Example: module M def greet "Hi" end end class C include M end c = C.new puts c.greet # Outputs: Hi
Result
The class C can call greet because the module M is included.
Knowing that including a module changes method lookup helps understand why the Included hook can modify the class at the moment of inclusion.
3
IntermediateIntroducing the Included Hook
🤔Before reading on: do you think the Included hook runs automatically or must be called manually? Commit to your answer.
Concept: The Included hook is a special method called automatically when a module is included in another class or module.
You can define a method named included inside your module. Ruby calls this method with the including class as an argument right after the module is included. Example: module M def self.included(base) puts "Module included in #{base}" end end class C include M end # Output: Module included in C
Result
The message shows the Included hook runs automatically when the module is included.
Understanding that the Included hook runs automatically lets you write code that reacts immediately to inclusion, enabling dynamic setup.
4
IntermediateUsing Included Hook to Add Methods
🤔Before reading on: do you think methods added inside the Included hook become instance or class methods? Commit to your answer.
Concept: Inside the Included hook, you can add methods or modify the including class dynamically.
You can use the base argument (the including class) to add methods. Example: module M def self.included(base) base.class_eval do def new_method "I'm new!" end end end end class C include M end c = C.new puts c.new_method # Outputs: I'm new!
Result
The class C gains a new instance method dynamically when including M.
Knowing you can add methods dynamically inside the Included hook unlocks powerful metaprogramming patterns.
5
IntermediateSetting Class Variables in Included Hook
🤔
Concept: The Included hook can set or initialize class-level data when included.
You can use the Included hook to set class variables or constants. Example: module M def self.included(base) base.instance_variable_set(:@my_var, 42) end end class C include M def self.my_var @my_var end end puts C.my_var # Outputs: 42
Result
The class C has a class instance variable set by the Included hook.
Understanding that the Included hook can initialize class data helps build flexible modules that configure classes automatically.
6
AdvancedCombining Included with Extend for Class Methods
🤔Before reading on: do you think the Included hook can add class methods directly or needs help? Commit to your answer.
Concept: The Included hook often uses extend to add class methods to the including class.
Modules can add class methods by extending the including class inside the Included hook. Example: module M def self.included(base) base.extend(ClassMethods) end module ClassMethods def class_greet "Hello from class!" end end end class C include M end puts C.class_greet # Outputs: Hello from class!
Result
The class C gains a class method from the module M via the Included hook.
Knowing the Included hook can extend the including class to add class methods is a key metaprogramming technique.
7
ExpertIncluded Hook and Module Nesting Surprises
🤔Before reading on: do you think including a module inside another module triggers the Included hook immediately? Commit to your answer.
Concept: Including a module inside another module triggers the Included hook immediately, affecting nested module behavior.
When you include a module inside another module, the Included hook runs at that moment, not just when the outer module is included in a class. Example: module A def self.included(base) puts "A included in #{base}" end end module B include A # Triggers A.included with B as base end class C include B # Does not trigger A.included again end # Output: A included in B
Result
The Included hook runs when A is included in B, not when B is included in C.
Understanding this helps avoid confusion about when setup code runs in nested modules.
Under the Hood
When Ruby processes an include statement, it inserts the module into the class's ancestor chain and then checks if the module defines a method named included. If it does, Ruby calls this method with the including class or module as an argument. This call happens immediately during the include operation, allowing the module to execute code that modifies the including class or module dynamically.
Why designed this way?
Ruby's Included hook was designed to give modules a chance to customize the classes that include them without requiring manual calls. This design supports Ruby's flexible mixin system and metaprogramming style, enabling modules to be active participants in class behavior. Alternatives like requiring explicit setup calls would be error-prone and verbose, so automatic hooks improve developer experience and code clarity.
Class or Module
    │
    │ include Module M
    ▼
  Ruby inserts M into ancestors
    │
    │ checks for M.included method
    ▼
  Calls M.included(base)
    │
    │ base is the including class/module
    ▼
  M runs setup code on base
Myth Busters - 3 Common Misconceptions
Quick: Does the Included hook run when a module is extended instead of included? Commit to yes or no.
Common Belief:The Included hook runs whenever a module is added to a class, whether by include or extend.
Tap to reveal reality
Reality:The Included hook only runs when a module is included, not when it is extended. For extend, Ruby calls a different hook named extended.
Why it matters:Confusing these hooks can cause setup code to never run, leading to missing methods or incorrect behavior.
Quick: If a module includes another module, does the Included hook of the included module run when the outer module is included in a class? Commit to yes or no.
Common Belief:The Included hook of a nested module runs only when the outer module is included in a class.
Tap to reveal reality
Reality:The Included hook runs immediately when the nested module is included in the outer module, not deferred until the outer module is included in a class.
Why it matters:This can cause unexpected side effects or setup code running earlier than expected, confusing debugging.
Quick: Can the Included hook add instance methods to the including class by defining methods inside the hook directly? Commit to yes or no.
Common Belief:You can define instance methods directly inside the Included hook method body and they become available in the including class.
Tap to reveal reality
Reality:Methods defined inside the Included hook method body belong to the module's singleton class, not the including class. To add instance methods, you must define them in the module or use class_eval on the base.
Why it matters:Misunderstanding this leads to methods not being available where expected, causing runtime errors.
Expert Zone
1
The Included hook runs in the context of the module's singleton class, so self inside included is the module itself, not the including class.
2
Using base.extend inside Included allows adding class methods, but this can cause conflicts if multiple modules extend the same methods.
3
The order of multiple Included hooks matters; they run in the order modules are included, which can affect method overrides and setup.
When NOT to use
Avoid using the Included hook for heavy logic or side effects that depend on runtime state; instead, use explicit initialization methods. For adding class methods, consider using the prepend pattern or refinements if you need more control.
Production Patterns
In production Ruby code, the Included hook is commonly used in gems to add both instance and class methods cleanly. It's also used to register classes in registries, set default configurations, or inject callbacks automatically when modules are included.
Connections
Observer Pattern
The Included hook acts like an automatic observer that reacts to inclusion events.
Understanding the Included hook as an event listener helps grasp how Ruby modules can respond dynamically to changes in class composition.
Dependency Injection
Included hook enables injecting behavior and setup into classes at inclusion time, similar to injecting dependencies.
Seeing the Included hook as a form of dependency injection clarifies how modules can configure classes without explicit calls.
Biological Symbiosis
Like two organisms benefiting by living together, the Included hook lets modules and classes adapt mutually when combined.
This cross-domain connection shows how cooperation and adaptation concepts appear in both biology and programming.
Common Pitfalls
#1Trying to add instance methods by defining them inside the included method directly.
Wrong approach:module M def self.included(base) def new_method "Hi" end end end class C include M end C.new.new_method # Error: undefined method
Correct approach:module M def self.included(base) base.class_eval do def new_method "Hi" end end end end class C include M end puts C.new.new_method # Outputs: Hi
Root cause:Defining methods inside included defines them on the module's singleton class, not the including class.
#2Assuming the Included hook runs when a module is extended instead of included.
Wrong approach:module M def self.included(base) puts "Included in #{base}" end def self.extended(base) puts "Extended by #{base}" end end class C extend M end # Output: Included in C (incorrect assumption)
Correct approach:module M def self.included(base) puts "Included in #{base}" end def self.extended(base) puts "Extended by #{base}" end end class C extend M end # Output: Extended by C
Root cause:Included and extended hooks are distinct and run on different operations.
#3Expecting Included hook to run only when the module is included in a class, ignoring nested module includes.
Wrong approach:module A def self.included(base) puts "A included in #{base}" end end module B include A end class C include B end # Output: (nothing or delayed)
Correct approach:module A def self.included(base) puts "A included in #{base}" end end module B include A # Triggers A.included with B end class C include B end # Output: A included in B
Root cause:Included hook runs immediately on module inclusion, even inside other modules.
Key Takeaways
The Included hook is a special method in Ruby modules that runs automatically when the module is included in a class or another module.
It allows modules to dynamically add methods, set variables, or modify the including class at the moment of inclusion.
Understanding the difference between included and extended hooks is crucial to avoid setup mistakes.
The Included hook runs immediately when a module is included, even inside nested modules, which can affect timing and behavior.
Using the Included hook effectively unlocks powerful metaprogramming patterns for flexible, reusable Ruby code.