CGI::Application - 再利用可能なWEBアプリケーションを構築するためのフレームワーク
# "WebApp.pm"の内容... package WebApp; use base 'CGI::Application'; # (一般的なケースではにsetup()はスキップ可能。以降のドキュメント参照。) sub setup { my $self = shift; $self->start_mode('mode1'); $self->mode_param('rm'); $self->run_modes( 'mode1' => 'do_stuff', 'mode2' => 'do_more_stuff', 'mode3' => 'do_something_else' ); } sub do_stuff { ... } sub do_more_stuff { ... } sub do_something_else { ... } 1; ### "webapp.cgi"の内容... use WebApp; my $webapp = WebApp->new(); $webapp->run();
CGI::Applicationは洗練された、高効率で再利用可能なWebベースのアプリケーションの作成を簡単にすることを目指しています。このモジュールは、もし従えばWebソフトウェアをデザインしやすく、ドキュメント化しやすく、書きやすく、発展させやすくする方法論を実装しています。
CGI::Applicationは賢明にも、開発者をいずれかのツールやオペレーティング・システム、Webサーバの組み合わせに縛り付けてしまうような技術や技法を使うのを避けています。
あなたはウィジットのデータベースを検索するアプリケーションを書かなければならないとします。そのアプリケーションは3つの画面を持ちます:
1. 検索フォーム(Search form) 2. 結果のリスト(List of results) 3. 1つのレコードの詳細(Detail of a single record)
CGI::Applicationを使って、このアプリケーションを書くためには2つのファイルを作らなければなりません:
1. WidgetView.pm -- あなたの"アプリケーション・モジュール(Application Module)" 2. widgetview.cgi -- あなたの "インスタンス・スクリプト(Instance Script)"
アプリケーション・モジュール(Application Module)には、あなたのアプリケーションの機能に関するすべてのコードが入ります。そしてWebサーバのドキュメント・ルートの外の、Perlライブラリの検索パスのどこかにあります。
インスタンス・スクリプト(Instance Script)が実際にWebサーバから呼ばれます。それはとても小さく、単純なファイルで、それは単にあなたのアプリケーションのインスタンスを作成し、継承されたメソッドrun()を呼び出します。以下が``widgetview.cgi''の全体です。
#!/usr/bin/perl -w use WidgetView; my $webapp = WidgetView->new(); $webapp->run();
ご覧の通り、widgetview.cgi は単にアプリケーション・モジュール(それは``WidgetView''というPerlパッケージを実装しています)を``use''しているだけです。アプリケーション・モジュール``WidgetView.pm''は、より長いものになります:
package WidgetView; use base 'CGI::Application'; use strict; # データベース接続のために必要 use CGI::Application::Plugin::DBH; sub setup { my $self = shift; $self->start_mode('mode1'); $self->run_modes( 'mode1' => 'showform', 'mode2' => 'showlist', 'mode3' => 'showdetail' ); # DBI->connect()と同様の引数により、DBIデータベースへの接続; $self->dbh_config(); } sub teardown { my $self = shift; # 完了時には接続解除(DBIは通常、これを自動で行いますが) $self->dbh->disconnect(); } sub showform { my $self = shift; # CGIクエリオブジェクトの取得 my $q = $self->query(); my $output = ''; $output .= $q->start_html(-title => 'Widget Search Form'); $output .= $q->start_form(); $output .= $q->textfield(-name => 'widgetcode'); $output .= $q->hidden(-name => 'rm', -value => 'mode2'); $output .= $q->submit(); $output .= $q->end_form(); $output .= $q->end_html(); return $output; } sub showlist { my $self = shift; # データベース接続の取得 my $dbh = $self->dbh(); # CGIクエリオブジェクトの取得 my $q = $self->query(); my $widgetcode = $q->param("widgetcode"); my $output = ''; $output .= $q->start_html(-title => 'List of Matching Widgets'); ## DBI接続されたデータベースから、CGI.pm queryオブジェクトを介して ## 前のHTMLフォームから提供される、ユーザが指定した"widgetcode"の ## 値に対応する"widgets"を取得するための処理をおこなう。 ## ## 各行には以下のようにアンカー・タグを提供する"Widget Detail"への ## リンクが入ります。 ## ## "widgetview.cgi?rm=mode3&widgetid=XXX" ## ## ..."XXX"はユーザがクリックした"widget"に対するIDを表す ## ユニークな値になります。 $output .= $q->end_html(); return $output; } sub showdetail { my $self = shift; # データベース接続の取得 my $dbh = $self->dbh(); # CGIクエリオブジェクトの取得 my $q = $self->query(); my $widgetid = $q->param("widgetid"); my $output = ''; $output .= $q->start_html(-title => 'Widget Detail'); ## ユーザがクリックした"widget"のプロパティをすべて取得するための ## 処理を行います。このwidgetのキー IDの値は、CGI.pm query ## オブジェクトの"widgetid"プロパティを通して与えられます。 $output .= $q->end_html(); return $output; } 1; # Perlではすべてのモジュールの最後にこれが必要
CGI::Applicationはnew()とrun()メソッドの実装の面倒を見ます。STDOUTに出力をおくるためにprint()を呼んでいないことに注意してください。代わりにすべての出力はスカラで返されます。
CGI::Applicationのもっとも大きな貢献はアプリケーションの状態を管理することです。アプリケーションを先に進めるために必要なことは、HTMLフォーム・パラメータ'rm'の値を、フォーム・サブミッションを扱いたい実行モード(``run mode'')の値に設定することだけです。これがCGI::Applicationの鍵です。
CGI::Applicationの裏にある哲学をガイドすると、Webベースのアプリケーションは特定の``実行モード(Run-Mode)''の集まりにまとめることができるということです。各実行モードは大まかに1つの画面(一つのフォームと、複数の出力やその他)に対応します。実行モードはPerlモジュールである1つの``アプリケーション・モジュール(Application Module)''によって管理されます。Webサーバのドキュメント空間には``インスタンス・スクリプト(Instance Script)''があり、それはWebサーバによってCGI(あるいはApache+mod_perlを使っていればApache::Registryスクリプト)として呼び出されます。
この方法論は、アプリケーションの各状態ごとにページがあり、ページが機能を起動する``埋め込み(Embedded)''式(ASP、JSP、EmbPerl、Masonなど)の哲学の反対です。CGI::Applicationではフォームは機能に従います -- アプリケーション・モジュールがページを起動し、1つのアプリケーションのコードは1ヶ所にあります;複数の``ページ''に散らばったりしません。もし埋め込みアーキテチャがわかりにくい、まとまっていない、設計しにくく管理しにくいと感じるのであれば、CGI::Applicationは、そんなあなたのための方法なのです!
CGI::ApplicatinにApacheは必須ではありません。CGI::ApplicationをベースとしたWebアプリケーションはNT/IISや他の全てのCGI互換性のある環境でも同じように動きます。その一方で、CGI::Applicationをベースとしたアプリケーションは、自然に正しいプログラミングの実践を促進させ、しばしば何の変更もなしに永続的な環境で動作させることができるものになるので、Apache/mod_perlでの使用にも適したものになります。
mod_perl下でのCGI::Applicationの使用についてのより詳細な情報は、CGI::Application::Plugin::Apacheと同様、 http://www.cgi-app.org/ の私たちのサイトをご覧ください。
CGI::Applicationはオブジェクト指向のPerlモジュールで、抽象クラスを実装します。このパッケージを直接インスタンス化するようにはなっていません。代わりにあなたのアプリケーション・モジュールがCGI::Applicationのサブ・クラスとして実装されるようになっています。
CGI::Applicationから継承するためは、以下のコードがアプリケーション・モジュールのはじめの、パッケージ宣言の後になければなりません。
use base 'CGI::Application';
表記法と規約
このドキュメントでは、以下の表記法を利用します:
WebApp.pm アプリケーション・モジュール・クラスを実装するPerlモジュール。
WebApp アプリケーション・モジュール・クラス;CGI::Applicationのサブクラス。
webapp.cgi アプリケーション・モジュールを実装するインスタンス・スクリプト。
$webapp アプリケーション・モジュール・クラスのインスタンス(オブジェクト)
$self $webappと同じ。インスタンス・メソッドで現在のオブジェクトを表します
(標準のPerlオブジェクト指向のテクニック)
CGI::Applicationから継承することにより、多くの組み込みメソッドにアクセスできます。以下はインスタンス・スクリプトから呼ばれるであろうと考えられるものです。
new()
new()メソッドはCGI::Applicationのためのコンストラクタです。ブレスされたアプリケーション・モジュール・パッケージ(クラス)へのリファレンスを返します。new()はオプションでキー => 値の組をとることもできます:
my $webapp = App->new( TMPL_PATH => 'App/', PARAMS => { 'custom_thing_1' => 'some val', 'another_custom_thing' => [qw/123 456/] } );
このメソッドはいくつかの特定のパラメータをとることができます:
TMPL_PATH - このオプション・パラメータはテンプレートのディレクトリへのパスを定義します。これはload_tmpl()メソッド(後述)で使われ、そしておそらく他のテンプレート・プラグインでも同様の目的で使われるでしょう。この実行時パラメータにより、テンプレートのインスタンス作成をさらにカプセル化し、再利用性を高めます。これはスカラでも、複数のパスを指定するための配列リファレンスでも可です。
QUERY - このオプション・パラメータにより、既存のCGI.pmクエリ・オブジェクトを指定することが可能です。通常の使用時には、CGI::Applicationは自身でCGI.pmクエリ・オブジェクトをインスタンス化します。一定の条件下では、既存のものを使用できることが役立つかもしれません。
PARAMS - このパラメータは、もし使われると、実行時にいくつかのカスタム・パラメータを設定することができます。異なる値を同じアプリケーション・モジュールを使う異なるインスタンス・スクリプトで渡すことにより、さらに高いレベルの再利用性を実現できます。例えば、``MailForm.pm''というアプリケーション・モジュールがあるとします。アプリケーションはHTMLフォームの内容を取得し、これを指定された宛先にメールします。サイトのあちこちに、いずれもこの``MailForm.pm''モジュールを使った、異なる宛先、あるいは異なるフォームを設定した複数のインスタンス・スクリプトを設置することができます。
インスタンス・スクリプトでの一般的な使い方の一つは、設定(config)ファイルのパスを与えることです。この設計により、いくつものさまざまなインスタンス・スクリプトとして使われる、プロジェクト全般にわたる設定が行われたオブジェクトを定義できます。このための記法をシンプルにし、遅延読み込みを提供するいくつかのプラグインがあります。ここでは、さまざまな設定ファイルフォーマットをサポートすCGI::Application::Plugin::ConfigAutoを使用する例を挙げます。
my $app = WebApp->new(PARAMS => { cfg_file => 'config.pl' }); # Later in your app: my %cfg = $self->cfg() # or ... $self->cfg('HTML_ROOT_DIR');
これ以外の設定ファイルの統合方式については、後のプラグインリストを参照してください。
run()
run()メソッドはインスタンス・スクリプトから、アプリケーション・モジュール・オブジェクトに対して呼ばれます。呼ばれると、アプリケーション・モジュールの機能を実行します。
my $webapp = WebApp->new(); $webapp->run();
このメソッドは、まずmode_param()によって指定されるCGIパラメータ(デフォルトは``Run Mode''を表す``rm'')の値を参照することにより、アプリケーションの状態を判定します、それには操作のモードの名前が入っていることが期待されます。指定されなければ、状態はstart_mode()の値がデフォルトになります。
モード判定が行われると、run()はrun_modes()に格納されたディスパッチ・テーブルを検索し、モード名がキーになっている関数ポインタを見つけます。もしあれば関数が呼ばれ、返されたデータがSTDOUT、そしてブラウザにprint()されます。指定されたモードがrun_modes()テーブルになければ、run()はcroak()します。
予期せぬ死亡のハンドリング
実行モードが何らかの理由で死んでしまった場合、run()はerror_mode()が設定されているかを参照します。設定されていれば、run()はこのメソッドを実行モードとして、$@だけを引数として実行します。
プラグイン作成者はerror_mode()が呼び出される直前に、errorのフックが行われ、エラーメッセージが唯一のパラメータとして渡されることを知れば興味を持つかもしれません。おそらく変更されることはありませんが、このフックはいまだ実験的なものとみなされています。
これ以外のログ記録の統合方式については、CGI::Application::Plugin::LogDispatchを調べてみてください。
CGI::Applicationサブクラス・モジュールを実装していく中で、オーバーライドされることが期待されるいくつかのメソッドを実装しています。以下がそのメソッドです:
setup()
このメソッドへ継承されたnew()コンストラクタ・メソッドから呼び出されます。setup()メソッドは、以下のプロパティ/メソッドを定義するのに使われるべきです:
mode_param() - 実行モードのCGIパラメータ名を指定。
start_mode() - デフォルトの実行モードが入ったテキスト・スカラ。
error_mode() - エラーモードが入ったテキスト・スカラ。
run_modes() - mode => 関数のマッピングが入ったハッシュテーブル。
tmpl_path() - テンプレート・ファイルへのパスが入ったテキスト・スカラまたは配列リファレンス。
setup()メソッドでは、すべてのそのアプリケーションのすべてのインスタンス・メソッドを呼び出すことができます。この関数は$webapp->param()メソッドを介して、アプリケーション独特のプロパティを定義するのに適した箇所です。
setup()メソッドは、例えば以下のように実装されるでしょう:
sub setup { my $self = shift; $self->tmpl_path('/path/to/my/templates/'); $self->start_mode('putform'); $self->error_mode('my_error_rm'); $self->run_modes({ 'putform' => 'my_putform_func', 'postdata' => 'my_data_func' }); $self->param('myprop1'); $self->param('myprop2', 'prop2value'); $self->param('myprop3', ['p3v1', 'p3v2', 'p3v3']); }
ただし、しばしばsetup()内で必要なものは、実行モードとスタートモードを決めるだけになります。CGI::Application::Plugin::AutoRunmodeはこれを、実行モードの属性を使ったシンプルな記述で可能にします:
use CGI::Application::Plugin::AutoRunmode; sub show_first : StartRunmode { ... }; sub do_next : Runmode { ... }
teardown()
このメソッドは実装されていれば、アプリケーションの実行後に、自動的に呼び出されます。これはオペレーション後のクリーンアップに利用できるでしょう。teardown()関数の典型的な用途は、setup()関数で確立されたデータベース接続の切断です。また、teardown()メソッドをアプリケーションに関する状態情報をサーバに保持するのに使うこともできるでしょう。
cgiapp_init()
このメソッドは実装されていれば、まさにsetup()メソッドが呼び出されようとするその前に、自動的に呼び出されます。このメソッドは、補助的な初期化のフックを提供し、CGI::Applicationのオブジェクト指向の特性を向上させます。cgiapp_init()メソッドは、それ自身のパラメータとして、new()メソッドに送られたすべての引数を受け取ります。
このフックを利用することでもたらされる恩恵の例は、すべてのWebアプリケーションが、CGI::Applicationの代わりに継承するべき、カスタマイズされた``applicationスーパークラス''を作成することです。
以下について検討します:
# MySuperclass.pmの内容: package MySuperclass; use base 'CGI::Application'; sub cgiapp_init { my $self = shift; # ファイルやDBから設定を読み出すなどの # プロジェクト固有の初期化作業 }
# MyApplication.pmの内容: package MyApplication; use base 'MySuperclass'; sub setup { ... } sub teardown { ... } # CGI::Applicationに基づく続きを以下に...
説明したようにCGI::Applicationとcgiapp_init()メソッドを使うことで、特性を確実に共有するよう、アプリケーション・スイートを設計できます。これによりオブジェクト指向の継承に基づいたよりクリーンなコードを構築できるようになります。
cgiapp_prerun()
このメソッドは実装されていれば、まさに選択された実行モード・メソッドが呼び出されようとするその前に、自動的に呼び出されます。このメソッドは、補助的な実行モード前のフックを提供し、実行モード・メソッド呼び出し前のポイントへの機能追加を可能にします。
このフックをより有用にするために、実行モードの値がcgiapp_prerun()に渡されます。
もう一つの、このフックを利用することでもたらされる恩恵は、すべてのWebアプリケーションが、CGI::Applicationの代わりに継承するべき、カスタマイズされた``applicationスーパークラス''を作成することです。
以下について検討します:
# MySuperclass.pmの内容: package MySuperclass; use base 'CGI::Application'; sub cgiapp_prerun { my $self = shift; # 実行モード固有の認証機能をの指定を実装するなど、 # プロジェクト固有の初期化作業 }
# MyApplication.pmの内容: package MyApplication; use base 'MySuperclass'; sub setup { ... } sub teardown { ... } # CGI::Applicationに基づく続きを以下に...
説明したようにCGI::Applicationとcgiapp_prerun()メソッドを使うことで、特性を確実に共有するよう、アプリケーション・スイートを設計できます。これによりオブジェクト指向の継承に基づいたよりクリーンなコードを構築できるようになります。
もちろん、cgiapp_prerun()メソッドでも、アプリケーションの実行モードを変更することができます。これらは本POD中で取り上げる、prerun_mode()メソッドを介して行われます。
cgiapp_postrun()
このメソッドは実装されていれば、実行モード・メソッドがその出力を返した後、ただしHTTPヘッダが生成される前に、自動的に呼び出されます。これは、ボディとヘッダをWebブラウザに返される前に修正する機会を与えます。
このフックの典型的な用途は、CGI-Applicationの出力を一連の``フィルタ(filter)''プロセスにかけることです。例えば:
* CGI-Applicationの全出力を大きなページ中の一つのHTMLテーブル内に
入れたい。
* 実行モードは構造化されたデータ(例えばXML)を返しており、これを
標準的なメカニズム(例えばXSLT)を使って変換したい。
* CGI-Appを他のシステム、例えばHTML::Masonなどを通して後処理したい。
* すべての実行モード後に、HTTPヘッダを特定の方法で、特定の評価
基準に基づいて、変更したい。
cgiapp_postrun()フックはCGI-Appオブジェクトに加え、実行モード・メソッドからの出力のリファレンスを受け取ります。典型的なcgiapp_postrun()メソッドは、以下のように実装されます:
sub cgiapp_postrun { my $self = shift; my $output_ref = shift; # 出力をHTMLテーブルに入れる my $new_output = "<table border=1>"; $new_output .= "<tr><td> Hello, World! </td></tr>"; $new_output .= "<tr><td>". $$output_ref ."</td></tr>"; $new_output .= "</table>"; # 旧出力内容を新出力内容で置き換える $$output_ref = $new_output; }
自明のことですが、CGI-Appオブジェクトへのアクセスでは、実行モードで通常利用可能なすべてのメソッドにアクセスできます。例えばこの例での静的なHTMLを、load_tmpl()を使って、HTML::Templateで置き換えることも可能でした。HTTPヘッダを(header_type()およびheader_props()メソッドを介して)変更し、リダイレクトを設定することも可能でした。また、例えば、特定の実行モードでだけ、あるいはあるparam()が特定の時だけに行うのと同じように、ある状況下でだけオブジェクトプロパティを変更するのにも使えました。
cgiapp_get_query()
このメソッドはCGI::Applicationがクエリ・オブジェクトを取得するときに呼ばれます。cgiapp_get_query()は``require''を介してCGI.pmをロードし、CGI.pmクエリ・オブジェクトを返します。この実装は以下のようになっています:
sub cgiapp_get_query { my $self = shift; require CGI; return CGI->new(); }
CGI.pmの代わりに別のクエリ・インターフェースを使用したいと思ったら、このメソッドをオーバーライドすることができます。しかし、クエリインターフェースはCGI.pmと互換性があるか、CGI.pmとの互換性を実現するためにその選択したクエリインターフェースを``wrapper''クラスでくるんでやらなければいけないことに注意してください。
以下のメソッドはCGI::Applicationから継承され、自分のアプリケーション・モジュールを利用するアプリケーションから呼び出すことができます。これらの関数をアルファベット順に並べます。
delete()
$webapp->delete('my_param');
delete()メソッドは、それまでにnew()に渡されたPARAMSハッシュを使うか、またはparam()メソッドを呼ぶことでアプリケーションに保持させたパラメータを削除するのに使われます。これはCGI.pmのdelete()メソッドと非常に良く似たものです。これは、アプリケーションのここまでの部分で削除されることの、ある特定のパラメータの存在に基づく判定を行うようなアプリケーションや、あるいは単純にparam()のクリーンアップをするなどの際に便利でしょう。
dump()
print STDERR $webapp->dump();
dump()メソッドはデバッグ用の関数で、リクエストの環境変数とCGIフォームデータのすべてが入った、人間に読みやすくフォーマットされたテキストを返します。 STDERRに出力するのに便利です。
dump_html()
my $output = $webapp->dump_html();
dump_html()メソッドはデバッグ用関数でリクエストの環境変数とCGIフォームデータのすべてが入った、ブラウザを通して人間が読みやすくフォーマットされた部分テキストを返します。ブラウザに出力するのに便利です。
error_mode()
$webapp->error_mode('my_error_rm');
error_modeは規定の実行モードのeval呼び出しの失敗が起きた時に、呼び出される実行モード名を持ちます。デフォルトではerror_modeは定義されていません。error_mode()実行モードでの死亡はトラップされませんので、これを独自の方法で死なせるのに使うこともできます。
get_current_runmode()
$webapp->get_current_runmode();
get_current_runmode()メソッドは現在実行されている実行モード名を含むテキスト・スカラを返します。実行モードがまだ決定されていない場合、例えばsetup()中などには、このメソッドはundefを返します。
header_add()
# 'type'ヘッダの付加または置換え
$webapp->header_add( -type => 'image/png' );
- or -
# cookieの付加または追加
$webapp->header_add(-cookie=>[$extra_cookie]);
header_add()メソッドはレスポンスヘッダの出力用に、一つまたは複数のヘッダを付加するのに使われます。パラメータはCGI.pmのheader()メソッドに渡されるものと同等(eventuallly)ですので、使い方の詳細についてはCGIのドキュメントを参照してください。
header_props()を呼ぶのとは違い、header_add()は既存のヘッダを予約されているものとして扱います。header_add()にスカラ値が渡されたときはこれを置き換えます。
配列リファレンスが値としてheader_add()に渡されたときは、その配列リファレンス内の値が、そのキーに対する既存の値に追加されます。これはまず、すでにcookieが一つ設定されており、さらに追加で設定するときに便利でしょう。
header_props()
$webapp->header_props(-type=>'image/gif',-expires=>'+3d');
header_props()メソッドはCGI.pm互換のHTTPヘッダ・プロパティのハッシュを期待します。これらのプロパティは直接、CGI.pmのheader()またはredirect()メソッドに渡されます。使い方の詳細についてはCGIのドキュメントを参照してください。
header_propsは、これまでにセットした既存のすべてのヘッダを消去します。
古いものを消去することなしに、後からヘッダを追加するには、header_add()を見てください。
header_props()は現在設定されているすべてのヘッダのハッシュを返します。
IMPORTANT NOTE REGARDING HTTP HEADERS
header_props()およびheader_add()メソッドを通じて、出力されるHTTPヘッダを変更することができます。クッキーを設定したり、``text/html''以外のMIMEタイプを設定したり、リダイレクトを実行するためにこれは必要です。header_props()メソッドはheader_type()と一緒に機能します。header_type()に入っている値が、CGI::header()かCGI::redirect()のどちらを使うのかを決定します。header_props()の内容は、呼び出されるどちらかのCGI.pm関数に引数として渡されます。
この関係を理解することは、HTTPヘッダを正しく操作したいのであれば重要です。
$webapp->header_type('redirect');
header_type()メソッドは'header'、'redirect'または'none'のいずれかが渡されることを期待します。このメソッドは、ブラウザに送り返されるHTTPヘッダの種類を指定します。指定しなければ、デフォルトでは'header'になります。詳細はCGIのheaderセクションをご覧下さい。
CGI::Application(およびCGI.pm)をリダイレクトに使うには、以下を行います:
sub some_redirect_mode { my $self = shift; my $new_url = "http://site/path/doc.html"; $self->header_type('redirect'); $self->header_props(-url=>$new_url); return "$new_urlにリダイレクトしています"; }
HTTPヘッダを完全に抑制したい(いささかエキゾチックな環境で作業していれば、こうしたケースにあたるかもしれません)場合、header_type()で``none''を指定できます。これはヘッダーを完全に隠してしまいます。
load_tmpl()
my $tmpl_obj = $webapp->load_tmpl; my $tmpl_obj = $webapp->load_tmpl('some.html'); my $tmpl_obj = $webapp->load_tmpl( \$template_content ); my $tmpl_obj = $webapp->load_tmpl( FILEHANDLE );
このメソッドはテンプレート・ファイルの名前、テンプレートデータのリファレンス、あるいはFILEHANDLEを取り、HTML::Templateオブジェクトを返します。ファイル名が未定義であったり、未指定であればCGI::Applicationはデフォルトでは、現在の実行モード名+拡張子``.html''を使用しようとします。
デフォルトのテンプレート命名システムを使うのであれば、コントロールをある実行モードから別の実行モードに渡したときにも、現在の名前を性格に保持するのを補助してくれるシンプルな、CGI::Application::Plugin::Forwardも使うべきでしょう。
そのオブジェクトの作成のためにHTML::Template->new_file()コンストラクタが使われます。HTML::Templateの特別な使い方についてはHTML::Templateをご覧ください。
(そのほかのテンプレートシステムの統合とテンプレート命名の自動化については、後の``Alternatives to load_tmpl()''を見てください。)
ファイルネームを渡した場合、HTML::Template->new_file()コンストラクタがオブジェクト生成のために使われます。テンプレートコンテントのリファレンスを渡した場合はHTML::Template->new_scalar_ref()コンストラクタが、ファイルハンドルを渡した場合はHTML::Template->new_filehandle()コンストラクタが使われます。
HTML::Templateの使い方については、HTML::Templateを参照してください。
tmpl_path()が設定されていると、load_tmpl()は、パスを与えるために、HTML::Template pathオプションを設定します。これはさらにテンプレート使用のカプセル化を進めます。
load_tmpl()メソッドは他のいかなるパラメータも、ダイレクトにHTML::Template->new_file()(あるいはnew_scalar_ref()やnew_filehandle())に渡します。これにより、HTML::Templateオブジェクトをよりカスタマイズすることが可能になります:
my $tmpl_obj = $webapp->load_tmpl('some_other.html', die_on_bad_params => 0, cache => 1 );
他の引数を渡したいけれど、デフォルトのテンプレート名を使いたいというときには、名前としてundefを与える必要があることに注意してください:
my $tmpl_obj = $webapp->load_tmpl(undef, die_on_bad_params => 0, cache => 1 );
Alternatives to load_tmpl()
もしアプリケーションでこれよりももっと得意なことを行う必要があれば、CGI::Applicationのサブクラスであるアプリケーション・モジュールで、独自のload_tmpl()を実装することでload_tmpl()をオーバーライドして置き換えてしまうこともできます。
まず、そのテンプレートに関連したプラグインがないか、確かめておきたいと思うでしょう。
CGI::Application::Plugin::AnyTemplateはHTML::Template、Template Toolkit、Petalへの統一的なインターフェースと、自動的なデフォルトファイル名、そのほかの機能を提供しますまずこれを調べてみてください。
CGI::Application::Plugin::TTはTemplate Toolkitの統合にフォーカスしており、preおよびpost機能、シングルトンのサポートやその他の特徴を持ちます。
CGI::Application::Plugin::Streamはファイルなしでストリームを返したいという時の助けになります。シンプルな記述とMIME-type検知といった特徴を持ちます。
The load_tmpl() callback
プラグイン作成者はload_tmpl()が返る前に実行される、コールバックを登録できることを知れば興味を持つかもしれません:
$self->add_callback('load_tmpl',\&your_method);
your_method()が実行される際、三つの引数が渡されます:
1. C<load_tmpl>に渡される追加パラメータのハッシュリファレンス
2. 次に、テンプレート・パラメータのハッシュリファレンス。
これらにより、リファレンスをテンプレート・オブジェクトの
new()およびparam()メソッドに実際に渡される値に影響を及ぼす
リファレンスを介して、これらを変更することができます。
3. テンプレート・ファイル名。
load_tmpl()のスタブの例を示します:
sub my_load_tmpl_callback { my ($self, $ht_params, $tmpl_params, $tmpl_file) = @_ # modify $ht_params or $tmpl_params by reference... }
mode_param()
# 実行モード名を持つCGIフォーム・パラメタ。これはデフォルトの # 動作で、しばしばこれで十分です。 $webapp->mode_param('rm'); # 実行モードを直接コード・リファレンスで指定します。 $webapp->mode_param(\&some_method); # 代わりのインターフェースとして、これで$ENV{PATH_INFO} # から直接実行モードを取得するように指定できます。 $webapp->mode_param( path_info=> 1, param =>'rm' );
このアクセサ/ミューテータ・メソッドはsetup()メソッド内で呼ばれます。これは呼び出す実行モードの決定を助けるために使われます。三つの呼び出し方のオプションがあります。
$webapp->mode_param('rm');
ここでは、CGI使用される実行モードの名前が入るCGIフォーム・パラメータが名指しされています。これはデフォルトの動作で、'rm'という名前のパラメータが使われます。
$webapp->mode_param(\&some_method);
ここではコード・リファレンスが与えられています。これは実行モード名を直接返します。例えば:
sub some_method { my $self = shift; return 'run_mode_x'; }
これは任意のロジックに基づき、プログラム的に実行モードを設定することを可能にします。
$webapp->mode_param( path_info=> 1, param =>'rm' );
この記法で、簡単に$ENV{PATH_INFO}から直接実行モードを指定することが可能になります。この際、$ENV{PATH_INFO}の最初の部分(最初の``/''まで)を実行モードとして設定しようとします。むしろ$ENV{PATH_INFO}の2番目の部分から実行モード名を取得したいのだ、と指定するには:
$webapp->mode_param( path_info=> 2 );
また、これは、あなたがparamハッシュ・キーを渡す必要がないことも示しています。これはデフォルトのrmのままになります。
path_infoに負の値を設定することもできます。これは単純に逆方向のリスト・インデックスとして働きます:-1であれば、実行モード名は$ENV{PATH_INFO}の最後の部分から取られます。-2であれば、その一つ前、そういった具合です。
$ENV{PATH_INFO}から実行モードを見つけられなかった場合、前述したように、'param'で定義されたCGIフォームフィールドの値を見る方法に戻ります。これは大抵の場合は便利な$ENV{PATH_INFO}のトリックを利用しつつ、事前に実行モードを知ることができずJavaScriptで決定したいというような、極端なケースをサポートすることを可能にします。
$ENV{PATH_INFO}についての補足
実行モード名としての$ENV{PATH_INFO}の使用は、サブミットされたフォームの値と、処理する実行モードの決定方法が、きれいな分割されたものにします。URLも検索エンジンにとってよりフレンドリーなものにします。例として、次のような記述でのフォーム・サブミットを見てみましょう:
<form action="/cgi-bin/instance.cgi/edit_form" method=post>
<input type="hidden" name="breed_id" value="4">
ここでは実行モードは``edit_form''に設定されます。もう一つは、クエリ・ストリングを使った例です:
/cgi-bin/instance.cgi/edit_form?breed_id=2
これは$ENV{PATH_INFO}とクエリ・ストリングを問題なく一緒に使えることを示しています。CGIの仕様の一部として定義されている$ENV{PATH_INFO}は、CGIスクリプトをサポートするあらゆるWebサーバでサポートされるはずです。
param()
$webapp->param('pname', $somevalue);
param()メソッドはアプリケーション中でアクセスしやすい、アプリケーションインスタンスの特性を設定することができる能力を提供します。
param()メソッドには二つの基本的な使い方があります。第一に、これをパラメータ値の取得と設定に使うことです:
$webapp->param('scalar_param', '123'); my $scalar_param_values = $webapp->param('some_param');
第二に、配列コンテキストで、パラメータ名を指定せずに呼び出した時に、param()は現在あるパラメータをすべて含む配列を返します:
my @all_params = $webapp->param();
param()メソッドでは、ハッシュ(またはハッシュ・リファレンス)を渡すことで、一群のパラメータを一度に設定することも可能です:
$webapp->param( 'key1' => 'val1', 'key2' => 'val2', 'key3' => 'val3', );
param()メソッドは、一つのインスタンスをベースとしたカスタマイズ可能なアプリケーションという、非常に価値の高いシステムを可能にします。一つのモジュールが、いくつものインスタンス・スクリプトからインスタンス化されるでしょう。個々のインスタンス・スクリプトは、一連のパラメータにそれぞれ異なる値の設定するかもしれません。これは、よく似たアプリケーション間で共通のコード・ベースを共有しますが、異なる動作をするということが可能になります。
これにより、よく似たアプリケーション間では共通のコード・ベースを使いながら、しかし異なる振る舞いをするということが可能になります。例えば、一つのアプリケーションモジュールで、しかし複数のインスタンス・スクリプトがあるような、メール・フォーム・アプリケーションを想像してみてください。各インスタンス・スクリプトでは、別々の受信者を指定するでしょう。もう一つ、掲示板システムの例を挙げましょう。それぞれは別々のトピックと管理者がいる、複数の掲示板が設置されることがあるでしょう。
new()メソッドはいくつもの実行時パラメータを一度に指定するためのショートカットを提供します。内部的には、CGI::Applicationはこれらのプロパティをセットするために、param()メソッドを呼び出します。param()メソッドはアプリケーションの再利用性をすばらしく高めるパワフルなツールです。
prerun_mode()
$webapp->prerun_mode('new_run_mode');
prerun_mode()メソッドは、cgiapp_prerun()メソッド内で、実行されようとしている実行モードを変更するのに使われるアクセサ/ミューテータです。例えば、これを検討してみます:
# WebApp.pmの内容: package WebApp; use base 'CGI::Application'; sub cgiapp_prerun { my $self = shift; # もしあれば、Webユーザ名を取得 my $q = $self->query(); my $user = $q->remote_user(); # 必要であれば、loginへリダイレクト unless ($user) { $self->prerun_mode('login'); } }
この例では、Webユーザーは既にログインしているのでなければ、``login''実行モードを強制されます。prerun_mode()メソッドにより、実行モードが何であったとしても、スカラ・テキスト文字列でオーバーライドすることが許されます。
prerun_mode()をcgiapp_prerun()内で使うことは、mode_param()でサブルーチン・リファレンスを介してコールバックを使うように設定することとは異なります。異なるというのは、cgiapp_prerun()はcgiapp_prerun()メソッド内で、実行モードを何らかのロジックに基づいて選択的に設定できるからです。mode_param()でのcall-back方式は、実行モードを決定するためのCGI::Applicationのメカニズムを、独自のメソッドで完全に置き換えることを強制します。prerun_mode()メソッドは、CGI::Applicationの通常の実行モード切替方式を使いたいという時にも、そうではなく特定の条件化でモードを選択的に切り替えられるようにしたいというときにも使えます。
注意: prerun_mode()は、cgiapp_prerun()メソッドのコンテキスト内で *のみ* 呼び出されるべきです。setup()や実行モードメソッドなど、そのほかの箇所でprerun_mode()が呼び出されれば、アプリケーションはdie()してしまうでしょう。
query()
my $q = $webapp->query(); my $remote_user = $q->remote_user();
このメソッドは、アプリケーションモジュールのインスタンス化の際に生成されているCGI.pmクエリ・オブジェクトを取得します。クエリ・オブジェクトの使い方の詳細については、CGIを参照してください。CGI::ApplicationはCGIモジュール上で組み立てられています。一般的に言って、フォームデータを介して対話する時にはクエリ・オブジェクトを使用するでしょうから、CGI.pmとは特に親密になりたいと思うでしょう。
new()メソッドが呼ばれると、CGIクエリ・オブジェクトは自動的に生成されます。もし、何らかの理由で、独自のCGIクエリ・オブジェクトを使いたいと思ったら、new()メソッドはコンストラクト時のQUERY引数により、既存のクエリ・オブジェクトの受け渡しをサポートしています。
run_modes()
# 共通的な使い方:性格にサブルーチン名にマッチするモード名の配列リファレンス $webapp->run_modes([qw/ form_display form_process /]);
# ハッシュ・リファレンスで、異なる名前またはコード・リファレンスを使用 $webapp->run_modes( 'mode1' => 'some_sub_by_name', 'mode2' => \&some_other_sub_by_ref );
このアクセサ/ミューテータは、上の例のような記法を使い、アプリケーション状態のディスパッチ・テーブルを指定します。ディスパッチ・テーブルがハッシュとして返されます。
run_modes()メソッドは一度だけ呼ばれることになるでしょう。追加する値がrun_modes()に渡されれば、実行モード・テーブルに追加されます。既存の実行モードが再定義された場合、新しい値が既存の値をオーバーライドします。この振舞いは、アプリケーションが別のアプリケーションから継承して作られた場合や、ユーザ入力に基づいて発揮する能力を変更するより進んだアプリケーションの場合には有用でしょう。
run()メソッドは、mode_param()で指定されたCGIパラメータ(デフォルトでは``Run Mode''の'rm')を読み込み、アプリケーションをどの関数に送ればよいのかを決めるのに、このテーブルのデータを使います。これらの関数は``実行モード・メソッド(run mode methods)''として参照されます。
このメソッドでのテーブル・セットのハッシュには、モード名がキーとして含まれていることが期待されます。この値は、アプリケーションがその実行モードに入った時に呼び出されてほしい実行モード・メソッドのハード・リファレンス(サブルーチンのリファレンス)か、呼び出されてほしい実行モード・メソッドの名前のどちらかでなければなりません:
'mode_name_by_ref' => \&mode_function 'mode_name_by_name' => 'mode_function'
指定された実行モード・メソッドは、そのままWebブラウザに送り返せるようなテキスト・ブロック(例:HTML)を返すことが期待されます。実行モード・メソッドはそのテキスト・ブロックを、スカラで返してもスカラ・リファレンスで返しても構いません。
リファレンスの代わりに名前で実行モード・メソッドを指定することの有利な点は、継承を使ってより簡単に配布アプリケーションを作成できることです。例えば、既存のアプリケーションと一つの実行モードが異なるだけで後はまったく同じ新しいアプリケーションがあるならば、シンプルにそのアプリケーションを継承して異なる実行モード・メソッドだけをオーバーライドすることができます。
名前の代わりにリファレンス名前で実行モード・メソッドを指定することの有利な点は、パフォーマンスです。サブルーチン・リファレンスのデリファレンスは、コード・ブロックをeval()するより高速です。もし実行時のパフォーマンスがクリティカルな要件であれば、実行モード・メソッドは名前ではなく、リファレンスで指定してください。とは言え、総体的にはこの速度の差は小さなもので、したがって名前で指定するのが良いでしょう。
配列リファレンスでの実行モードの指定です: Specifying the run modes by array reference:
$webapp->run_modes([ 'mode1', 'mode2', 'mode3' ]);
これは、キーと値が同じハッシュを使うのと同じことです
$webapp->run_modes( 'mode1' => 'mode1', 'mode2' => 'mode2', 'mode3' => 'mode3' );
これはしばしば、メソッドと同じ名前に関連付けられた実行モード・マップを持つための、良い関連付けの考え方になります。配列リファレンス・インターフェースは、こうした振る舞いへのショートカットを提供し、コードのくどさを軽減します。
ハッシュか配列リファレンスのどちらかで実行モードを指定することのもう一つの重要性は、ここで示されたPerlメソッドだけがアプリケーションを通じて呼び出されても良いことを保障するものであることに、注意してください。許容メソッドを指定せず、他をすべて禁止するということをしないアプリケーション環境は不安定で、任意のコードの実行の許可というドアを開ける可能性を潜在させています。
CGI::Applicationは厳密にすべてのメソッドの起動を``デフォルトでは禁止''のスタンスでメンテナンスされ、これによりこの上ではアプリケーションの作成を可能にします。
IMPORTANT NOTE ABOUT RUN MODE METHODS
アプリケーションから標準出力(STDOUT)へのprint()は *絶対に* しないでください。(HTTPヘッダを含む)アウトプットの標準出力へ送出するためのprint()は、継承されたrun()メソッドの完全な専権事項です。このルールを破ることはエラーの共通的な原因になります。もしプログラムがHTTPヘッダの前にコンテンツを送るような誤りをしているなら、おそらくこのルールが破られているでしょう。
THE RUN MODE OF LAST RESORT: ``AUTOLOAD''
CGI::Applicationが存在しない実行モードに進むように頼まれると、これは通常はエラーとともにcroak()します。 これが期待する動作と異なるのであれば、``AUTOLOAD''という予約された名前の実行モードを実装することで、例外を捕まえることができます:
$self->run_modes( "AUTOLOAD" => \&catch_my_exception );
CGI::Applicationはcroak()を呼ぶ前に、``AUTOLOAD''と呼ばれる実行モードがあるか確認します。 これが指定されていれば、この実行モードが、一つの例外を除いて通常の実行モードのように実行されます:これは、唯一の引数として、これを呼び出した実行モード名を受け取ります:
sub catch_my_exception { my $self = shift; my $intended_runmode = shift; my $output = "Looking for '$intended_runmode', but found 'AUTOLOAD' instead"; return $output; }
この機能は、単に人が読みやすいエラー画面のために、あるいはより洗練されたアプリケーションの挙動のために利用できるでしょう。
start_mode()
$webapp->start_mode('mode1');
start_modeにはrun_modes()テーブルで指定されているモード名が含まれます。デフォルトのモードは``start''です。mode_param()で指定したCGIフォーム・パラメータの値が未定義の時には、常にこの値が使用されます。一般に、これはアプリケーションの初回実行時です。
tmpl_path()
$webapp->tmpl_path('/path/to/some/templates/');
このアクセサ/ミューテータ・メソッドはテンプレートがおかれているディレクトリ(またはディレクトリ群)のファイルパスを設定します。これはload_tmpl()で、HTML::Templateのpathオプションを使って、テンプレート・ファイルを検索するのに使われます。パスの設定では、テキスト・スカラを渡すことも、複数のパスの配列リファレンスを渡すこともできます。
CGI::Applicationに組み込まれた試験方法論というのはありませんが、しかしすべてを負わせるというわけではありません。Perlモジュールの試験に利用できる、たくさんの試験機構やフレームワークがあります(例えば、Test::Harness、Test::More)。生のWebアプリケーションの試験に利用できるツールやフレームワークも多数あります(WWW::Mechanize、HTTP::Test、Apache::Test)。CPANを見て周り、必要性にあった最善のものを見つけることをお勧めします。
モジュールレベルでの試験フレームワークの大半は特定のフォーマットでアウトプットが標準出力(STDOUT)に送られてくることを要求し、またCGI::Applicationが実行モードからの出力を直接標準出力に出すので、問題が起こります。これを避けるには、単に環境変数'CGI_APP_RETURN_ONLY'を真に設定すれば、出力を捕まえ、独自のメッセージを標準出力に出すことができます。例えば
$ENV{CGI_APP_RETURN_ONLY} = 1; $output = $webapp->run(); #perform whatever test on the output that you want and then print to STDOUT if($output =~ /GOOD/){ print "ok 11\n"; } else { print "not ok 11\n"; }
CGI::Applicationにはこれ用のプラグインを簡単に使え、簡単に開発できるプラグイン・アーキテクチャがあります。
以下のCGI::Application用に既に開発されているプラグインがあります。 現時点での全リストは、CPANを確認してください:
http://search.cpan.org/search?m=dist&q=CGI%2DApplication%2DPlugin
CGI::Application::Plugin::AnyTemplate - CGI::Applicationでさまざまなテンプレートを統一されたインターフェースで使用
CGI::Application::Plugin::Apache - Apache::*モジュールを干渉なく使用
CGI::Application::Plugin::AutoRunmode - runmodesの自動登録
Config::Autoの統合
Config::Contextの統合
Config::Generalの統合
Config::Simpleの統合
CGI::Application::Plugin::CompressGzip - Gzip圧縮の追加
CGI::Application::Plugin::DBH - DBIの統合
HTML::FillInFormの統合
Log::Dispatchの統合
CGI::Sessionの統合
CGI::Application::Plugin::Stream - ブラウザへのストリームファイルの補助
CGI::Application::Plugin::TemplateRunner - 各画面ごとに異なるHTMLとコードを個別のファイルにもつASPスタイルでのコード構築を可能に
Template::Toolkitを使用
CGI::Application::Plugin::ValidateRM - Data::FormValidatorとHTML::FillInFormの統合
詳細な利用法については各プラグインを確認してください。
プラグインの書き方はシンプルです。 単純にまずパッケージを作成し、CGI::Applicationプロジェクトの一部にしたいメソッドをexportします。 例としては、CGI::Application::Plugin::ValidateRMを見てください。
CGI::Applicationとの名前空間の衝突を避ける必要があるので、プラグイン開発者は情報を保持する際に、プラグインパッケージなどのユニークなプレフィクスを使うことが推奨されます。例えば:
$app->{__PARAM} = 'foo'; # BAD!衝突するかも。 $app->{'MyPlugin::Module::__PARAM'} = 'foo'; # Good. $app->{'MyPlugin::Module'}{__PARAM} = 'foo'; # Good.
プラグインを書く際、データベース接続やセッションの初期化といった、それぞれのステージで自動的にアクションが起きてほしいと思うかもしれません。'callback'メソッドを使うと、それぞれのフェーズにサブルーチンを登録でき、この目的を達成できます。
Callback Examples
# 標準的なCGI::Applicationのフックへのコールバックの登録 # 'init'、'prerun'、'postrun'、'teardown'、'load_tmpl'の内の一つ # プラグイン作成者にとっておそらく唯一必要なメソッドです。 # Class-based: callback will persist for all runs of the application # クラス・ベース:コールバックはすべてのアプリケーション実行で持続します $class->add_callback('init', \&some_other_method); # オブジェクト・ベース:コールバックはこのオブジェクトのライフタイム内で終わります $self->add_callback('prerun', \&some_method); # アプリケーションで新しいフック箇所を作成するには、フックの作成と # 呼び出しのための、以下の二つのメソッドを知っておく必要があります。 # 新しいフックを作成 $self->new_hook('pretemplate'); # その後、このフックに登録されているすべてのコールバックを実行 $self->call_hook('pretemplate');
コールバック・メソッド
$self->add_callback ('teardown', \&callback); $class->add_callback('teardown', 'method');
add_callbackメソッドにより、与えられた実行ステージで呼び出されるように、コールバック関数を登録することが可能です。
正しいフックには'init'、'prerun'、'postrun'および'teardown'、'load_tmpl'、そしてnew_hookメソッドで定義したその他のフックが含まれます。
コールバックはサブルーチンへのリファレンスか、メソッド名です。
一つのフックに複数のコールバックを追加することができ、それらは次々に、すべて実行されます。
正確な順序は、コールバックの順序に説明されているように、各コールバックにどのクラスがインストールされているかによります。
コールバックは、add_callbackをオブジェクト・メソッドとして呼ぶか、クラス・メソッドとして呼ぶかによって、オブジェクトベースにもclass-basedクラスベースにもできます:
# オブジェクト・ベースのコールバックの追加 $self->add_callback('teardown', \&callback);
# クラス・ベースのコールバックの追加 $class->add_callback('teardown', \&callback); My::Project->add_callback('teardown', \&callback);
オブジェクト・ベースのコールバックはWebアプリケーションの$selfオブジェクトで保持されます;$selfオブジェクトが消えるこのリクエストの終了時に、コールバックも消えます。
オブジェクト・ベースのコールバックは、現在動作しているアプリケーションに対する一回限りの適用に便利です。例えば、現在のリクエストの最後、HTMLがすべてブラウザに送信された後で、長時間かかるプロセスが行われるように、teardownコールバックを導入することができます。
クラス・ベースのコールバックは、Perlプロセスが走っている間は生き残ります。(mod_perlやPersistentPerlといった永続化環境では、一つのPerlプロセスが多くのWebリクエストを捌きます。)
クラス・ベースのコールバックは、すべてのWebアプリケーションに対して機能追加するようなプラグインにとって有用です。
クラス・ベースのコールバックのもう一つの特徴は、プラグインがいつでも‐Webアプリケーションの$selfオブジェクトが初期化される前であっても‐フックを作成したりコールバックを追加できることです。
これを行うのに適した箇所は、プラグインのimportサブルーチンです:
package CGI::Application::Plugin::MyPlugin; use base 'Exporter'; sub import { my $caller = scalar(caller); $caller->add_callback('init', 'my_setup'); goto &Exporter::import; }
$caller->add_callbackは次のラインに含まれているモジュールを代表してコールバックをインストールするのだということに注意してください:
use CGI::Application::Plugin::MyPlugin;
new_hook(HOOK)
$self->new_hook('pretemplate');
new_hook()メソッドはコールバックを登録できる新しい箇所を作成するために使えます。これは一つの引数、フック名を取ります。既に存在していなければ、このフック箇所が作成されます。常に、真の値が返されます。
例えば、CGI::Application::Plugin::TTはすべてのテンプレートプロセスの前後にフックを追加します。
どのようにフックが呼び出されるのかの詳細は、call_hook(HOOK)を見てください。
call_hook(HOOK)
$self->call_hook('pretemplate', @args);
call_hookは与えられたフックに登録されているコールバックを実行するために使われます。これは新しいフック箇所の作成を可能にするnew_hookと組み合わせて使用されます。
call_hookの最初の引数はフック名です。残りの引数は全て、このフック箇所で実行されるそれぞれのコールバックに渡されます。
したがって、'pretemplate'フックでのコールバックのための部分はこのようになるでしょう:
sub my_hook { my ($self,@args) = @_; # .... }
このフックは半ば公然の箇所にあることに注意してください。フックの呼び出しは、このフックに現在のオブジェクトから登録されたコールバックと、それから現在のオブジェクトの親クラスから登録されたコールバックの実行を意味します。正確な順序については、以下を見てください。
コールバックの順序
オブジェクト・ベースのコールバックは、クラス・ベースのコールバックより先に実行されます。
クラス・ベースのコールバックの順序は、実行中のアプリケーションの継承ツリーから決定されます。
cgiapp_init、cgiapp_prerun、cgiapp_postrun、そしてteardownの組込みメソッドはこの方法で、以下の順序に従って実行されます。
永続化環境では、同時に非常に多くのアプリケーションがメモリ上にあるでしょう。例えば:
CGI::Application
Other::Project # CGI::Application::Plugin::Bazを使用
Other::App # CGI::Application::Plugin::Bamを使用
My::Project # CGI::Application::Plugin::Fooを使用
My::App # CGI::Application::Plugin::Barを使用
上記のプラグインがそれぞれ'init'ステージで起動されるコールバックを追加したと想像してみてください:
プラグイン initコールバック ---------- ---------------- CGI::Application::Plugin::Baz baz_startup CGI::Application::Plugin::Bam bam_startup CGI::Application::Plugin::Foo foo_startup CGI::Application::Plugin::Bar bar_startup
My::Appが実行されたときは、foo_callbackとbar_callbackだけが走ります。その他のコールバックはスキップされます。
My::Appの@ISAリストは:
My::App My::Project CGI::Application
この順序がコールバックが走らされる順序を決定します。
My::Appアプリケーション上でcall_hook('init')が実行されると、これらのモジュールによって導入されたコールバックがこの順序で起動され、次の結果になります:bar_startup、foo_startup、そして最後にcgiapp_init
もし一つのクラスが複数のコールバックを同じフックに導入した場合、これらのコールバックが登録された順で走らされます(FIFO)。
CGI::Applicationについてさらに学びたい、あるいはこれについて他の人と議論したいという人が利用できる主要なリソースを挙げます。
Wiki
コミュニティが作り上げ、メンテナンスしており、誰の貢献をも歓迎するリソースです。 ここには自前の多くの記事と、CGI::Applicationに関連した多くのページへのリンクがあります:
サポート・メーリング・リスト
何か質問やコメント、バグレポートや機能の提案などがあれば、サポート・メーリング・リストに投稿してください!メーリング・リストへの参加は、``cgiapp-subscribe@lists.erlbaum.net''に空のメッセージを送信するだけです。
IRC
irc.perl.orgの#cgiappに立ち寄ると、プロジェクトに関わっている人を見つける良いチャンスがあるでしょう。
CGI
HTML::Template
CGI::Application::Framework - A full-featured web application based on CGI::Application. http://www.cafweb.org/
Jesse Erlbaum <jesse@erlbaum.net>
多数の貢献者の援助がChangesファイルに記録されている中、Mark StosbergはVersion 3.2から副メンテナの役を果たしています。
その他の読み物
もし、CGI::Applicationをより多くのことを発見したいと思ったなら、以下の記事がPerl.comにあります:
Using CGI::Application http://www.perl.com/pub/a/2001/06/05/cgi.html
Simon CozensとO'Reilly networkには、この記事を発行してくれたこと、そしてそれがPerlコミュニティにもたらす計り知れない価値に感謝します!
CGI::Applicationは、New York Cityのソフトウェア・エンジニアリングおよびコンサルティング・ファームであるErlbaumグループによって開発されました。もし自分たちのWebサイトを開発してくれる会社、あるいは自分たちのチームに追加するために個人開発者を探しているようであれば、ご一報ください:
The Erlbaum Group, LLC 826 Broadway, Suite 933 New York, NY 10003 Phone: 212-684-6161 Fax: 212-684-6226 Email: info@erlbaum.net Web: http://www.erlbaum.net
このライブラリの初期開発を支え、これを世界に向けてリリースするように勧めてくれたVanguard Media (http://www.vm.com) に感謝します。
何年もに渡る彼の無数の貢献と、ついにはこれをCPANにもって行こうと腰を上げさせてくれたことについて、(最も優れたHTML::Templateモジュールの作成者でもある)Sam Tregarには非常に感謝します。
多くの人が示唆を与え、あるいはパッチを送って貢献してくれており、それらがChangesファイルに記録されています。
CGI-Appメーリング・リストのみんなにも感謝を!あなたたちのアイディア、示唆、洞察(そして酷評!)このモジュールを限りなく研ぎ澄まされたものにしてくれました。(このメーリング・リストに加わるには、空のメッセージを``cgiapp-subscribe@lists.erlbaum.net''に送るだけです。)
CGI::Application : Framework for building reusable web-applications Copyright (C) 2000-2003 Jesse Erlbaum <jesse@erlbaum.net>
This module is free software; you can redistribute it and/or modify it under the terms of either:
a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version,
or
b) the ``Artistic License'' which comes with this module.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the Artistic License for more details.
You should have received a copy of the Artistic License with this module, in the file ARTISTIC. If not, I'll be glad to provide one.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Makio Tsukamoto, tsukamoto@gmail.com