2015/12/05

俺の CLI コマンドの勘所2

[perl] [cpan] [cli]

このエントリーは Perl 5 Advent Calender 2015 の5日目の記事です。

3日の記事 から中一日で再び登場の bayashi です、こんにちわわわわー!

本日は、先日のエントリで書ききれなかった要素をいくらか書き足したいと思います。

Perl CLI ツールのテスト

CLI ツールをワンライナーではなくモジュールにして利用するメリットのひとつに、テストを書いて機能の追加や変更などの運用をきちんとしやすくなるという点があります。やっぱりテストは重要ですね。

exitコードのテスト

CLIコマンドは、時に exit するかと思います。そんな exit するコマンド実行パターンのテストは以下のように書いています(確か Text::Xslate のCLIツールのテストから拝借したまんま)。

https://github.com/bayashi/App-Randf/blob/master/t/01_basic.t

use Test::More;

my $command = 'script/randf';

# version
system(
    $^X, (map { "-I$_" } @INC),
    $command,
    '--version'
);
is $?, 256, '--version';

--help や invalid なオプションを渡した場合の exitコードをテストするなどにもいける。

標準入力のリダイレクトと標準出力のテスト

パイプで標準入力を受けつつ、標準出力に何か出すというコマンドのテストは以下のように書いている。標準出力を捕まえるのには Capture::Tiny 以外に Test::Output も便利。

https://github.com/bayashi/App-FromUnixtime/blob/master/t/01_basic.t

use App::FromUnixtime;
use Capture::Tiny qw/ capture /;
use Test::More;

open my $IN, '<', \<<'_INPUT_';
id          1
name        John
date        1419702037
_INPUT_

local *STDIN = *$IN;

my ($stdout, $strerr) = capture {
    App::FromUnixtime->run;
};
close $IN;

like $stdout, qr/date\s+1419702037\([^\)]+\)/;

特に CLI どうこうというより PerlIO の話の予感。

CLI ツールのあり方

さて、お仕事で Perl プロジェクトやってる方々におかれましてはプロジェクト依存の CLI ツールをたくさん書くと思います。しかし、そうしたツールはある程度の数になってくると管理が大変になってきませんか? このツールなにするやつだっけ!? あれするツールどれだっけ!? なんでこのツールは使い方ないんだよ!! テスト実行かと思ったらいきなり実行されたよ!!!! とか。開発者の数が増えるごとにあるあるだと思います。

というわけで、うちのプロジェクトではそのような問題を解決するために、CLI フレームワークみたいなものに押し込んでツールを書いています(そうじゃないのもありますが)。

たとえば、プロジェクトの一大統一コマンドとして project というものがあります。こいつは、サブコマンドへのルーティングだけを行います。なので、project とだけ叩くと、サブコマンド一覧が出ます。

$ project
db-user
db-item
memd-user
memd-item
logs

サブコマンドは、何も引数がなければ使い方が表示されます。必ずです。

$ project db-user
    project db-user USER_ID
        -f, --full  fetch relational information also

実装上は、Project::Script::Root などに親コマンドとルーティングを書いておき、Project::Script::SubCmd::* におかれたモジュールがコマンドとなって実行される感じです。たとえば、Project::Script::SubCmd::DbUser が project db-user として実行される。開発者は、Project::Script::SubCmd::* にモジュールを書けば良いだけ。

サブコマンド一覧は、.bashrc で補完が効くようにしておくと完璧です。

一般的なツールと違って、プロジェクトで利用する CLI ツール群はそれぞれ独立したものを書くより、このようなフレームワークに乗っけたものにしておいた方が運用面で楽ですね(といってこのやり方はまだいろいろ模索中ですが)。

というわけで、以上、俺の CLI コマンドの勘所2 でした。

明日は @karupanerura さんです!

Perl 5 Advent Calendar 2015 はまだまだ参加者募集中!!

サイト内検索