銀行員からのRailsエンジニア

銀行員からのRailsエンジニア

銀行員から転身したサービス作りが大好きなRailsエンジニアのブログです。個人で開発したサービスをいくつか運営しており、今も新しいサービスを開発しています。転職して日々感じていること、個人開発サービス運営のことなどを等身大で書いていきます。

【Rubyによるデザインパターンまとめ15】メタプログラミング

コードの品質向上のため、Rubyデザインパターンを解説した名著である Rubyによるデザインパターン で紹介されているデザインパターンを1つずつまとめており、今回が第15弾です。(毎週1つが目標です!)

前回の記事(DSLドメイン特化言語)のまとめ)はこちらです。
【Rubyによるデザインパターンまとめ14】DSL(ドメイン特化言語) - 銀行員からのRailsエンジニア

今回は メタプログラミング についてまとめました。

attr_reader と同じ機能を、メタプログラミングを使って実装しながら説明しています。

f:id:ysk_pro:20200314140337p:plain

メタプログラミングとは

必要なコードを全て書いておくのではなく、実行時にプログラムに基づいて作り出します。

文章での説明よりも実際のコードを見た方が分かりやすので、以下のコードをご覧ください。

コード

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 以外にも多くの例を用いて説明されていて分かりやすかったので、ご興味ある方は是非合わせてご覧ください。

Rubyによるデザインパターン

Rubyによるデザインパターン

また、以前読んだこちらもメタプログラミングについて多く説明がされておりとても面白かったです。

メタプログラミングRuby 第2版

メタプログラミングRuby 第2版

次回は、Convention over Configurationについてまとめます。(次回でついに最終回です!)

来週も頑張ります!

(追記)
Convention over Configuration についてまとめました!
是非合わせてご覧ください。
ysk-pro.hatenablog.com