任意の関数のDispatch

モジュールを CLI から起動した時に、渡された第一引数をサブコマンド として解釈する考えです。

package Foo;

sub hello { print "hello!\n" }
sub goodbye {print "goodbye!\n" }

unless (caller) {

  my $funcName = shift
    or die "function name is required!";

  my $func = __PACKAGE__->can($funcName)
    or die "No such function: $funcName";
  
  print Dumper($func->(@ARGV));
};1

この方式なら、任意の関数をコマンド行から呼び出すことが可能になります。

% ./Foo.pm hello
hello!
% ./Foo.pm goodbye
goodbye!
  • 関数に引数として HASH/ARRAY を渡したいケースもありえます。その場合は コマンド行引数に {...}[...] が渡されたときだけ、 JSON として decode する、というアプローチを取ることが可能でしょう。 TypeScript などではこの方法が上手くフィットしそうだと私は考えています。

    • その場合、 出力も JSON として encode しておけば、コマンド行を glue として関数同士を組み合わせることも可能になるでしょう。
  • この unless caller ブロック内のロジックを予め別のモジュールとして 準備しておけば、個々のモジュールにおける Modulino 化のコーディング負担は 極めて少なくなります。

  • 開発の最初期から、コマンド行から繰り返し関数を実データと共に呼び出すことが可能になります。その結果、関数名の良し悪しについて考え直す機会が増えます。

  • このようにコマンド行から呼びやすく設計した関数は、テストも容易になる傾向が あります。

この方法の短所

この方法では、

  • CLI から OOP のオブジェクトを一切扱えない(オブジェクトを扱う関数は、呼び出してもエラーになる)
  • サブコマンドを覚えるのが面倒、という考え方も有るかもしれません。
    ただ、これは shell の側で補完機能を用意出来れば、問題ではなくなるでしょう。

という弱点があります。これは現代の Perl プログラムにとっては かなり痛い制限です。