Akihiro's Programmer Blog

Technology Notes for Personal

Amon2の流れを掴む - 3


前回の続きから。


script/sample-server

unless (caller) {

...

}

 unlessの条件として caller が呼ばれています。

 callerはperlの組み込み関数の1つで、サブルーチンの呼び出し元情報を取得出来ます。

 詳しくはここを参照です。

 ログを取る時とかに便利です。

 で、今回の場合は呼び出しているのがサブルーチンの中ではないので、undefを返します。

 つまり、 「外部から呼ばれた場合はブロック内を無視する」という意味です。

 unlessはifの条件を反転したものなので、偽ならばブロック内を処理します。


my $port        = 5000;
my $host        = '127.0.0.1';
my $max_workers = 4;

 まず始めに、 port番号・ホスト名・プリフォークするプロセス数 を定義しています。

 これがデフォルト値ですね。


require Getopt::Long;

  Getopt::Long は、コマンドラインオプションを解析して良い感じに引数を取ってきてくれるモジュールです。


require Plack::Loader;

  Plack::Loader は、指定したオプションに基づいた Plack::Handerインスタンスを得られます。

  Plack::Handler は、psgiアプリケーションWebサーバを結びつけるアダプターの役割を持ちます。


my $p = Getopt::Long::Parser->new(
    config => [qw(posix_default no_ignore_case auto_help)]
);

 ここではGetopt::Longのオプション指定をしています。

 詳しくはこちらを参照のこと。

 簡単に説明すると以下のような感じ。

オプション 意味
posix_default 色々余計な機能をOFFにしてくれる。
no_ignore_case オプションの大文字小文字を区別する。
auto_help 自動で--helpが使えるようになる。pod2usageを呼んでくれる。


$p->getoptions(
    'p|port=i'      => \$port,
    'host=s'        => \$host,
    'max-workers=i' => \$max_workers,
    'version!'      => \my $version,
    'c|config=s'    => \my $config_file,
);

 早速オプションの指定と、引数の指定を行っています。

 順番に見て行くと、p|port=i-p--port をオプションに指定している。そして i は数値を引数とすることを表している。その引数を $port に格納する、という感じです。

 2つ目は --host をオプションとして、s は文字列を引数に指定しています。

 3つ目も同様。

 4つ目の ! は否定を表すオプションを定義している。この場合、 --noversion と指定してやれば、 $version を0に出来ます。(でも、ここのオプション指定の意義がよく分からない。。。)

 5つ目も同じようなことをやっています。


if ($config_file) {
    my $config = do $config_file;
    Carp::croak("$config_file: $@") if $@;
    Carp::croak("$config_file: $!") unless defined $config;
    unless ( ref($config) eq 'HASH' ) {
        Carp::croak("$config_file does not return HashRef.");
    }
    no warnings 'redefine';
    no warnings 'once';
    *sample::load_config = sub { $config }
}

 このブロック内はオプション -c または --config にファイル名を指定すると実行されます。

 ここで言うコンフィグファイルは、sample/config/ 以下にある development.pl 等が対象となっています。

 ではブロック内の処理を見て行きましょう。


my $config = do $config_file;

  do は指定したファイル名のファイルをperlスクリプトとして実行します。戻り値はそのスクリプトで最後に評価された値です。

 ですので、$config には sample/config/ 以下のファイルを見るに、 各種設定を表すハッシュリファレンス が入ることが想定されているようです。


Carp::croak("$config_file: $@") if $@;

  Carp::croakdie とほぼ同じ意味です。ただし、die は「dieが実行された位置番号」を知らせるのに対し、croak は「呼び出し元の位置情報」を知らせてくれます。

 また、ここで出てきている $@ は、doコンパイルに失敗した時にエラーメッセージを格納する特殊変数です。成功なら undef が返ってきます。

 (ここでcroak使う理由ってなんだろう? このスクリプト自体さっきの caller 云々で外部から呼び出せないはずだし。。。)


Carp::croak("$config_file: $!") unless defined $config;

 ここでは $configundef の場合に、croak が実行されます。

 croakの中の $! は、これまた do がファイルを読み取ることが出来ない場合にエラーメッセージが入ります。こちらも成功なら undef が返ります。


unless ( ref($config) eq 'HASH' ) {
    Carp::croak("$config_file does not return HashRef.");
}

 これはつまり、 「コンフィグファイルの戻り値はハッシュリファレンスじゃないとダメだよ」 ということです。


no warnings 'redefine';
no warnings 'once';
*sample::load_config = sub { $config }

 サブルーチン名の前に * を付けると、サブルーチンの再定義が出来ます。

 その際に、use warnings していると余計な警告が出るので、それを上の2行で抑制しています。

 意味は以下のような感じです。

コード 意味
no warnings 'redefine' 既に定義されているサブルーチンに対する上書きを警告する。
no warnings 'once' 一度しか呼ばれていない変数に対して警告する。


print "sample: http://${host}:${port}/\n";

 言わずもがな。


my $loader = Plack::Loader->load('Starlet',
    port        => $port,
    host        => $host,
    max_workers => $max_workers,
);

  Plack::Loaderload メソッドを呼んでいます。

 第一引数にハンドラ名を指定して、後の引数にはオプションを指定しています。


return $loader->run($app);

 そして最後に $loader のrunメソッド$app を 渡すと、アプリケーションがPSGIサーバとアプリケーションがコネクトされ、起動します。


return $app;

 最終行に書かれたこれは、おそらく外部からこのスクリプトが呼び出された場合に、 $app を返すためでしょう。

 これで plackup でこのスクリプトファイルを指定しても起動します。



 これで一先ずアプリケーションの起動部分までは把握出来ました。

 次は sample/lib/ 以下のPSGIアプリケーションを司るモジュール達を見て行きたいと思います。