理系学生日記

おまえはいつまで学生気分なのか

DBIC に出てくる Carp::Clan を用いたスキップについて

DBIC のソースを読んでたら、不意に出てきた Carp::Clan。気になって調べてみました。

Carp との違い

一番分かりやすい Carp との違いは、どのサブルーチン内でエラーが起こったかまでが、エラーメッセージとともに出力されることです。

#!/opt/local/bin/perl
use strict;
use warnings;

package Pack::A;
sub exception { Pack::B::exception(); }

package Pack::B;
sub exception { Pack::C::exception(); }

package Pack::C;
use Carp;
# use Carp::Clan;
sub exception { carp "exception"; }

package main;
Pack::A::exception();
use Carp の場合
exception at ./carp-clan.pl line 9
use Carp::Clan の場合
Pack::C::exception(): exception at ./carp-clan.pl line 9

Carp は、呼び出し元がどこか (line 9) だけしか分かりませんが、Carp::Clan にするとで、どこ(Pack::C::exception()) でエラーが発生しているかも分かるようになります。
ただ、これだけでは Clan (一族とかを意味します) の意味をまだ成していません

Clan をスキップ

Carp::Clan では、use 時にどのモジュールを Clan (一族) とするかを決めることができます。
例えば、上記のソースでの Pack::C パッケージを以下のようにしてみます。

package Pack::C;
# use Carp;
use Carp::Clan qw(Pack::[BC]);
sub exception { carp "exception"; }

ここでは、Pack::A、及び Pack::B を Clan として定義しています。このときの出力は、以下のようになります。

Pack::B::exception(): exception at ./carp-clan.pl line 6

呼び出し元は今までの "line 9" から "line 6" になり、エラーの発生源は今までの Pack::C::exception からPack::B::exception に変わりました。
これはどういうことかというと、Clan として定義した Pack::[BC] は一族(Clan) ですから、例えPack::C::exception() で例外が発生しても、Pack::B::exception で例外が発生したのと同じだよって(ユーザには)見えるようにするってことです。

DBIC::Schema::Loader では

use Carp::Clan qw/^DBIx::Class/;

って形で定義されてますが、これは DBIx::Class::* ていうモジュールは全部 Clan だから、その中で起きた例外は全て、コールスタック上を最も遡ったところにある DBIx::Class メソッドの呼び出しで例外が発生したようにユーザには見えることになります。