Search code examples
perlmoose

How to check the validity of the required argument in Moose constructor?


This is sure very simple question, but i'm still learning and not found the answer.

Need check the validity of the supplied (required) argument to Moose object constructor, e.g. like in the next example:

use 5.016;
use warnings;

package My {
    use Moose;
    has 'mydir' => (
        is          => 'ro',
        isa         => 'Str',
        required    => 1,
    );
}

use File::Path qw(remove_tree);
package main {
    my @dirs = qw(./d1 ./d2);

    #ensure no one dir exists
    remove_tree($_) for ( @dirs );

    #create the first dir
    mkdir $dirs[0] or die;

    foreach my $dir( @dirs ) {
        my $m = My->new( mydir=>$dir );
        say "$dir ", defined($m) ? "" : "NOT", " ok";
    }
}

The question is: what i should add to the My package to ensure create the My object only if the supplied mydir path exists? So somewhere need add the test if -d ... .

How to define the attribute mydir with validity check?

Wanted result of the main program:

./d1 ok
./d2 NOT ok

Solution

  • You can define a subtype with a type constraint.

    The syntactic sugar for working with this is provided by Moose::Util::TypeConstraints.

    package My;
    use 5.16.0;
    
    use Moose;
    use Moose::Util::TypeConstraints; # provides sugar below
    
    subtype 'ExistingDir' => (
        as 'Str',
        where { -d $_ },
        message { 'The directory does not exist' }
        );
    
    has 'mydir' => (
            is          => 'ro',
            isa         => 'ExistingDir',
            required    => 1,
        );
    
    package main;
    
    my $foo = My->new(mydir => 'perl'); # exists
    say $foo->mydir();
    
    my $bar = My->new(mydir => 'perlXXX'); # does not exist, so dies here...
    

    outputs:

    >mkdir perl
    >perl foo.pl
    
    perl
    Attribute (mydir) does not pass the type constraint because: The directory does not exist at ...