Perl Hackers Hub

第45回 Perlで作るコマンドラインツール―オプション,サブコマンド,設定ファイルへの対応(2)

この記事を読むのに必要な時間:およそ 3 分

前回の(1)こちらから。

設定ファイルの利用

ここでは,Perlを使って設定ファイルの読み込みを行う手法について紹介していきます。

設定ファイルはなぜ必要か

コマンドラインツールでは,実行するたびに変わってくるものがあります。たとえば実行結果をメールで送信するツールなら,メールアドレスは実行ユーザーごとに変わりますし,同じユーザーでも常用しているメールアドレスが変更になった場合は変える必要があります。ファイルを変換するツールなら,どのファイルを変換するのかやファイルの保存場所が毎回変わります。こういった値は,コードに直接書くのではなく,設定値としてプログラムの外部から渡せるようになっているのが良いプログラムです。

設定値を渡す方法として,すでにコマンドライン引数を使ってオプションを渡す方法を説明しました。これは標準的な方法でユーザーも使い慣れているためわかりやすいのですが,多数の設定項目があったり,それらの項目の組み合わせを複数セット使い分けたりする必要がある場合,煩雑になります。

それに対して設定値を設定ファイルとして持つようにすると,設定値の確認や編集をテキストエディタで行えます。また,よく使う設定値のパターンを複数のファイルとして用意しておけば,設定ファイルを切り替えるだけでコマンドラインツールの動作を変えられます。作っているコマンドラインツールの設定項目が多くなってきたと感じたら,設定ファイルを使った動作設定を行えるようにすることを検討するとよいでしょう。

設定ファイルの形式

Perlで書かれたコマンドラインツールの設定ファイルには,JSONやYAMLYAML Ain't Markup Languageなどの広く使用されている形式の文書ファイルを使うのが一般的です。また,Perlのコードそのものを設定ファイルとして使う手法も,手軽かつ強力です。よく使われる形式を表1にまとめました。

表1設定ファイルによく使われる形式

形式特徴
JSONプログラムによる解釈が簡単。人間が読みづらくなる場合がある
YAMLインデントといくつかの記号で構造を表す。比較的人間が読みやすい
TOMLシンプルな記法。複雑な構造の記述には向いていない
PerlPerlコードそのもの。データの表現力は高いがPerlコードを書ける人でないと使えない

Perlコードを設定ファイルとして使う方法

Perlコードを設定ファイルとして使う場合,設定ファイル内では,Perlのプログラムでハッシュリファレンスを定義します。

config.pl

+{
    dbi => ["dbi:mysql:database=foo", "user", "pass"],
    filepath => '/path/to/file',
};

設定ファイルを利用するプログラムでは,次のように記述して設定ファイルを読み込みます。

my $config = do 'config.pl';

$config->{filepath}
# => /path/to/file

Perlコードを設定ファイルとして使う利点は,読み込む側で依存モジュールを必要としないことと,記述力の高さにあります。設定ファイルがPerlのプログラムですので,ループや分岐で設定値を組み立て/変更したり,環境変数を使ったりも自在です。

my $conf = {
    path => '/path/',
};

# 分岐と環境変数の利用
if ($ENV{TEST}) {
    $conf->{debug} = 1;
}
$conf;

ただし逆に言えば,なんでもできすぎて危険な処理を設定ファイル内で実行される可能性があります。また,プログラマーではないユーザーが設定ファイルを作成/編集するのは難しいでしょう。そのため,小規模かつプログラマーが運用するコマンドラインツールに向いていると言えそうです。

JSON/YAML/TOMLを設定ファイルとして使う方法

設定ファイルとして何らかの記法で記述されたファイルを使う場合,対応するモジュールを使用します。JSON,YAMLなど,たいていの記法には同名のCPANモジュールが存在しています。

例として,コマンドライン引数で渡したファイル名のJSONファイルを読み込むプログラムを示します。

read_json.pl

my $opt = Smart::Options->new
       ->coerce('File' => 'Str', sub { path($_[0]) })
       ->type('conf' => 'File')->parse();

unless ($opt->{conf}) {
    my $default_conf = +{
        file => '/path/to/file',
        rows => 10,
    };
    path('.config')->spew(encode_json($default_conf));
    print "write default config => .config\n";
    exit;
}

my $config = decode_json($opt->{conf}->slurp());

# 以下,コマンドラインツールの実際の処理

このコードでは,コマンドライン引数でconfオプションが指定されなかった場合,.configという名前で設定ファイルを作成し,その旨を表示してプログラムを終了します。このように,設定ファイルの指定なしにプログラムを起動したら,所定の場所に初期値を埋めた設定ファイルのひな型を出力する機能が付いていると親切です。

コメント

コメントの記入