このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
プロパティによる Carp への影響を考えてみよう。
まずは、croak のメッセージの仕組みを調べるために、
コールスタックをトレースさせてみよう。
Carp モジュールに 'verbose' 引数を渡して取り込んだ場合、
croak が自動的にバックトレースつきで出力される。
なので、EmployeeTest.pl に、以下の行を加えておこう。
use Carp 'verbose';
さて、$jack->set_salary(100000); の場合どうなるか。
$ ./EmployeeTest.pl
I can't agree you offered! at Employee.pm line 40
Employee::set_salary('Employee=HASH(0x185312c)', 100000) called at EmployeeTest.pl line 16
Employee.pm line 40 でエラーが起きていることが分かる。
これは Employee::set_salary で、呼び出し元は、
EmployeeTest.pl line 16 だ。
では、$jack->salary = 100000; の場合はどうなるか。
$ ./EmployeeTest.pl
I can't agree you offered! at Employee.pm line 40
Employee::set_salary('Employee=HASH(0x185312c)', 100000) called at property.pm line 55
property::STORE('property=HASH(0x27554c)', 100000) called at EmployeeTest.pl line 16
Employee.pm line 40 でエラーが起きているのは同じだが、
まずは property.pm line 55 から呼ばれている。
これは property::STORE だ。property::STORE 自体は、
EmployeeTest.pl line 16 から呼ばれている。
さて、croak した際に問題がおきるのは、
マジカルスカラへの代入によって、
property::STORE の呼び出しが発生しているからである。
つまり、set_salary を呼び出している property::STORE が、
エラーの原因とされて表示されてしまうのだ。
これを回避するためには、Carp の信頼システムを利用する。
モジュールが croak した場合、スタックをたどり、
「信頼していない」モジュールの呼び出しがあれば、
それがエラーの原因としてファイル名や行番号が使用される。
Employee は、property のことを知らないので、
Employee::set_salary を呼び出した property::STORE は、
信頼していないとみなされ、エラーの原因とされてしまう。
信頼関係を作るには、信頼する側のパッケージに、
@CARP_NOT という配列をつくり、
そこに信頼するパッケージ名を記入すればよい。
Employee が property を信頼していれば、
property::STORE は安全と判断されるはずだ。
@Employee::CARP_NOT = ('property');
しかし、property モジュールを使うモジュールが、
いちいち CARP_NOT を指定するのは面倒くさい。
property はプラグマ的に作用するようにしているので、
プロパティを呼び出し元のパッケージに登録したように、
CARP_NOT にも設定してやればよいのだ。
では、property.pm の import メソッドを変えてみよう。
sub import {
my $package = shift;
my %param = @_;
my $target = caller;
_create_property($target, $param{'name'},
$param{'get'}, $param{'set'});
my $symbol = "${target}::CARP_NOT";
no strict 'refs';
no warnings;
push(@$symbol, __PACKAGE__);
}
ここでもシンボリックリファレンスが役に立つ。
$symbol には、'Employee::CARP_NOT' などが入る。
@$symbol で、@Employee::CARP_NOT を示すことになる。
既に @CARP_NOT に値があることを考え、
push を使って新たな値を配列に追加する。
__PACKAGE__ は、コードのあるパッケージ名だ。
ここでは、'property' になるはずだ。
では EmployeeTest.pl から use Carp 'verbose'; を外し、
$jack->salary = 100000; で実行してみよう。
$ ./EmployeeTest.pl
I can't agree you offered! at EmployeeTest.pl line 15
これでうまくいった。