An example explains the hook method in ruby and adding hooks to method calls

Time:2021-11-27

The hook method is similar to the event driven device. It can execute a specific callback function after a specific event occurs. This callback function is the hook method (more vividly: the hook method can hook a specific event like a hook). In rails, the before \ after function is the most common hook method.

The class #inherited method is also such a hook method. Ruby will call this method when a class is inherited. By default, class #inherited does nothing, but through inheritance, we can intercept the event and respond to the inheritance event of interest.

?
1
2
3
4
5
6
class String
  def self.inherited(subclass)
    puts “#{self} was inherited by #{subclass}”
  end
end
class MyString < String; end

Output:

?
1
String was inherited by MyString

By using the hook method, we can intervene in the life cycle of ruby classes or modules, which can greatly improve the flexibility of programming.

Adds an instance of a hook to a method call
Ruby has many useful hooks, such as included, in here, and method_ missing。 Adding hooks to method calls can be implemented by using alias to surround the alias, but it’s a little troublesome after all, alias_ method_ Chain needs to define with_ The feature method is also more troublesome, so the following module and include are called method_. callback :before_ method,:after_ Method can be before_ Method add after_ Method hook

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
module AfterCall
 def self.included(base)
  base.extend(ClassMethods)
 end
 module ClassMethods
  def after_call when_call,then_call,*args_then,&block_then
   alias_method "old_#{when_call}",when_call
   define_method when_call do |*args_when,&block_when|
    send "old_#{when_call}",*args_when,&block_when
    send then_call,*args_then,&block_then
   end
  end
 end
end
class Student
 include AfterCall
 def enter_class sb
  puts "enter class #{sb}"
  yield('before') if block_given?
 end
 private
 def after_enter_class pop
  puts "after enter class #{pop}"
  yield('after') if block_given?
 end
 protected
 def third_after
  puts "from third enter"
 end
 
 after_call :after_enter_class ,:third_after
 after_call :enter_class ,:after_enter_class,"doubi", &lambda {|x|puts "from lambda #{x}"}
end
Student.new.enter_class "1" do |x|
 puts "from lambda #{x}"
end

The operation results are as follows:

?
1
2
3
4
5
#enter class 1
#from lambda before
#after enter class doubi
#from lambda after
#from third enter