Commit | Line | Data |
093a09aa |
1 | =pod |
2 | |
3 | =head1 NAME |
4 | |
d67ce58f |
5 | Moose::Manual::Delegation - Attribute delegation |
093a09aa |
6 | |
7 | =head1 WHAT IS DELEGATION? |
8 | |
50f346d7 |
9 | Delegation is a feature that lets you create "proxy" methods that |
117ad31b |
10 | do nothing more than call some other method on an attribute. This |
d3e02c74 |
11 | is quite handy since it lets you simplify a complex set of "has-a" |
093a09aa |
12 | relationships and present a single unified API from one class. |
13 | |
d3e02c74 |
14 | With delegation, consumers of a class don't need to know about all the |
15 | objects it contains, reducing the amount of API they need to learn. |
093a09aa |
16 | |
17 | Delegations are defined as a mapping between one or more methods |
18 | provided by the "real" class (the delegatee), and a set of |
19 | corresponding methods in the delegating class. The delegating class |
d3e02c74 |
20 | can re-use the method names provided by the delegatee or provide its |
093a09aa |
21 | own names. |
22 | |
23 | Delegation is also a great way to wrap an existing class, especially a |
24 | non-Moose class or one that is somehow hard (or impossible) to |
25 | subclass. |
26 | |
27 | =head1 DEFINING A MAPPING |
28 | |
29 | Moose offers a number of options for defining a delegation's mapping, |
30 | ranging from simple to complex. |
31 | |
32 | The simplest form is to simply specify a list of methods: |
33 | |
34 | package Website; |
35 | |
36 | use Moose; |
37 | |
38 | has 'uri' => ( |
39 | is => 'ro', |
40 | isa => 'URI', |
41 | handles => [qw( host path )], |
42 | ); |
43 | |
44 | With this definition, we can call C<< $website->host >> and it "just |
45 | works". Under the hood, Moose will call C<< $website->uri->host >> for |
b3b5ff5a |
46 | you. Note that C<$website> is not automatically passed to the C<host> |
47 | method; the invocant is C<< $website->uri >>. |
093a09aa |
48 | |
49 | We can also define a mapping as a hash reference. This allows you to |
50 | rename methods as part of the mapping: |
51 | |
52 | package Website; |
53 | |
54 | use Moose; |
55 | |
56 | has 'uri' => ( |
57 | is => 'ro', |
58 | isa => 'URI', |
59 | handles => { |
60 | hostname => 'host', |
61 | path => 'path', |
62 | }, |
63 | ); |
64 | |
65 | In this example, we've created a C<< $website->hostname >> method, |
66 | rather than using C<URI.pm>'s name, C<host>. |
67 | |
68 | These two mapping forms are the ones you will use most often. The |
69 | remainder are a bit more complex, and less common. |
70 | |
71 | has 'uri' => ( |
72 | is => 'ro', |
73 | isa => 'URI', |
74 | handles => qr/^(?:host|path|query.*)/, |
75 | ); |
76 | |
77 | This is similar to the array version, except it uses the regex to |
78 | match against all the methods provided by the delegatee. In order for |
79 | this to work, you must provide an C<isa> parameter for the attribute, |
80 | and it must be a class. Moose uses this to introspect the delegatee |
81 | class and determine what methods it provides. |
82 | |
83 | You can use a role name as the value of C<handles>: |
84 | |
85 | has 'uri' => ( |
86 | is => 'ro', |
87 | isa => 'URI', |
88 | handles => 'HasURI', |
89 | ); |
90 | |
91 | Moose will introspect the role to determine what methods it provides |
92 | and create a mapping for each of those methods. |
93 | |
94 | Finally, you can also provide a sub reference to I<generate> a |
95 | mapping. You probably won't need this version often (if ever). See the |
96 | L<Moose> docs for more details on exactly how this works. |
97 | |
50f346d7 |
98 | =head1 PERL DATA STRUCTURES |
99 | |
100 | Handles also will allow you to delegate to "helper" methods that work on |
101 | common Perl data structures. If you remember or have ever used |
a07ac196 |
102 | L<MooseX::AttributeHelpers|MooseX::AttributeHelpers> the mechanism is very |
f4c5daeb |
103 | similar. |
104 | |
50f346d7 |
105 | has 'queue' => ( |
f4c5daeb |
106 | isa => 'ArrayRef[Item]', |
107 | traits => ['Array'], |
50f346d7 |
108 | default => sub { [ ] }, |
109 | handles => { |
f4c5daeb |
110 | add_item => 'push', |
50f346d7 |
111 | next_item => 'shift', |
9610c1d2 |
112 | }, |
50f346d7 |
113 | ) |
114 | |
f4c5daeb |
115 | By providing the C<Array> trait to the C<traits> parameter you signal to |
50f346d7 |
116 | Moose that you would like to use the set of Array helpers. Moose will then |
8580644d |
117 | create C<add_item> and C<next_item> method that "just works". Behind the |
50f346d7 |
118 | scenes C<add_item> is something like |
119 | |
f4c5daeb |
120 | sub add_item { |
50f346d7 |
121 | my ($self, @items) = @_; |
26366034 |
122 | |
f4c5daeb |
123 | for my $item (@items) { |
124 | $Item_TC->validate($item); |
125 | } |
26366034 |
126 | |
50f346d7 |
127 | push @{ $self->queue }, @items; |
128 | } |
129 | |
130 | There are traits for not only C<Array> but also C<Hash>, C<Bool>, C<String>, |
131 | C<Number>, and C<Counter>. For more information see the documentation in |
132 | L<Moose::Meta::Attribute::Native|Moose::Meta::Attribute::Native>. |
133 | |
134 | =head1 CURRYING |
135 | |
136 | Currying is a way of creating a method or function from another method or |
26366034 |
137 | function with some of the parameters pre-defined. Moose provides the ability to |
f4c5daeb |
138 | curry methods when creating delegates. |
50f346d7 |
139 | |
140 | package Spider; |
141 | use Moose; |
142 | |
143 | has request => ( |
26366034 |
144 | is => 'ro' |
145 | isa => 'HTTP::Request', |
50f346d7 |
146 | handles => { |
26366034 |
147 | set_user_agent => [ header => 'UserAgent' ], |
9610c1d2 |
148 | }, |
50f346d7 |
149 | ) |
150 | |
8580644d |
151 | With this definition, calling C<< $spider->set_user_agent('MyClient') >> will |
4a1fdc05 |
152 | behind the scenes call C<< $spider->request->header('UserAgent', 'MyClient') >>. |
50f346d7 |
153 | |
093a09aa |
154 | =head1 MISSING ATTRIBUTES |
155 | |
156 | It is perfectly valid to delegate methods to an attribute which is not |
d3e02c74 |
157 | required or can be undefined. When a delegated method is called, Moose |
158 | will throw a runtime error if the attribute does not contain an |
159 | object. |
093a09aa |
160 | |
161 | =head1 AUTHOR |
162 | |
163 | Dave Rolsky E<lt>autarch@urth.orgE<gt> |
164 | |
165 | =head1 COPYRIGHT AND LICENSE |
166 | |
2840a3b2 |
167 | Copyright 2009 by Infinity Interactive, Inc. |
093a09aa |
168 | |
169 | L<http://www.iinteractive.com> |
170 | |
171 | This library is free software; you can redistribute it and/or modify |
172 | it under the same terms as Perl itself. |
173 | |
174 | =cut |