Moose (Perl): convert undef to empty string or 0, not die ()

I received many exceptions from QA due to incomplete data that was passed to my Moose constructors. The attribute name is present in the constructor arguments, but the value is undef .

It is a fact of life with many scripting applications that everything is just undef . And often itโ€™s beautiful. You do not need the annoying warning from the warnings pragma (so you do no warnings 'uninitialized' ), and you certainly do not want your code to die, because one small value, for example, the phone number, undef .

So, without further ado, I want my Moose constructors to behave like a straight Perl (i.e. without use warnings 'uninitialized' ), which should convert undef to 0 or empty string as needed. The attempt shown in this example does not work for the case where the attribute name is present, but the value is undef . I could come up with using BUILDARGS to achieve what I want. But is there a declarative way in simple Muse without resorting to MooseX :: UndefTolerant (unfortunately, I cannot use it, since it is not installed)?

 package AAA; use Moose; has 'hu', is => 'ro', isa => 'Str'; has 'ba', is => 'ro', isa => 'Int'; no Moose; __PACKAGE__->meta->make_immutable; package BBB; use Moose; extends 'AAA'; has '+hu', default => ''; # don't want to die on undef has '+ba', default => 0; # idem no Moose; __PACKAGE__->meta->make_immutable; package main; use Test::More; use Test::Exception; # Those AAAs should die ... throws_ok { AAA->new( hu => undef ) } qr/Validation failed for 'Str' with value undef/; throws_ok { AAA->new( ba => undef ) } qr/Validation failed for 'Int' with value undef/; # .. but these BBBs should live: lives_ok { BBB->new( hu => undef ) } 'hu supplied as undef'; lives_ok { BBB->new( ba => undef ) } 'ba supplied as undef'; done_testing; 
+7
source share
3 answers

In Moose :: Manual :: Types , this is a way to document this kind of problem.

Use the Maybe[a] .

 package AAA; use Moose; has 'hu', is => 'ro', isa => 'Str'; has 'ba', is => 'ro', isa => 'Int'; no Moose; __PACKAGE__->meta->make_immutable; package BBB; use Moose; extends 'AAA'; has 'hu', is => 'rw', isa => 'Maybe[Str]', default => ''; # will not die on undef has 'ba', is => 'rw', isa => 'Maybe[Int]', default => 0; # idem sub BUILD { my $self = shift; $self->hu('') unless defined $self->hu; $self->ba(0) unless defined $self->ba; } no Moose; __PACKAGE__->meta->make_immutable; package main; use Test::More; use Test::Exception; # Those AAAs should die ... throws_ok { AAA->new( hu => undef ) } qr/Validation failed for 'Str' with value undef/; throws_ok { AAA->new( ba => undef ) } qr/Validation failed for 'Int' with value undef/; # .. but these BBBs should live: lives_ok { BBB->new( hu => undef ) } 'hu supplied as undef'; lives_ok { BBB->new( ba => undef ) } 'ba supplied as undef'; my $bbb = BBB->new( hu => undef, ba => undef ); is $bbb->hu, '', "hu is ''"; is $bbb->ba, 0, 'ba is 0'; done_testing; 
+8
source

Your complaint is actually that the Elk does exactly what he should do. If you explicitly pass undef as a value, but that value can only be Int , then you should get an error.

So you need to make a choice. You can either change the type (via union) to allow undef as a valid value:

  has 'hu', is => 'ro', isa => 'Str | Undef'; has 'ba', is => 'ro', isa => 'Int | Undef'; 

Or you may just not send undefined values:

  my %aa_params = (); $aa_params{hu} = $foo if defined $foo; $aa = AA->new( %aa_params ); 

Or finally, for some unknown reason, you absolutely can not resist sending invalid undefined values โ€‹โ€‹for things that should not be explicitly set to undefined, just write a quick filter:

  sub filt_undef { my %hash = @_; return map { $_ => $hash{$_} } grep { defined $hash{$_} } keys %hash; } $aa = AA->new( filt_undef( hu => undef ) ); 

But it seems rather uncomfortable and terrible.

+3
source

Or use coercion "on the fly":

 package BBB; use Moose; use MooseX::AttributeShortcuts; extends 'AAA'; has '+hu', traits => [Shortcuts], coerce => [ Undef => sub { '' } ], ; 
0
source

All Articles