こんにちは、タナカです。
夏は花火を見ながら飲むビールが最高ですね。
さて、本日はRubyをある程度使いこなせるようになった方へおすすめの「メタプログラミングRuby」を紹介したいと思います。

- 作者: Paolo Perrotta,角征典
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/10/10
- メディア: 大型本
- この商品を含むブログ (3件) を見る
メタプログラミングとは?
そもそもメタプログラミングとは何でしょうか、本書籍には以下一文で説明されています。
メタプログラミングとは、コードを記述するコードを記述することである。
Javaのソースコード上で使用できるアノテーションや、C++のテンプレートのようなコードを思い浮かべるとわかりやすいかもしれません。
これらのように、プログラムの一部を自動生成するものをメタプログラミングと呼びます。
ただし、これらの場合はコードジェネレータやコンパイラを使ったものなので、「静的メタプログラミング」と呼んで本書籍では区別しています。
Rubyの場合は言語自体がメタプログラミングをサポートしていて自由度の高い事ができるため、「動的メタプログラミング」と呼んでいます。
Rubyのメタプログラミング
まずは、ソースコードを見ていただくのが早いと思います。
class Movie < ActiveRecord::Base end movie = Movie.create # moviesテーブルにtitleカラムが定義されている場合 movie.title = “博士の異常な愛情” movie.title #=> “博士の異常な愛情”
このコード上ではMovieクラスにtitleメソッドが定義されていないにも係わらずエラーにならず設定、参照できています。
エラーにならず動作するのは、Movieクラスで定義されていないメソッドが呼ばれた際に、method_missing()というメソッドが呼ばれるのですが、このメソッドをActiveRecord::Base上で定義してあるからです。
ActiveRecord::Baseでは、テーブルのカラム名に一致するメソッドが実行されたときにmethod_missing()を通して値が設定されるようになっています。
Rubyでは、メタプログラミングの技術でプログラムを動的に拡張することができます。
ActiveRecordをはじめ様々なgem等で、このような技術が利用されています。
書籍の構成
本書籍は2部+付録の構成になっていて、1部は以下の章で構成されています。
- 1章 頭文字M
- 2章 オブジェクトモデル
- 3章 メソッド
- 4章 ブロック
- 5章 クラス定義
- 6章 コードを記述するコード
この中から第2章のオブジェクトモデルを少し紹介したいと思います。
オブジェクトモデル
この章では、クラスやオブジェクトを動的に拡張する方法から、メソッド探索等Rubyの内部処理について学ぶことができます。
オープンクラス
オープンクラスとは、クラスをオープンしてその場で拡張できる技法のことです。
たとえば、Stringクラスを拡張するようなこともでき、以下のようにして文字列にメソッドを追加できます。
class String def to_alphanumeric gsub(/[-\w\s]/, “”) end end “#3, the *magic, Number*?”. to_alphanumeric #=> “3 the Magic Number”
オブジェクトモデルの内部
オブジェクトモデルのメソッドや、インスタンス変数は以下のようにしてプログラム中で取得することができます。
また、RubyではJavaとは違いインスタンス変数は値が代入されるまで存在しないという特徴があります。
class MyClass def my_method @v = 1 end end obj = MyClass.new obj.class # => MyClass obj.my_method obj.instance_variables # => [:@v] obj.methods.grep(/my/) # => [:my_method]
オブジェクトからは、classを通して、クラス定義を調べることもできます。
クラスの真相
Rubyではクラスはオブジェクトであるという特徴があり、Class.newで新しいクラスを動的に生成することもできてしまいます。
“hello”.class # => String String.class # => Class Class.instance_mothods(false) # => [:allocate, :new, superclass]
オブジェクトとクラスは以下の関係があります。
オブジェクトobjのclassはMyClassクラスであり、MyClassクラスのclassはClassクラスになります。
まだ、MyClassクラスのsuperclassはObjectクラスで、さらに、ObjectクラスのsuperclassはルートクラスのBasicObjectクラスです。 (図にはありませんが)
この関係を覚えておくとRubyの理解が深まると思います。
メソッドを呼び出すときに何が起きているの?
メソッドを呼び出すとRubyはまず「メソッド探索」を行い、次に「メソッドの実行」を行います。
メソッド探索
メソッド探索では「レシーバー」と「継承チェーン」の2つの考えを把握しておく必要があります。
用語 | 説明 |
---|---|
レシーバ | 呼び出すメソッドが属するオブジェクト |
継承チェーン | クラスからスーパークラス、スパークラスのスーパークラス、ルートクラスのBasicObjectまで通るクラスの道筋 |
メソッド探索 | レシーバーのクラスに入り、メソッドを見つけるまで継承チェーンを登ること |
以下はメソッド探索のイメージ図です。
矢印の1でレシーバーのクラスに入り、矢印の2で継承チェーンを登りメソッドを見つけます。
本書籍では、ほかにモジュールを組み合わせたパターンや、多重インクルード時のメソッド探索についても解説されています。
なお、継承チェーンの内容はancestorsメソッドで確認することができます。
MySubclass.ancestors # => [MySubclass, MyClass, Object, Kernel, BasicObject]
メソッドの実行
メソッドを実行する際は、まずメソッドが呼び出されているオブジェクト(レシーバ)が何なのかを意識する必要があります。 以下の例は、レシーバであるobjがselfになること、レシーバを明示していないmy_methodメソッドのレシーバがobjになることを表したものです。
class MyClass def testing_self @var = 10 # selfのインスタンス変数 my_method # self.my_methodと同じ self end def my_method @var = @var + 1 end end obj = MyClass.new obj.testing_self # => #<MyClass:0x007f93ab08a728 @var=11>
まとめ
今回紹介した内容は本書籍の内容のごく一部です。
次の3章では動的メソッドを利用して重複コードを排除する方法、2部ではRailsにおけるメタプログラミングについて解説されていて、いずれも興味深いものです。
Rubyについて深く理解するためにも、メタプログラミングRubyはぜひオススメです。