コードの品質向上のため、Rubyでデザインパターンを解説した名著である Rubyによるデザインパターン で紹介されているデザインパターンを1つずつまとめており、今回が第15弾です。(毎週1つが目標です!)
前回の記事(DSL(ドメイン特化言語)のまとめ)はこちらです。
【Rubyによるデザインパターンまとめ14】DSL(ドメイン特化言語) - 銀行員からのRailsエンジニア
今回は メタプログラミング についてまとめました。
attr_reader と同じ機能を、メタプログラミングを使って実装しながら説明しています。
コード
Rubyのコードではお馴染みの「attr_reader」と同じ機能をメタプログラミングで実装してみましょう。
説明は不要だと思いますが、attr_reader はゲッターメソッドとも呼ばれ、クラスに
attr_reader :name
と記載するだけで、
def name @name end
このように、インスタンス変数を取得するメソッドを定義してくれる便利な機能です。
attr_reader という同じ名前だと分かりづらいので、同じ機能を持った「metapro_reader」をメタプログラミングを使って実装します。
class Object def self.metapro_reader(name) code = "def #{name} @#{name} end" class_eval(code) end end class User metapro_reader :name def initialize(name) @name = name end end
なんとこれだけです。
次のように実行すると
user = User.new('メタプロくん') puts user.name
次の結果になります。
メタプロくん
「metapro_reader :name」のところをコメントアウトすると、このコードは当然エラーします。
コードについて説明していきます。
Objectクラスは全てのクラスの最終的な親クラスで、Objectクラスにメソッドを定義するとどこからでも呼び出すことができます。
本家の attr_reader もそうなのですが、metapro_reader はただのクラスメソッドです。
class_eval メソッドがキモで、引数として渡された文字列をクラス内でRubyプログラムとして実行してくれます。これにより、動的にメソッド(今回でいう metapro_reader)を定義することができます。
※ 本家の attr_reader メソッドは ObjectクラスにincludeされているModuleモジュールに書かれているのですが、効率化のためにRubyではなく C で書かれています。
おわりに
ここまで読んでいただきありがとうございます。
メタプログラミングと聞くとちょっと怖い気がしますが、Rubyのコード内でも使われている身近なものだと分かると思います。
Rubyによるデザインパターン の中では、attr_reader 以外にも多くの例を用いて説明されていて分かりやすかったので、ご興味ある方は是非合わせてご覧ください。
- 作者:Russ Olsen,ラス・オルセン
- 発売日: 2009/04/01
- メディア: 単行本
また、以前読んだこちらもメタプログラミングについて多く説明がされておりとても面白かったです。
- 作者:Paolo Perrotta
- 発売日: 2015/10/10
- メディア: 大型本
次回は、Convention over Configurationについてまとめます。(次回でついに最終回です!)
来週も頑張ります!
(追記)
Convention over Configuration についてまとめました!
是非合わせてご覧ください。
ysk-pro.hatenablog.com