Carpは継承関係のモジュールを信頼する
初めに
以下のドキュメントに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 {...} が追加されてますね!
やりたかっただけです!