2006 年 4 月 22 日 23 時 57 分

Carp 対策


このアーカイブは同期化されません。 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

これでうまくいった。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.