#---Callback/Hook Methods---
The most common Callback methods in Ruby are:
These are called when a module is included, prepended,
or extended in a class,
Or when a class is inherited from another class.
Module callbacks:
module Trainable
def self.included(base)
p "Module Trainable included in #{base}"
end
def self.prepended(base)
p "Module Trainable prepended in #{base}"
end
def self.extended(base)
p "Module Trainable extended in #{base}"
end
end
class Person
include Trainable
end
class Robot
prepend Trainable
end
class Machine
extend Trainable
end
## Just executing the above code will print:
## => "Module Trainable included in Person"
## => "Module Trainable prepended in Robot"
## => "Module Trainable extended in Machine"
Class callback:
class Animal
def self.inherited(subclass)
p "Class Animal inherited by #{subclass}"
end
end
class Dog < Animal
end
## Just executing the above code will print:
## => "Class Animal inherited by Dog"
It even works with multi-level inheritance:
class Labrador < Dog
end
## => "Class Animal inherited by Labrador"
There are two I can think of:
1. Callback Use One:
Like how some good parents set up some advantage for
their children even before they are born, ruby classes
and modules can use these callback methods to set up
some initial state or behavior for the classes and
modules that include/prepend/extend/inherit from them
later on.
(Weird analogy, I know. But I’m thinking of certain things now.)
Rails has this example where a parent class sets up the inheriting child class’s activerecord associations via the inherited callback for a test case:
=begin ## comment block because I didn't install Rails
class Device < ActiveRecord::Base
def self.inherited(subclass)
subclass.belongs_to :person, \
inverse_of: subclass.name.demodulize.tableize.to_sym
subclass.filter_attributes = [:secret_attribute, \
:"#{subclass.name.demodulize.downcase}_key"]
end
end
class Computer < Device; end
=end
Computer class gets the belongs to person association and the filter_attributes without doing any work.
2. Callback Use Two:
We know including a module in a class makes the module
methods as the class’s instance methods.
And extending a module in a class makes the
module methods as the class’s class methods.
But what if we have a module that has some methods
that will be used as instance methods, and some others
that’ll be used as class methods? This is a practical
use case.
We can use this common pattern to do that:
module Trainable
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def train
"Training #{self}"
end
end
def run
"#{self} is running"
end
end
class Person
## this gives both the class method `train` and the
## instance method `run`
include Trainable
end
p Person.train
p Person.new.run