The value of a role’s required attribute is only checked on object creation. This article provides one way of enforcing it when applying the role to an object on the fly.
What is certain about Perl programming is that there's always more to learn, and this article on applying roles in OO Perl is one such example. It's the challenge of ensuring attributes are set in roles applied on the fly.
It’s quite often the case that if people forget to assign a value to an attribute we really want things to die rather than have undef being returned as the value of the attribute.
Here's an example:
It’s quite often the case that if people forget to assign a value to an attribute we really want things to die rather than have undef being returned as the value of the attribute.
Here's an example:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
package Brand; | |
use Moo::Role; | |
has name => ( is => 'ro' ); | |
sub description { "This is a nice ". shift->name } | |
} | |
{ | |
package Car; | |
use Moo; | |
with 'Brand'; | |
} | |
say Car->new ( name => "Peugeot" )->description; # Good usage | |
say Car->new->description; # Bad usage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> ./car-01.pl | |
This is a nice Peugeot | |
Use of uninitialized value in concatenation (.) or string at ./car-01.pl line 15. | |
This is a nice |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> ./car-02.pl | |
This is a nice Peugeot | |
Missing required arguments: name at (eval 12) line 49. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
has name => ( is => 'ro', required => 1 ); | |
# This will die: my $car = Car->new; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
package Brand; | |
use Moo::Role; | |
has name => ( is => 'rw', required => 1 ); # made rw | |
sub description { "This is a nice ". shift->name } | |
} | |
{ | |
package Car; | |
use Moo; | |
# with 'Brand'; # not at compile time | |
} | |
my $car = Car->new; | |
# TODO an investigation which determines that it really is a branded car | |
Moo::Role->apply_roles_to_object($car, 'Brand'); | |
# $car->name("Peugeot"); | |
say $car->description; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
./car-03.pl | |
Use of uninitialized value in concatenation (.) or string at ./car-03.pl line 15. | |
This is a nice |
"Terminate!" by default
Rather than requiring the attribute on object creation (before the role has been applied) the solution here is to make the attribute lazy, then die by default on accessing the attribute to indicate that a value hasn't been assigned.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
package Brand; | |
use Moo::Role; | |
has name => ( | |
is => 'rw', | |
lazy => 1, | |
default => sub { die "name is required" } | |
); | |
sub description { "This is a nice ". shift->name } | |
} | |
{ | |
package Car; | |
use Moo; | |
} | |
my $car = Car->new; | |
Moo::Role->apply_roles_to_object($car, 'Brand'); | |
# $car->name("Peugeot"); # assign a name to avert termination! | |
say $car->description; |
No comments:
Post a Comment