=> via { $en_parser->parse_datetime($_) };
has birth_date => (
- is => 'rw',
- isa => 'DateTime',
+ is => 'rw',
+ isa => 'DateTime',
+ coerce => 1,
+ handles => { birth_year => 'year' },
);
subtype 'ShirtSize'
exists $p{birth_date}
or confess 'birth_date is a required attribute';
- my $date = $p{birth_date};
- $class->_coerce_birth_date( \$date );
+ $p{birth_date} = $class->_coerce_birth_date($date );
$class->_validate_birth_date( $date );
$p{shirt_size} = 'l'
$class->_validate_shirt_size( $p{shirt_size} );
- my $self = map { $_ => $p{$_} } qw( name shirt_size );
- $self->{birth_date} = $date;
+ my %self = map { $_ => $p{$_} } qw( name shirt_size );
+ $self{birth_date} = $date;
- return bless $self, $class;
+ return bless \%self, $class;
}
sub _validate_name {
shift;
my $date = shift;
- return unless defined $date && ! ref $date;
+ return $date unless defined $date && ! ref $date;
my $dt = $en_parser->parse_datetime($date);
my $self = shift;
if (@_) {
- my $date = shift;
-
- $self->_coerce_birth_date( $date );
+ my $date = $self->_coerce_birth_date( $_[0] );
$self->_validate_birth_date( $date );
+
$self->{birth_date} = $date;
}
return $self->{birth_date};
}
+ sub birth_year {
+ my $self = shift;
+
+ return $self->birth_date->year;
+ }
+
sub shirt_size {
my $self = shift;
Perl 5 programmers to just not bother, which results in much more
fragile code.
-Did you spot the bug?
+Did you spot the (intentional) bug?
It's in the C<_validate_birth_date()> method. We should check that
that value in C<$birth_date> is actually defined and object before we
go and call C<isa()> on it! Leaving out those checks means our data
validation code could actually cause our program to die. Oops.
-There's one bit of code in there worth explaining, which is the
-handling of the birth date for coercion. In both the constructor and
-accessor, we first take a copy of the birth date before passing it to
-the coercion routine. This is to avoid changing the value as it was
-passed to those methods, which could cause problems for the caller.
-
Also note that if we add a superclass to Person we'll have to change
the constructor to account for that.
Of course, there are CPAN modules that do some of what Moose does,
like C<Class::Accessor>, C<Class::Meta>, and so on. But none of them
put together all of Moose's features along with a layer of declarative
-sugar.
+sugar, nor are these other modules designed for extensibility in the
+same way as Moose. With Moose, it's easy to write a MooseX module to
+replace or extend a piece of built-in functionality.
=head1 AUTHOR