概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: Metaprogramming: Ruby Hook Methods – Mehdi Farsi – Medium
- 原文公開日: 2018/03/27
- 著者: Mehdi Farsi
Ruby: メタプログラミングに役立つフック系メソッド(翻訳)
Rubyにはさまざまなフック系メソッドがあり、これらを用いてクラスやモジュールやオブジェクトをその場で操作できます。
以下はその中でも重要度の高いフック系メソッドです。
Module#included
Module#extended
Module#prepended
Class#inherited
モジュールでincluded
やextended
やprepended
を使う
これらのフック系メソッドは、モジュールが別のモジュールやクラスにそれぞれinclude
されたとき、extend
されたとき、prepend
されたときに必ず呼び出されます。
それぞれの動作は割りと似通っていますので、ここではincluded
フックメソッドを用いて詳しく説明します。
module Commentable
def self.included(commentable_entity)
puts "#{commentable_entity}エンティティがコメントを受け取れるようになった!"
end\
end
class MediumPost
include Commentable
end
上のコードの実行結果は次のとおりです。
MediumPostエンティティがコメントを受け取れるようになった!
このフックメソッドが定義されているモジュールを他のクラスやモジュールがinclude
すると、それらに応じてメソッドや属性をこのように追加できます。
このメカニズムは、ActiveSupport::Concern
モジュールで実際に使われています。
このメソッドの実装は、Module#extended
フックメソッドやModule#prepended
フックメソッドとだいぶ似通っています。
Class#inherited
このフックメソッドが定義されているクラスがあると、そのクラスのサブクラスが作成(定義)されたときに必ず呼び出されます。
class User
def self.inherited(user_type)
puts "#{user_type}はユーザーの一種です"
end
end
class Tenant < User
end
上のコードの実行結果は次のとおりです。
Tenantはユーザーの一種です
このフックメソッドは、あるクラスのサブクラスごとに変数やclass_attribute
を定義したい場合に割りと便利です。
ActiveRecord::Core
モジュールの[initialize_find_by_cache](https://github.com/rails/rails/blob/master/activerecord/lib/active_record/core.rb#L151)
クラスメソッドはまさにこれを行っています。
まとめ
フック系メソッドは、クラスやモジュールにその場で操作を加えたい場合になかなか有用です。
しかし、これらのフック系メソッドはモジュールやクラスの設計を改変するので、スーパークラスのメソッドがオーバーライドされるといった望ましくない副作用が生じる可能性もあります。
BasicObject#method_missing
フックメソッドについてはまた別の記事で解説いたします。
それじゃまた!
本記事をお読みいただきありがとうございました☺。
お役に立ちましたら、ぜひ本記事への 👏や共有をお願いします。