今日のCPANモジュール(跡地)

宣伝と注意書き

このサイトが元になったCPANモジュールガイドという本を書きました。

本ではコマンドラインオプションを取るモジュールとしてはGetopt::Longを紹介しています。App::Optionsについては、設定ファイルや環境変数からも複合的に設定を取得できるモジュールとして紹介しています。

2007-02-08

use App::Options;

コマンドライン型プログラムで、引数を受け取る部分の話題です。たとえば、

hoge.pl --name="Tomita Naoki" --age=28 --debug

というように引数を指定した場合、プログラム側では name が "Tomita Naoki"、debug は true というように受け取りたいわけです。

受け取るだけじゃなく、こんな要件もあろうかと思います。

GetOptions + pod2usage を使う方法

このとき、よく使われて、かつ悪くないのは、Getopt::LongPod::Usage の組み合わせです。Getopt::Long まわりは幾つかの書き方がありますが、こんな感じです。

use Getopt::Long;
use Pod::Usage;

my %argv = (
    name => 'Unknown',
    age  => '',
);

GetOptions(
    \%argv,
    "name=s",
    "age=i",
    "debug",
    "help",
) or $argv{help}++;

pod2usage(2) if $argv{help};

# 処理...
print "Hello $argv{name}";

=head1 SYNOPSIS

使い方...

=cut

この GetOptions + pod2usage の組み合わせがいいのは、両方ともコアモジュールだという点です。しかし、CPAN には上記例をもっと簡単便利に書けるモジュールが超たくさんあります。

App::Options を使う方法

中でもぼくのお気に入りは App::Options です。
これだと上の例がこうなります。

use App::Options(
    option => {
        name  => "type=string; required; default=Unknown;",
        age   => "type=integer;",
        debug => "type=boolean",
    },
);

# 値は %App::options ハッシュの中に入ります
print "Hello $App::options{name}";

use 文の中ですべてまとまっていることや、シンプルで直感的なのでお気に入りです。

いちおうほかの引数取得系モジュールで琴線にふれたものをメルマガの最後の SEE ALSO に並べておきますので、以下の説明で App::Options にひかれない人は別なのも見てみてください。

賢いのが自動 Usege 機能で、特に指示しなくても --help の時や必須条件をクリアしなかった場合に自動で Usage を表示してくれます。

> test.pl --age="twenty eight" --name=Tomita

Error: "age" must be of type "integer" (not "twenty eight")
Usage: test.pl [options] [args]
       --help                             print this message (also -?)
       --age=<value>                      [twenty eight] (integer)
       --debug                            [undef] (boolean)
       --name=<value>                     [Tomita] (string)

お気に入りなのですが、日本語での説明を見かけないモジュールなので、少し詳しく解説していきます。

option =>

use App::Options に渡す option という引数にはコマンドラインから取得するキーと、その値の条件を書いていきます。条件は、セミコロンで区切って以下のような各種指示を書けます。

使うのは こんなとこですが、ほかのもあげると、description=...;value_description=...; を指示すると、自動 Usage 表記をカスタマイズできます。セミコロン区切りの文字列ではなく、ハッシュで渡すこともできます。

use App::Options(
    option => {
        name => {
            type => 'string',
            required => 1,
            default => 'Unknown',
        },
        age => {
            type => 'integer',
        },
    },
);

values =>

use App::Options のところで渡せるオプションには option 以外にいろいろあって、便利なのが values です。デフォルトだと App::Options は %App::options ハッシュ(oが小文字なのに注意)に値を入れていきますが、これを変えることができます。`$App::options{なんとか}" だとちょっと長い?ということでそれを短い %argv にしたい場合はこうです。

my %argv;
use App::Options (
    values => \%argv,
    option => {
        name  => "type=string;",
    },
);

# $App::options{name} ではなく、
print "Hello $argv{name}";

短縮化を進むなら %ARGV を使うのもおすすめです。%ARGV は Perl が使う変数ではありませんが、@ARGV などが予約されている関係で、use strict; 下でも my とか our 宣言しないで使える抜け道です。

use App::Options (
    values => \%ARGV,
);

print "Hello $ARGV{name}";

print_usage =>

App::Options の自動 Usage が気に入らない場合は、print_usage にサブルーチンを渡すことで置き換えることができます。例えばヘルプは Pod::Usage を使って POD の SYNOPSIS を出したいよ、という場合は以下のようにします。

use Pod::Usage;
use App::Options (
    print_usage => sub { pod2usage(2) },
);

=head1 SYNOPSIS

test.pl --date=2006-02-28

brah brah brah brah brah brah...

=cut

App::Options の自動 Usage 出したいよ、という場合にはデフォルトのも呼び出せばいいです。

use Pod::Usage;
use App::Options (
    values => \%ARGV,
    option => {
        debug => "type=date",
    },
    print_usage => sub { 
        App::Options->print_usage(@_);
        pod2usage(2);
    },
);

=head1 SYNOPSIS

test.pl --date=2006-02-28

brah brah brah brah brah brah...

=cut

さて、書くのが疲れてきました。くわしくは POD を眺めるとだいたいわかると思うのででそろそろ終わりにします。(POD = Perl のソースコード内に書かれるドキュメント形式。ドキュメントという意味で使われることも。)

デフォルトで行われる処理

ただ、App::Options はただ引数処理をするだけではなく、もっと大きな野望をもったモジュールだ、というのを覚えておく必要があります。それがゆえに、ただ引数を取りたいという目的だけだとちょっと余計とも思える動作をします。

App:: というかっこいい名前空間は、P5EE - Perl 5 Enterprise Environment Project で使われていて、大規模なアプリケーション用モジュールを見越したモジュール用とされています。App::Options もそのファミリーであり、いろいろ考えているわけです。どうもP5EE プロジェクトそのものはあまり盛り上がっていないように見えますが、ストップしているわけではありませんし、複数メンバーで全体を見ているようなので、わりと安心して使い続けられます。

まず、コマンドラインで指定しなくても、app, host, prefix, hostname というキーが自動的に設定されます。たとえば app には、ファイル名が test.pl の場合、test という値が入ります。

さらに実は App::Options は、コマンドラインからの引数と環境変数からの値と ini 形式のファイルからの値をブレンドするという機能があり、それが自動で働きます。(no_env_vars => 1;no_option_file => 1; を use App::Options に渡すことでそちらは無視させることが可能)

環境変数は、APP_なんとか に値を指定しておくと、「--なんとか」の代わりとして使えます。あと option の env 指示でまったく別な環境変数を読ませることもできます。

ini 形式のファイルを読む機能はなかなか高度で、この順番で設定ファイルを探す機能や、プロダクション環境用とステージング環境用の値を書いておいて、app の値でどちらかを選ぶ、などが実装されています。