This commit is contained in:
313
CPAN/Moose/Manual/Delegation.pod
Normal file
313
CPAN/Moose/Manual/Delegation.pod
Normal file
@@ -0,0 +1,313 @@
|
||||
# PODNAME: Moose::Manual::Delegation
|
||||
# ABSTRACT: Attribute delegation
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Moose::Manual::Delegation - Attribute delegation
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 2.2207
|
||||
|
||||
=head1 WHAT IS DELEGATION?
|
||||
|
||||
Delegation is a feature that lets you create "proxy" methods that do nothing
|
||||
more than call some other method on an attribute. This lets you simplify a
|
||||
complex set of "has-a" relationships and present a single unified API from one
|
||||
class.
|
||||
|
||||
With delegation, consumers of a class don't need to know about all the
|
||||
objects it contains, reducing the amount of API they need to learn.
|
||||
|
||||
Delegations are defined as a mapping between one or more methods
|
||||
provided by the "real" class (the delegatee), and a set of
|
||||
corresponding methods in the delegating class. The delegating class
|
||||
can re-use the method names provided by the delegatee or provide its
|
||||
own names.
|
||||
|
||||
Delegation is also a great way to wrap an existing class, especially a
|
||||
non-Moose class or one that is somehow hard (or impossible) to
|
||||
subclass.
|
||||
|
||||
=head1 DEFINING A MAPPING
|
||||
|
||||
Moose offers a number of options for defining a delegation's mapping,
|
||||
ranging from simple to complex.
|
||||
|
||||
The simplest form is to simply specify a list of methods:
|
||||
|
||||
package Website;
|
||||
|
||||
use Moose;
|
||||
|
||||
has 'uri' => (
|
||||
is => 'ro',
|
||||
isa => 'URI',
|
||||
handles => [qw( host path )],
|
||||
);
|
||||
|
||||
Using an arrayref tells Moose to create methods in your class that match the
|
||||
method names in the delegated class.
|
||||
|
||||
With this definition, we can call C<< $website->host >> and it "just
|
||||
works". Under the hood, Moose will call C<< $website->uri->host >> for
|
||||
you. Note that C<$website> is I<not> automatically passed to the C<host>
|
||||
method; the invocant is C<< $website->uri >>.
|
||||
|
||||
We can also define a mapping as a hash reference. This allows you to
|
||||
rename methods as part of the mapping:
|
||||
|
||||
package Website;
|
||||
|
||||
use Moose;
|
||||
|
||||
has 'uri' => (
|
||||
is => 'ro',
|
||||
isa => 'URI',
|
||||
handles => {
|
||||
hostname => 'host',
|
||||
path => 'path',
|
||||
},
|
||||
);
|
||||
|
||||
Using a hash tells Moose to create method names (specified on the left) which
|
||||
invoke the delegated class methods (specified on the right).
|
||||
|
||||
In this example, we've created a C<< $website->hostname >> method,
|
||||
rather than simply using C<URI.pm>'s name, C<host> in the Website
|
||||
class.
|
||||
|
||||
These two mapping forms are the ones you will use most often. The
|
||||
remaining methods are a bit more complex.
|
||||
|
||||
has 'uri' => (
|
||||
is => 'ro',
|
||||
isa => 'URI',
|
||||
handles => qr/^(?:host|path|query.*)/,
|
||||
);
|
||||
|
||||
This is similar to the array version, except it uses the regex to
|
||||
match against all the methods provided by the delegatee. In order for
|
||||
this to work, you must provide an C<isa> parameter for the attribute,
|
||||
and it must be a class. Moose uses this to introspect the delegatee
|
||||
class and determine what methods it provides.
|
||||
|
||||
You can use a role name as the value of C<handles>:
|
||||
|
||||
has 'uri' => (
|
||||
is => 'ro',
|
||||
isa => 'URI',
|
||||
handles => 'HasURI',
|
||||
);
|
||||
|
||||
Moose will introspect the role to determine what methods it provides
|
||||
and create a name-for-name mapping for each of those methods.
|
||||
|
||||
Finally, you can provide a sub reference to I<generate> a mapping that behaves
|
||||
like the hash example above. You probably won't need this version often (if
|
||||
ever). See the L<Moose> docs for more details on exactly how this works.
|
||||
|
||||
=head1 NATIVE DELEGATION
|
||||
|
||||
Native delegations allow you to delegate to standard Perl data structures as
|
||||
if they were objects.
|
||||
|
||||
has 'queue' => (
|
||||
traits => ['Array'],
|
||||
isa => 'ArrayRef[Item]',
|
||||
default => sub { [ ] },
|
||||
handles => {
|
||||
add_item => 'push',
|
||||
next_item => 'shift',
|
||||
},
|
||||
)
|
||||
|
||||
The C<Array> trait in the C<traits> parameter tells Moose that you would like
|
||||
to use the set of Array helpers. Moose will then create C<add_item> and
|
||||
C<next_item> methods that "just work". Behind the scenes C<add_item> is
|
||||
something like
|
||||
|
||||
sub add_item {
|
||||
my ($self, @items) = @_;
|
||||
|
||||
for my $item (@items) {
|
||||
$Item_TC->validate($item);
|
||||
}
|
||||
|
||||
push @{ $self->queue }, @items;
|
||||
}
|
||||
|
||||
For example, you might use Array helpers to add C<add_task> and
|
||||
C<add_appointment> methods to a Calendar class:
|
||||
|
||||
has 'tasks' => (
|
||||
traits => ['Array'],
|
||||
isa => 'ArrayRef[Task]',
|
||||
default => sub { [ ] },
|
||||
handles => {
|
||||
add_task => 'push',
|
||||
next_task => 'shift',
|
||||
},
|
||||
);
|
||||
|
||||
has 'appointments' => (
|
||||
traits => ['Array'],
|
||||
isa => 'ArrayRef[Appointment]',
|
||||
default => sub { [ ] },
|
||||
handles => {
|
||||
add_appointment => 'push',
|
||||
next_appointment => 'shift',
|
||||
},
|
||||
);
|
||||
|
||||
Which you would call as:
|
||||
|
||||
$calendar->add_task( $task_obj );
|
||||
$calendar->add_appointment( $appointment_obj );
|
||||
|
||||
As mentioned above, each trait provides a number of methods which are
|
||||
summarized below. For more information about each of these provided methods
|
||||
see the documentation for that specific trait.
|
||||
|
||||
Moose includes the following traits for native delegation.
|
||||
|
||||
=over 4
|
||||
|
||||
=item * L<Array|Moose::Meta::Attribute::Native::Trait::Array>
|
||||
|
||||
The following methods are provided by the native Array trait:
|
||||
|
||||
count, is_empty, elements, get, pop, push, shift, unshift, splice, first,
|
||||
first_index, grep, map, reduce, sort, sort_in_place, shuffle, uniq, join, set,
|
||||
delete, insert, clear, accessor, natatime, shallow_clone
|
||||
|
||||
=item * L<Bool|Moose::Meta::Attribute::Native::Trait::Bool>
|
||||
|
||||
The following methods are provided by the native Bool trait:
|
||||
|
||||
set, unset, toggle, not
|
||||
|
||||
=item * L<Code|Moose::Meta::Attribute::Native::Trait::Code>
|
||||
|
||||
The following methods are provided by the native Code trait:
|
||||
|
||||
execute, execute_method
|
||||
|
||||
=item * L<Counter|Moose::Meta::Attribute::Native::Trait::Counter>
|
||||
|
||||
The following methods are provided by the native Counter trait:
|
||||
|
||||
set, inc, dec, reset
|
||||
|
||||
=item * L<Hash|Moose::Meta::Attribute::Native::Trait::Hash>
|
||||
|
||||
The following methods are provided by the native Hash trait:
|
||||
|
||||
get, set, delete, keys, exists, defined, values, kv, elements, clear, count,
|
||||
is_empty, accessor, shallow_clone
|
||||
|
||||
=item * L<Number|Moose::Meta::Attribute::Native::Trait::Number>
|
||||
|
||||
The following methods are provided by the native Number trait:
|
||||
|
||||
add, sub, mul, div, mod, abs
|
||||
|
||||
=item * L<String|Moose::Meta::Attribute::Native::Trait::String>
|
||||
|
||||
The following methods are provided by the native String trait:
|
||||
|
||||
inc, append, prepend, replace, match, chop, chomp, clear, length, substr
|
||||
|
||||
=back
|
||||
|
||||
=head1 CURRYING
|
||||
|
||||
Currying allows you to create a method with some pre-set parameters. You can
|
||||
create a curried delegation method:
|
||||
|
||||
package Spider;
|
||||
use Moose;
|
||||
|
||||
has request => (
|
||||
is => 'ro'
|
||||
isa => 'HTTP::Request',
|
||||
handles => {
|
||||
set_user_agent => [ header => 'UserAgent' ],
|
||||
},
|
||||
)
|
||||
|
||||
With this definition, calling C<< $spider->set_user_agent('MyClient') >> will
|
||||
call C<< $spider->request->header('UserAgent', 'MyClient') >> behind the
|
||||
scenes.
|
||||
|
||||
Note that with currying, the currying always starts with the first parameter to
|
||||
a method (C<$_[0]>). Any arguments you pass to the delegation come after the
|
||||
curried arguments.
|
||||
|
||||
=head1 MISSING ATTRIBUTES
|
||||
|
||||
It is perfectly valid to delegate methods to an attribute which is not
|
||||
required or can be undefined. When a delegated method is called, Moose
|
||||
will throw a runtime error if the attribute does not contain an
|
||||
object.
|
||||
|
||||
=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