初めに
以下のドキュメントにCarpの詳細説明があるので、それを読めば挙動が分かります。
Carp - モジュールのための warn と die の代替
この記事では、実際に継承してるコードを例に出して説明しようと思います。
コードと実行結果
client.pl
#!/usr/bin/env perl
use strict;
use warnings;
use Concrete;
Concrete->new->run(@ARGV);
Concrete.pm(具象クラス)
package Concrete;
use strict;
use warnings;
use Carp;
use parent 'Abstract';
sub speak {
my $self = shift;
croak "ダレカタスケテー";
}
1;
Abstract.pm(抽象クラス)
package Abstract;
use strict;
use warnings;
sub new {
my $class = shift;
bless {}, $class;
}
sub run {
my $self = shift;
$self->speak;
}
sub speak {}
1;
実行結果
$ ./client.pl
ダレカタスケテー at ./client.pl line 6.
挙動について
このコードを実装した際、呼び出し元がAbstract::runなので、
ダレカタスケテー at Abstract.pm line 12. と出るかと思ったら、
client.plの行数が出てしまいました。
これは何故かというと、継承関係にある呼び出し元は(具体的には@ISAに入っていれば)、
安全であると判断されスルーされます。
更に上位の呼び出し元はclient.plになるので、上記の実行結果となりました。
これだとエラーとしては分かり辛いなぁと思います。
対策
dieを使う
die
を実行した行数とそのファイル名を返します。
$ ./client.pl
ダレカタスケテー at Concrete.pm line 10.
confessを使う
confess
はスタックトレースを伴うエラーを発生させます。
$ ./client.pl
ダレカタスケテー at Concrete.pm line 10.
Concrete::speak('Concrete=HASH(0x177b178)') called at Abstract.pm line 12
Abstract::run('Concrete=HASH(0x177b178)') called at ./client.pl line 6
Carp::verboseを有功にする
全てのcroak
をconfess
に、carp
をcluck
にとして扱うようにします。
CPANからダウンロードして使用している外部モジュールなども対象となります。
$ perl -MCarp=verbose client.pl
ダレカタスケテー at Concrete.pm line 10.
Concrete::speak('Concrete=HASH(0x184b1a8)') called at Abstract.pm line 12
Abstract::run('Concrete=HASH(0x184b1a8)') called at client.pl line 6
まとめ
Template Methodパターンで作ってたらこの問題にぶち当たりました。
CPANに公開しないモジュールであれば、confess
を使っておくのが良いかなぁと思ってます。
(die
は情報が少ないし、Carp::verboseはやりすぎ感がある……)
おまけ
evalで例外をキャッチするとこんな表示になります。
Abstract.pm(runを書き換え)
sub run {
my $self = shift;
eval { $self->speak };
if($@) {
print "$@";
warn "チョットマッテテー";
}
}
実行結果
Use of uninitialized value $_ in string at Abstract.pm line 14.
ダレカタスケテー at Concrete.pm line 10.
Concrete::speak('Concrete=HASH(0x1ec0178)') called at Abstract.pm line 12
eval {...} called at Abstract.pm line 12
Abstract::run('Concrete=HASH(0x1ec0178)') called at ./client.pl line 6
チョットマッテテー at Abstract.pm line 15.
eval {...} が追加されてますね!
やりたかっただけです!