今日のCPANモジュール
use App::Options;
コマンドライン型プログラムで、引数を受け取る部分の話題です。たとえば、
hoge.pl --name="Tomita Naoki" --age=28 --debug
というように引数を指定した場合、プログラム側では name が "Tomita Naoki"、debug は true というように受け取りたいわけです。
受け取るだけじゃなく、こんな要件もあろうかと思います。
- name と age は必須にしたい
- age は数字だけ受け取れるように
- name のデフォルト値は Unknown に
- --help が指定された場合は Usage を表示して終わる
GetOptions + pod2usage を使う方法
このとき、よく使われて、かつ悪くないのは、Getopt::Long と Pod::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}.\n";
=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}.\n";
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 という引数にはコマンドラインから取得するキーと、その値の条件を書いていきます。条件は、セミコロンで区切って以下のような各種指示を書けます。
type=...;として、例で使った string、integer、boolean 以外に、float、date(YYYY-MM-DD形式)、time(HH:MM:SS形式)、datetime(YYYY-MM-DD HH:MM:SS形式)が選べます。日付系は便利です。それ以外の場合は、use App::Options( option => { gender => 'type=/^(male|female)$/; required;', }, );と正規表現で指定したりできます。
required;もしくはrequired=1;で「必須」です。default=...;にデフォルトの値を指定できます。env=...;というのもあって、コマンドライン引数じゃなく任意の環境変数から値をとるようにする指示を書けます、これも便利なのですが、環境変数の話をまだしてなかったので後で説明します。
使うのは こんなとこですが、ほかのもあげると、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}.\n";
短縮化を進むなら %ARGV を使うのもおすすめです。%ARGV は Perl が使う変数ではありませんが、@ARGV などが予約されている関係で、use strict; 下でも my とか our 宣言しないで使える抜け道です。
use App::Options (
values => \%ARGV,
);
print "Hello $ARGV{name}.\n";
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 の値でどちらかを選ぶ、などが実装されています。
最近は YAML で設定を書くことが多いので、ぼくはこの機能はほとんど使わず、App::Options を引数の処理だけに使うことが多いです。メンテナーの Stephen に聞いたところ、将来 ini 形式だけじゃなくて、YAML などに対応する予定もあるよ、ということだったので、期待してます。
SEE ALSO
App::Options, Getopt::Long, Pod::Usage
Getopt::Casual, Getopt::Euclid, Scriptalicious, Script::Toolbox, Getopt::Auto, App::CLI
WRITTEN BY
冨田 尚樹 <tomita@cpan.org>