This commit is contained in:
180
CPAN/Moose/Cookbook/Basics/Person_BUILDARGSAndBUILD.pod
Normal file
180
CPAN/Moose/Cookbook/Basics/Person_BUILDARGSAndBUILD.pod
Normal file
@@ -0,0 +1,180 @@
|
||||
# PODNAME: Moose::Cookbook::Basics::Person_BUILDARGSAndBUILD
|
||||
# ABSTRACT: Using BUILDARGS and BUILD to hook into object construction
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Moose::Cookbook::Basics::Person_BUILDARGSAndBUILD - Using BUILDARGS and BUILD to hook into object construction
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 2.2207
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package Person;
|
||||
|
||||
has 'ssn' => (
|
||||
is => 'ro',
|
||||
isa => 'Str',
|
||||
predicate => 'has_ssn',
|
||||
);
|
||||
|
||||
has 'country_of_residence' => (
|
||||
is => 'ro',
|
||||
isa => 'Str',
|
||||
default => 'usa'
|
||||
);
|
||||
|
||||
has 'first_name' => (
|
||||
is => 'ro',
|
||||
isa => 'Str',
|
||||
);
|
||||
|
||||
has 'last_name' => (
|
||||
is => 'ro',
|
||||
isa => 'Str',
|
||||
);
|
||||
|
||||
around BUILDARGS => sub {
|
||||
my $orig = shift;
|
||||
my $class = shift;
|
||||
|
||||
if ( @_ == 1 && ! ref $_[0] ) {
|
||||
return $class->$orig(ssn => $_[0]);
|
||||
}
|
||||
else {
|
||||
return $class->$orig(@_);
|
||||
}
|
||||
};
|
||||
|
||||
sub BUILD {
|
||||
my $self = shift;
|
||||
|
||||
if ( $self->country_of_residence eq 'usa' ) {
|
||||
die 'Cannot create a Person who lives in the USA without an ssn.'
|
||||
unless $self->has_ssn;
|
||||
}
|
||||
}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This recipe demonstrates the use of C<BUILDARGS> and C<BUILD>. By
|
||||
defining these methods, we can hook into the object construction
|
||||
process without overriding C<new>.
|
||||
|
||||
The C<BUILDARGS> method is called I<before> an object has been
|
||||
created. It is called as a class method, and receives all of the
|
||||
parameters passed to the C<new> method. It is expected to do something
|
||||
with these arguments and return a hash reference. The keys of the hash
|
||||
must be attribute C<init_arg>s.
|
||||
|
||||
The primary purpose of C<BUILDARGS> is to allow a class to accept
|
||||
something other than named arguments. In the case of our C<Person>
|
||||
class, we are allowing it to be called with a single argument, a
|
||||
social security number:
|
||||
|
||||
my $person = Person->new('123-45-6789');
|
||||
|
||||
The key part of our C<BUILDARGS> is this conditional:
|
||||
|
||||
if ( @_ == 1 && ! ref $_[0] ) {
|
||||
return $class->$orig(ssn => $_[0]);
|
||||
}
|
||||
|
||||
By default, Moose constructors accept a list of key-value pairs, or a
|
||||
hash reference. We need to make sure that C<$_[0]> is not a reference
|
||||
before assuming it is a social security number.
|
||||
|
||||
We call the original C<BUILDARGS> method to handle all the other
|
||||
cases. You should always do this in your own C<BUILDARGS> methods,
|
||||
since L<Moose::Object> provides its own C<BUILDARGS> method that
|
||||
handles hash references and a list of key-value pairs.
|
||||
|
||||
The C<BUILD> method is called I<after> the object is constructed, but
|
||||
before it is returned to the caller. The C<BUILD> method provides an
|
||||
opportunity to check the object state as a whole. This is a good place
|
||||
to put logic that cannot be expressed as a type constraint on a single
|
||||
attribute.
|
||||
|
||||
In the C<Person> class, we need to check the relationship between two
|
||||
attributes, C<ssn> and C<country_of_residence>. We throw an exception
|
||||
if the object is not logically consistent.
|
||||
|
||||
=head1 MORE CONSIDERATIONS
|
||||
|
||||
This recipe is made significantly simpler because all of the
|
||||
attributes are read-only. If the C<country_of_residence> attribute
|
||||
were settable, we would need to check that a Person had an C<ssn> if
|
||||
the new country was C<usa>. This could be done with a C<before>
|
||||
modifier.
|
||||
|
||||
=head1 CONCLUSION
|
||||
|
||||
We have repeatedly discouraged overriding C<new> in Moose
|
||||
classes. This recipe shows how you can use C<BUILDARGS> and C<BUILD>
|
||||
to hook into object construction without overriding C<new>.
|
||||
|
||||
The C<BUILDARGS> method lets us expand on Moose's built-in parameter
|
||||
handling for constructors. The C<BUILD> method lets us implement
|
||||
logical constraints across the whole object after it is created.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
Stevan Little <stevan@cpan.org>
|
||||
|
||||
=item *
|
||||
|
||||
Dave Rolsky <autarch@urth.org>
|
||||
|
||||
=item *
|
||||
|
||||
Jesse Luehrs <doy@cpan.org>
|
||||
|
||||
=item *
|
||||
|
||||
Shawn M Moore <sartak@cpan.org>
|
||||
|
||||
=item *
|
||||
|
||||
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
|
||||
|
||||
=item *
|
||||
|
||||
Karen Etheridge <ether@cpan.org>
|
||||
|
||||
=item *
|
||||
|
||||
Florian Ragwitz <rafl@debian.org>
|
||||
|
||||
=item *
|
||||
|
||||
Hans Dieter Pearcey <hdp@cpan.org>
|
||||
|
||||
=item *
|
||||
|
||||
Chris Prather <chris@prather.org>
|
||||
|
||||
=item *
|
||||
|
||||
Matt S Trout <mstrout@cpan.org>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2006 by Infinity Interactive, Inc.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user