open()の改良
Perlのopen()をマスターするのは大変だ。perldoc perlfuncのopenの項はすさまじい長さだし,perldoc perlopentutというopenのチュートリアルも,単なるチュートリアルなにものすごく長い。しかもPerlIOという機能のおかげでopen()そのものも自由に拡張できる。さらに,5.6.0以降の拡張*1が煩雑さに拍車をかけている。
そこで,いくつかの欠点を克服するべく,open()のラッパーを考えてみた*2。
use Carp qw(croak); sub my_open{ if(@_ < 2){ croak('Usage: my_open($mode, @args)'); } my $anonio; unless(CORE::open $anonio, $_[0], @_[1..$#_]){ croak("Cannot open(@_): $!"); } return bless $anonio => 'IO::Handle'; }
これは以下のように使用する。
my $in = my_open('<', 'foo.txt'); my $out = my_open('>', 'foo.txt'); my $tee = my_open('>:tee', 'foo.txt', \$s, \*STDERR);
Perlのopen()と異なる点は以下の通り。
ファイルハンドルをシンボルではなく値として扱う
これはIO::Fileが提供する機能である。しかし後述するように,IO::Fileでは3つ以上の引数が扱えない。
3引数のopen()を強要する
2引数のopen()はファイル名の前に文字列としてモードを付加する。これはこれで便利な機能だが,通常は必要のない機能である。
3つ以上の引数を扱える
サンプルコードの:teeの例のように,Perのopen()は3つ以上の引数を受け付ける可能性がある。しかし,IO::Fileのnew()は透過的にsysopen()を使えるかわりに,3つ以上の引数のopen()を扱えない。
open()に失敗したときに致命的エラーを発生させる
open or dieというイディオムの必要がない。標準モジュールのFatalでも同様の機能を期待できるが,Fatalモジュールが作り出すopen()は3つ以上の引数を扱えない。
FatalやIO::Fileといった標準モジュールで3つ以上の引数のopen()の存在が無視されているのはなんとも悲しい。もっとも使う機会はきわめて稀だとは思うが。