314 lines
7.9 KiB
Plaintext
314 lines
7.9 KiB
Plaintext
# 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
|