1. ホーム
  2. スクリプト・コラム
  3. ルビートピックス

Rubyにおけるフックメソッドとメソッド呼び出しへのフックの追加例

2022-01-04 16:49:20

フックメソッドは、特定のイベントが発生した後に特定のコールバック関数を実行できるという点で、イベントドライバと多少似ています。Railsでは、beforeafter関数が最も一般的なフックメソッドです。

class#inheritedメソッドもそのようなフックメソッドの一つで、クラスを継承する際にRubyが呼び出すメソッドです。デフォルトではClass#inheritedは何もしませんが、継承を行うことでそのイベントをインターセプトし、興味のある継承されたイベントに対応することができるのです。

class String
  def self.inherited(subclass)
    puts "#{self} was inherited by #{subclass}"
  end
end
class MyString < String; end


出力します。
String was inherited by MyString



Rubyのクラスやモジュールのライフサイクルに介入できるフックメソッドを利用することで、プログラミングの自由度を大きく向上させることができます。

メソッド呼び出しにフックを追加した例
rubyにはinclude, included, method_missingなどの便利なフックがたくさんあります。メソッド呼び出しにフックを追加するには、aliasを巻き付けることで実現できますが、少し面倒ですし、alias_method_chainはwith_featureメソッドを定義する必要があるので、これも面倒ですので、次のように実装します モジュール、call method_callback :before_method,:after_method after includeでfirst_methodへのフックを追加してください。

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



実行結果は以下の通りです。

#enter class 1
#from lambda before
#after enter class doubi
#from lambda after
#from third enter