[perl] MOP(メタオブジェクトプロトコル)について調べてみた


プログラミングのレベルを1つステップアップするためにメタプログラミングについて調査してみた。 メタプログラミングについては以下の書籍が有名だと思います。。この本はRubyをベースに書かれています。 実は読んだことがないのですが、次に読もう!!

MOP周りの用語

この記事の内容に書かれていることを抜粋
MooseとClass::MOPでメタプログラミング始めた

  • メタプログラミング
    ロジックを直接コーディングするのではなく、あるパターンをもったロジックを生成する高位ロジックによってプログラミングを行う方法

  • MOP(メタオブジェクトプロトコル)
    メタクラスを通してオブジェクトシステムへアクセスするAPI

  • メタクラス
    クラスの振る舞いを定義したクラスでイントロスペクション(introspection)とインターセッション(itercession)を備える

  • イントロスペクション
    オブジェクトの属性を得る能力 ex) 何のクラスを継承しているかとか、何のメソッドを持ってるかとか

  • インターセッション
    オブジェクトの振る舞いに変更を加える能力 ex) 親クラスを変更するとか、メソッドを追加するとか

メタプログラミングについて

メタプログラミングとはよく「プログラムをプログラムすること」と言われますが、どういうことでしょう?!
まつもとさんの書かれた記事にほぼ書いているのですが、
まつもと直伝 プログラミングのオキテ 第6回メタプログラミング

Perl の Mooseで説明すると、次のコードで説明できる。

■ MooseでHogeモジュール定義、mainで利用する

package Hoge;
use Moose;

has 'message' => (
    is => 'rw',
    required => 1,
);

# Hogeを利用するためのmainモジュール
package main;

my $obj = Hoge->new(message => "HOGE MESSAGE");
print $obj->message;   # HOGE MESSAGE

Hoge を new して message という属性(アトリビュート)のアクアクセサメソッドをつかって属性(アトリビュート)を設定したり、呼び出したりしている。ここでいう「has」メソッドが メタプログラミングされたメソッド となる。Mooseを定義することで自動で「new」メソッドができ、hasメソッドを書くことで message のセッター、ゲッターが暗黙的に利用できる状態になる。
このことをメタプログラミングと言って、「has」メソッドなど、 動的にオブジェクトやクラスにメソッドや属性を追加するための API を MOP という。そのMOPを提供するためのクラスをメタクラスという。
Perlでは Class::MOP が提供する。

Class::MOPを利用してみる

先ほどのHogeクラスをベースClass::MOPを使って動的にメソッドや属性を差し込む処理は以下の様な感じになります。

use strict;
use warnings;

package Hoge;
use Moose;

has 'message' => (
    is => 'rw',
    required => 1,
);

# このMooseのHogeクラスをClass::MOPのみでも作成することができる
# my $person_meta = Class::MOP::Class->create('Person');
#
# $person_meta->add_attribute(
#     'name',
#     accessor => 'name',
# );

##### ここから差し込むための処理 #####

package main;
use Class::MOP;

my $meta = Hoge->meta;  # [1] Hogeのメタクラスを取得

$meta->add_attribute(   # [2] nameという属性とアクセサメソッドの追加
    'name',
    accessor => 'name',
);

$meta->add_method(describe => sub { # [3] describeメソッドの追加
    my $self = shift;
    return "Name: ".$self->name.",  Message: ".$self->message;
});

my $hoge = Hoge->new(message => "I like soccer.", name => "YUSABANA");
  # オブジェクトの生成は以下のように$metaを使っても生成できる
  # $meta->new_object(message => "I like soccer.", name => "YUSABANA");

# 差し込んだメソッドdescribeを実行する
print $hoge->describe."\n";  # [4] Name: YUSABANA,  Message: I like soccer.

  • コード上[1]でHogeモジュールのメタクラスを取得する。
    このメタクラスを操作することで色々出来る。
  • コード上[2]は属性とアクセサメソッドを追加している。
  • コード上[3]はメソッドを追加している。
  • コード上[4]は追加したメソッドを実行して、画面出力する。

MOPを使えばこのように動的に処理を差し込むことができる。
Mooseの hasメソッドを定義している所でも add_attribute とかを使っているんだろ-なと予想できますねー!まだ、実際にコードは見ていないので確実ではないのですが。。。

  1. Class::MOP::Class – クラスに対するプロトコル
  2. Class::MOP::Attribute – アトリビュートに対するプロトコル
  3. Class::MOP::Method – メソッドに対するプロトコル
  4. Class::MOP::Instance – クラスのインスタンス生成に対するプロトコル

Moose::Util::TypeConstraints を使うと更に便利そう
http://idocsq.net/page/370

余談(Groovyでのメタプログラミング例)

■Stringクラスにhogeというメソッドを追加している。

String.metaClass.hoge = {->
    delegate.equals("hoge") ? true : false
}

println "hog".hoge()  //=> false
println "hoge".hoge() //=> true

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です