Perlでプラグインという仕組みを利用するには <2>
さて前回id:ya_ken:20060619:1150725716途中まで説明したCGI::Applicationのプラグインの実装方法の続きを書く。
今回のポイントを簡単に言えば「継承したわけではないのに、あるクラスにどうやって関数を追加するか」なんだ。そこで参考になるのが、CGI::Applicationについてるサンプリコードだ。
sub import { my $caller = scalar(caller); $caller->add_callback('init', 'my_setup'); goto &Exporter::import; }
この関数はプラグイン側に書かれるもので、何をしているかを分かりやすく言うと「CGI::Applicationのinitという処理にフックさせている」というわけ。
順を追って書こう、まず超重要なのはimport関数が何なのか?ということだ。Perlでuse xxxと書く時、Perlの仕様でxxxモジュールのimportメソッドが(あれば)呼ばれるんだ。だからプラグインにあるimportメソッドはそれがuseされた時点で自動的に呼び出される。そして、CGI::Applicationのプラグインをuseする場所はCGI::Applicationのサブクラスになるから$caller->add_callback()を呼ぶ事が出来るというわけ。これでフックの登録の仕組みは分かると思う。
次にgoto &Exporter::import部分を説明するが、説明の都合上Export::importのソースコードを読み解く事を強くお勧めする。ここではExport::importを適当に簡略化したコードを載せておく
sub import { my $pkg = shift; my $callpkg = caller(0); my @list_of_subroutins; ## @list_of_subroutinsを呼び出し元($pkg)の@EXPORTなどから初期化 *{"$callpkg?::$_"} = ?&{"$pkg?::$_"} foreach @list_of_siubroutins; }
実際に試してもらうのが一番良いのだけど、goto &Exporter::importの結果、このimportの$pkgはプラグインのパッケージ、$callpkgにはプラグインを呼び出したパッケージ、つまりCGI::ApplicationのサブクラスでCGI::Application::Plugin::Sessionをuseした場合は次のようになるはずだ。
そして、Exporter::importの最後の行でCGI::Application::Plugin::Sessionのエクスポート用関数をあなたが作ったCGI::Applicationのサブクラスにくっつけているというわけ。
これによってあなたのクラスから例えば$self->sessionみたいな関数が呼べるようになるというわけ。
じつはこれで昨日書いた2通りのプラグインの両方の説明を兼ねてしまったんだな。計画性も無く書いたから、ぐだぐだになってしまった。
まぁ、この仕組みをもう少しきれいにしてPluggableモジュールを作ったので、その仕組みを近いうちに書いてみよう。