Perl / Moose不会创建对象,但如果属性错误则不会死亡

时间:2014-03-31 08:40:31

标签: perl moose

拥有下一个包

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;

工作(差不多),所以使用时

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;

说" ok"对彼此而言。而$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,或者它不是普通文件。如果文件存在,则该文件应为Path::Tiny实例。 (从Str强迫)。

有人能帮助我吗?

2 个答案:

答案 0 :(得分: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代码中,在失败时返回特殊值被认为是正常的,但这会强制对调用者进行额外检查 - 并且可能会忘记检查。通过使用exeptions(因此强制它们被处理),Moose采取了更强大的路线,尽管在这种特定情况下,这确实增加了一些样板。

如果要隐藏此样板,请考虑编写工厂方法。

答案 1 :(得分:2)

我评论@ amon的帖子,但改变了我的想法,因为他的解决方案是普遍的,我的只处理这个特殊情况,无论如何发布它:

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