こんにちは、YOUTRUSTの今井(YOUTRUST/X)です。 今回は私が最近読んでいる「メタプログラミングRuby第2版」の感想と実際にYOUTRUSTでメタプログラミングが使われている箇所の紹介をしようと思います。
メタプログラミングとは
メタプログラミングとは、コードを記述するコードを記述することである。
書籍の導入でメタプログラミングについて、上記のような説明がされています。
具体例として、Active Record
でもメタプログラミングが使用されています。
class Movie < ActiveRecord::Base end
上記のようにActiveRecord::Base
のサブクラスを作っただけで、以下のことをメタプログラミングがやってくれます。
- 名前が
movies
のテーブルにマッピング - オブジェクトの
attribute
にアクセスするtitle=
,title
のようなメソッドを自動的に定義
つまり、以下のようなコードが記述できるようになります。
movie = Movie.create movie.title = "博士の異常な愛情" movie.title # => "博士の異常な愛情"
上記のコードは、movies
テーブルのレコードをラップしたMovie
オブジェクトを生成し、title
フィールドにアクセスするMovie#title
やMovie#title=
を呼び出しています。
しかしこれらのメソッドはソースコードのどこにも見当たりません。
このメソッドの定義をメタプログラミングがやってくれていました。
つまり、ActiveRecord::Base
が実行時にテーブルのスキーマを読み取り、movies
テーブルにtitle
というカラムがあることを見つけ、Movie#title
やMovie#title=
といったメソッドをこっそり定義してくれていたのです。
つまり、メタプログラミングをもっと厳密に定義すると、以下のように定義できると説明されています。
メタプログラミングとは、言語要素を実行時に操作するコードを記述することである。
Active Record
は、クラスのattribute
ごとにアクセサメソッドを書くのではなく、ActiveRecord::Base
を継承するだけで、実行時にアクセサメソッドが定義されるようなコードを書いています。
「コードを記述するコードを記述」してくれていたのです。
メタプログラミングによって、コードの重複を避け、より簡潔なコードを書くことができていることがわかります。
YOUTRUSTではどのように使われているのか
実際にYOUTRUSTでメタプログラミングを使用されている箇所を探してみました。
module FeedContent extend ActiveSupport::Concern module ClassMethods def feed_item_content(display_type:, publisher_method_name: :user) has_one :feed_item, as: :content, dependent: :restrict_with_exception alias_method :original_create_feed_item!, :create_feed_item! define_method :default_feed_item_hash do { display_type: display_type, publisher: public_send(publisher_method_name) } end define_method :create_feed_item! do |arg = {}| original_create_feed_item!(arg.merge(default_feed_item_hash)) end end end end
上記のFeedContent
モジュールは、YOUTRUST のタイムラインで表示する各フィードのクラスで使用しています。
YOUTRUSTではタイムラインで複数の種類のフィードを表示しています。
- 一般投稿
Postモデル
- コミュニティ内の投稿
CommunityPostモデル
- 募集投稿
RecruitmentPostモデル
etc.
この時、各フィードで共通して使用するメソッドを、FeedContent
モジュール内で定義しています。
モジュール内で使用されているdefine_method
は、メソッドをその場で定義することができるメソッドです。
上記のコードによってdefault_feed_item_hash
メソッドやcreate_feed_item!
メソッドは、FeedContent
モジュールをincludeした各クラスのインスタンスメソッドとして定義されます。
各フィードのクラスでcreate_feed_item!
メソッドを定義するのではなく、FeedContent
モジュールをincludeするだけで、実行時にcreate_feed_item!
メソッドを定義してくれます。
以下のようにコードを記述することが可能になります。
post = Post.new post.create_feed_item! # create_feed_item!に渡す引数も動的に定義している community_post = CommunityPost.new community_post.create_feed_item! recruitment_post = RecruitmentPost.new recruitment_post.create_feed_item!
最後に
今回「メタプログラミングRuby第2版」を読んだことで、これまでRubyでなんとなく書いていたコードの仕組みを理解することができました。特にメソッドを呼び出すときに何が起きているのか、丁寧に説明がされていてRubyの謎(少し大袈裟な言い方ですが)がよく分かりました。
「メタプログラミングRuby第2版」はRubyに慣れてきて、さらに深く理解したい人におすすめの書籍だと思います。 www.oreilly.co.jp
最後まで読んでいただきありがとうございます! 今回YOUTRUSTの一部コードを紹介しましたが、弊社ではOPEN CODEというYOUTRUSTの本番コードをNGなしでお見せするイベントを定期的に開催しております。 もし今回のブログで少しでもYOUTRUSTに興味を持っていただいた方は、ぜひご参加ください。
過去のイベントレポートがこちらです!
絶賛採用も強化中です!