2014-03-31 20 views
2

有下包的Perl /駝鹿不創建對象,但不會死,如果一個屬性是錯誤

package MyTest; 
use warnings; 
use Moose; 
use Types::Path::Tiny qw(AbsPath AbsFile); 

has 'file' => (
    is => 'ro', 
    isa => AbsPath, 
    required => 1, 
    coerce => 1, 
); 
no Moose; 
__PACKAGE__->meta->make_immutable; 
1; 

作品(幾乎)OK,所以當使用它

use strict; 
use warnings; 
use feature 'say'; 
use Mytest; 
use DDP; 

my $t1 = MyTest->new(file => './t'); # the ./t is existing file in the filesystem 
say $t1 ? "ok" : "no"; 

my $t2 = MyTest->new(file => './nonexistent_file'); 
say $t2 ? "ok" : "no"; 
p $t2; 

說兩個都可以。和$t2->fileisa "Path::Tiny

但是,我不想創建的對象,如果文件不是真的存在於文件系統。所以,第二個($t2)調用應返回undef

更改

 isa => AbsPath, 

 isa => AbsFile, 

會檢查文件的存在,但如果不存在的話 - 該腳本將與

Attribute (file) does not pass the type constraint because: File '/tmp/nonexistent_file' does not exist 

死我不想死,只想創建MyTest實例並返回undef,如果該文件不是exi sts或它不是一個純文件。如果文件存在,該文件應該是一個Path::Tiny實例。 (從Str強制)。

有人可以幫我嗎?

回答

3

最簡單的方法是將趕上並丟棄預期的錯誤:

use Try::Tiny; 

my $instance = try { 
    MyTest->new(file => './nonexistent_file'); 
} catch { 
    # only mute the constraint errors 
    return undef if /\AAttribute [(]\w+[)] does not pass the type constraint/; 
    die $_; # rethrow other errors 
}; 

與構造周圍碴,使其返回undef失敗是不是一個好主意,因爲是->new將一個隱含合同總是返回一個有效的實例。在較老的Perl代碼中,在失敗時返回一個特殊值被認爲是可以的,但是這會強制對調用者進行額外的檢查 - 並且檢查可能被遺忘。穆斯採取了更強大的路線,而不是使用免除(因此強迫他們被處理),雖然在這個特定的情況下,這確實增加了一些樣板。

如果要隱藏此樣板,請考慮編寫工廠方法。

+0

@ jm666在這種特定的情況下,這確實是一個更好的解決方案(文件不存在的情況並不例外,所以這種情況應該由正常的控制流程來處理)。考慮發佈它作爲你自己的答案:)在我的回答中,我試圖解釋錯誤是一件好事,而且它們很容易處理。 – amon

+0

我已經刪除了我的評論;) – jm666

2

我評論@阿蒙的帖子,但改變了主意,因爲他的解決方案是普遍的,而我的則只能處理這種特殊情況下,無論如何張貼:

my $file = './nonexistent_file'; 
my $t2 = (-f $file) ? MyTest->new(file => $file) : undef; 
相關問題