1Sub::HandlesVia(3)    User Contributed Perl Documentation   Sub::HandlesVia(3)
2
3
4

NAME

6       Sub::HandlesVia - alternative handles_via implementation
7

SYNOPSIS

9        package Kitchen {
10          use Moo;
11          use Sub::HandlesVia;
12          use Types::Standard qw( ArrayRef Str );
13
14          has food => (
15            is          => 'ro',
16            isa         => ArrayRef[Str],
17            handles_via => 'Array',
18            default     => sub { [] },
19            handles     => {
20              'add_food'    => 'push',
21              'find_food'   => 'grep',
22            },
23          );
24        }
25
26        my $kitchen = Kitchen->new;
27        $kitchen->add_food('Bacon');
28        $kitchen->add_food('Eggs');
29        $kitchen->add_food('Sausages');
30        $kitchen->add_food('Beans');
31
32        my @foods = $kitchen->find_food(sub { /^B/i });
33

DESCRIPTION

35       If you've used Moose's native attribute traits, or MooX::HandlesVia
36       before, you should have a fairly good idea what this does.
37
38       Why re-invent the wheel? Well, this is an implementation that should
39       work okay with Moo, Moose, Mouse, and any other OO toolkit you throw at
40       it.  One ring to rule them all, so to speak.
41
42       Also, unlike MooX::HandlesVia, it honours type constraints, plus it
43       doesn't have the limitation that it can't mutate non-reference values.
44
45   Using with Moo
46       You should be able to use it as a drop-in replacement for
47       MooX::HandlesVia.
48
49        package Kitchen {
50          use Moo;
51          use Sub::HandlesVia;
52          use Types::Standard qw( ArrayRef Str );
53
54          has food => (
55            is          => 'ro',
56            isa         => ArrayRef[Str],
57            handles_via => 'Array',
58            default     => sub { [] },
59            handles     => {
60              'add_food'    => 'push',
61              'find_food'   => 'grep',
62            },
63          );
64        }
65
66   Using with Mouse
67       It works the same as Moo basically.
68
69        package Kitchen {
70          use Mouse;
71          use Sub::HandlesVia;
72          use Types::Standard qw( ArrayRef Str );
73
74          has food => (
75            is          => 'ro',
76            isa         => ArrayRef[Str],
77            handles_via => 'Array',
78            default     => sub { [] },
79            handles     => {
80              'add_food'    => 'push',
81              'find_food'   => 'grep',
82            },
83          );
84        }
85
86       You are not forced to use Types::Standard. Mouse native types should
87       work fine.
88
89        package Kitchen {
90          use Mouse;
91          use Sub::HandlesVia;
92
93          has food => (
94            is          => 'ro',
95            isa         => 'ArrayRef[Str]',
96            handles_via => 'Array',
97            default     => sub { [] },
98            handles     => {
99              'add_food'    => 'push',
100              'find_food'   => 'grep',
101            },
102          );
103        }
104
105       Sub::HandlesVia will also recognize MooseX::NativeTraits-style traits.
106       It will jump in and handle them before MooseX::NativeTraits notices!
107
108        package Kitchen {
109          use Mouse;
110          use Sub::HandlesVia;
111
112          has food => (
113            is          => 'ro',
114            isa         => 'ArrayRef[Str]',
115            traits      => ['Array'],
116            default     => sub { [] },
117            handles     => {
118              'add_food'    => 'push',
119              'find_food'   => 'grep',
120            },
121          );
122        }
123
124       (If you have a mouse in your kitchen though, that might not be very
125       hygienic.)
126
127   Using with Moose
128       It works the same as Mouse basically.
129
130        package Kitchen {
131          use Moose;
132          use Sub::HandlesVia;
133          use Types::Standard qw( ArrayRef Str );
134
135          has food => (
136            is          => 'ro',
137            isa         => ArrayRef[Str],
138            handles_via => 'Array',
139            default     => sub { [] },
140            handles     => {
141              'add_food'    => 'push',
142              'find_food'   => 'grep',
143            },
144          );
145        }
146
147       You are not forced to use Types::Standard. Moose native types should
148       work fine.
149
150        package Kitchen {
151          use Moose;
152          use Sub::HandlesVia;
153
154          has food => (
155            is          => 'ro',
156            isa         => 'ArrayRef[Str]',
157            handles_via => 'Array',
158            default     => sub { [] },
159            handles     => {
160              'add_food'    => 'push',
161              'find_food'   => 'grep',
162            },
163          );
164        }
165
166       Sub::HandlesVia will also recognize native-traits-style traits. It will
167       jump in and handle them before Moose notices!
168
169        package Kitchen {
170          use Moose;
171          use Sub::HandlesVia;
172
173          has food => (
174            is          => 'ro',
175            isa         => 'ArrayRef[Str]',
176            traits      => ['Array'],
177            default     => sub { [] },
178            handles     => {
179              'add_food'    => 'push',
180              'find_food'   => 'grep',
181            },
182          );
183        }
184
185       (If you have a moose in your kitchen, that might be even worse than the
186       mouse.)
187
188   Using with Anything
189       For Moose and Mouse, Sub::HandlesVia can use their metaobject protocols
190       to grab an attribute's definition and install the methods it needs to.
191       For Moo, it can wrap "has" and do its stuff that way. For other
192       classes, you need to be more explicit and tell it what methods to
193       delegate to what attributes.
194
195        package Kitchen {
196          use Class::Tiny {
197            food => sub { [] },
198          };
199
200          use Sub::HandlesVia qw( delegations );
201
202          delegations(
203            attribute   => 'food'
204            handles_via => 'Array',
205            handles     => {
206              'add_food'    => 'push',
207              'find_food'   => 'grep',
208            },
209          );
210        }
211
212       Setting "attribute" to "food" means that when Sub::HandlesVia needs to
213       get the food list, it will call "$kitchen->food" and when it needs to
214       set the food list, it will call "$kitchen->food($value)".  If you have
215       separate getter and setter methods, just do:
216
217            attribute   => [ 'get_food', 'set_food' ],
218
219       Or if you don't have any accessors and want Sub::HandlesVia to directly
220       access the underlying hashref:
221
222            attribute   => '{food}',
223
224       Or maybe you have a setter, but want to use hashref access for the
225       getter:
226
227            attribute   => [ '{food}', 'set_food' ],
228
229       Or maybe you still want direct access for the getter, but your object
230       is a blessed arrayref instead of a blessed hashref:
231
232            attribute   => [ '[7]', 'set_food' ],
233
234       Or maybe your needs are crazy unique:
235
236            attribute   => [ \&getter, \&setter ],
237
238       The coderefs are passed the instance as their first argument, and the
239       setter is also passed a value to set.
240
241       Really, I don't think there's any object system that this won't work
242       for!
243
244       If you supply an arrayref with a getter and setter, it's also possible
245       to supply a third argument which is a coderef or string which will be
246       called as a method if needing to "reset" the value.  This can be
247       thought of like a default or builder.
248
249       (The "delegations" function can be imported into Moo/Mouse/Moose
250       classes too, in which case the "attribute" needs to be the same
251       attribute name you passed to "has". You cannot use a arrayref, coderef,
252       hash key, or array index.)
253
254   What methods can be delegated to?
255       The following table compares Sub::HandlesVia with Data::Perl, Moose
256       native traits, and MouseX::NativeTraits.
257
258         Array ===========================================
259                   accessor : SubHV  DataP  Moose  Mouse
260                        all : SubHV  DataP
261                   all_true : SubHV
262                        any : SubHV                Mouse
263                      apply : SubHV                Mouse
264                      clear : SubHV  DataP  Moose  Mouse
265                      count : SubHV  DataP  Moose  Mouse
266                     delete : SubHV  DataP  Moose  Mouse
267                   elements : SubHV  DataP  Moose  Mouse
268                      fetch :                      Mouse  (alias: get)
269                      first : SubHV  DataP  Moose  Mouse
270                first_index : SubHV  DataP  Moose
271                    flatten : SubHV  DataP
272               flatten_deep : SubHV  DataP
273                   for_each : SubHV                Mouse
274              for_each_pair : SubHV                Mouse
275                        get : SubHV  DataP  Moose  Mouse
276                       grep : SubHV  DataP  Moose  Mouse
277                       head : SubHV  DataP
278                     insert : SubHV  DataP  Moose  Mouse
279                   is_empty : SubHV  DataP  Moose  Mouse
280                       join : SubHV  DataP  Moose  Mouse
281                        map : SubHV  DataP  Moose  Mouse
282                        max : SubHV
283                     maxstr : SubHV
284                        min : SubHV
285                     minstr : SubHV
286                   natatime : SubHV  DataP  Moose
287               not_all_true : SubHV
288                  pairfirst : SubHV
289                   pairgrep : SubHV
290                   pairkeys : SubHV
291                    pairmap : SubHV
292                      pairs : SubHV
293                 pairvalues : SubHV
294                pick_random : SubHV
295                        pop : SubHV  DataP  Moose  Mouse
296                      print : SubHV  DataP
297                    product : SubHV
298                       push : SubHV  DataP  Moose  Mouse
299                     reduce : SubHV  DataP  Moose  Mouse
300                 reductions : SubHV
301                     remove :                      Mouse  (alias: delete)
302                      reset : SubHV
303                    reverse : SubHV  DataP
304                     sample : SubHV
305                        set : SubHV  DataP  Moose  Mouse
306              shallow_clone : SubHV  DataP  Moose
307                      shift : SubHV  DataP  Moose  Mouse
308                    shuffle : SubHV  DataP  Moose  Mouse
309           shuffle_in_place : SubHV
310                       sort : SubHV  DataP  Moose  Mouse
311                    sort_by :                      Mouse  (sort)
312              sort_in_place : SubHV  DataP  Moose  Mouse
313           sort_in_place_by :                      Mouse  (sort_in_place)
314                     splice : SubHV  DataP  Moose  Mouse
315                      store :                      Mouse  (alias: set)
316                        sum : SubHV
317                       tail : SubHV  DataP
318                       uniq : SubHV  DataP  Moose  Mouse
319              uniq_in_place : SubHV
320                    uniqnum : SubHV
321           uniqnum_in_place : SubHV
322                    uniqstr : SubHV
323           uniqstr_in_place : SubHV
324                    unshift : SubHV  DataP  Moose  Mouse
325
326         Bool ============================================
327                        not : SubHV  DataP  Moose  Mouse
328                      reset : SubHV
329                        set : SubHV  DataP  Moose  Mouse
330                     toggle : SubHV  DataP  Moose  Mouse
331                      unset : SubHV  DataP  Moose  Mouse
332
333         Code ============================================
334                    execute : SubHV  DataP  Moose  Mouse
335             execute_method : SubHV         Moose  Mouse
336
337         Counter =========================================
338                        dec : SubHV  DataP  Moose  Mouse
339                        inc : SubHV  DataP  Moose  Mouse
340                      reset : SubHV  DataP  Moose  Mouse
341                        set : SubHV         Moose  Mouse
342
343         Hash ============================================
344                   accessor : SubHV  DataP  Moose  Mouse
345                        all : SubHV  DataP
346                      clear : SubHV  DataP  Moose  Mouse
347                      count : SubHV  DataP  Moose  Mouse
348                    defined : SubHV  DataP  Moose  Mouse
349                     delete : SubHV  DataP  Moose  Mouse
350                   elements : SubHV  DataP  Moose  Mouse
351                     exists : SubHV  DataP  Moose  Mouse
352                      fetch :                      Mouse  (alias: get)
353               for_each_key : SubHV                Mouse
354              for_each_pair : SubHV                Mouse
355             for_each_value : SubHV                Mouse
356                        get : SubHV  DataP  Moose  Mouse
357                   is_empty : SubHV  DataP  Moose  Mouse
358                       keys : SubHV  DataP  Moose  Mouse
359                         kv : SubHV  DataP  Moose  Mouse
360                      reset : SubHV
361                        set : SubHV  DataP  Moose  Mouse
362              shallow_clone : SubHV  DataP  Moose
363                sorted_keys : SubHV                Mouse
364                      store :                      Mouse  (alias: set)
365                     values : SubHV  DataP  Moose  Mouse
366
367         Number ==========================================
368                        abs : SubHV  DataP  Moose  Mouse
369                        add : SubHV  DataP  Moose  Mouse
370                        div : SubHV  DataP  Moose  Mouse
371                        get : SubHV
372                        mod : SubHV  DataP  Moose  Mouse
373                        mul : SubHV  DataP  Moose  Mouse
374                        set : SubHV         Moose
375                        sub : SubHV  DataP  Moose  Mouse
376
377         String ==========================================
378                     append : SubHV  DataP  Moose  Mouse
379                      chomp : SubHV  DataP  Moose  Mouse
380                       chop : SubHV  DataP  Moose  Mouse
381                      clear : SubHV  DataP  Moose  Mouse
382                        get : SubHV
383                        inc : SubHV  DataP  Moose  Mouse
384                     length : SubHV  DataP  Moose  Mouse
385                      match : SubHV  DataP  Moose  Mouse
386                    prepend : SubHV  DataP  Moose  Mouse
387                    replace : SubHV  DataP  Moose  Mouse
388           replace_globally : SubHV                Mouse
389                      reset : SubHV
390                        set : SubHV
391                     substr : SubHV  DataP  Moose  Mouse
392
393   Method Chaining
394       Say you have the following
395
396            handles_via => 'Array',
397            handles     => {
398              'add_food'    => 'push',
399              'find_food'   => 'grep',
400              'remove_food' => 'pop',
401            },
402
403       Now "$kitchen->remove_food" will remove the last food on the list and
404       return it. But what if we don't care about what food was removed? We
405       just want to remove the food and discard it. You can do this:
406
407            handles_via => 'Array',
408            handles     => {
409              'add_food'    => 'push',
410              'find_food'   => 'grep',
411              'remove_food' => 'pop...',
412            },
413
414       Now the "remove_food" method will return the kitchen object instead of
415       returning the food. This makes it suitable for chaining method calls:
416
417         # remove the three most recent foods
418         $kitchen->remove_food->remove_food->remove_food;
419
420   Hand Waving
421       Sub::HandlesVia tries to be strict by default, but you can tell it to
422       be less rigourous checking method arguments, etc using the "~" prefix:
423
424            handles_via => 'Array',
425            handles     => {
426              'find_food'   => '~grep',
427            },
428
429   CodeRefs
430       You can delegate to coderefs:
431
432            handles_via => 'Array',
433            handles    => {
434              'find_healthiest' => sub { my $foods = shift; ... },
435            }
436
437   Named Methods
438       Let's say "FoodList" is a class where instances are blessed arrayrefs
439       of strings.
440
441            isa         => InstanceOf['FoodList'],
442            handles_via => 'Array',
443            handles     => {
444              'find_food'             => 'grep',
445              'find_healthiest_food'  => 'find_healthiest',
446            },
447
448       Now "$kitchen->find_food($coderef)" does this (which breaks
449       encapsulation of course):
450
451         my @result = grep $coderef->(), @{ $kitchen->food };
452
453       And "$kitchen->find_healthiest_food" does this:
454
455         $kitchen->food->find_healthiest
456
457       Basically, because "find_healthiest" isn't one of the methods offered
458       by Sub::HandlesVia::HandlerList::Array, it assumes you want to call it
459       on the arrayref like a proper method.
460
461   Currying Favour
462       All this talk of food is making me hungry, but as much as I'd like to
463       eat a curry right now, that's not the kind of currying we're talking
464       about.
465
466            handles_via => 'Array',
467            handles     => {
468              'get_food'   => 'get',
469            },
470
471       "$kitchen->get_food(0)" will return the first item on the list.
472       "$kitchen->get_food(1)" will return the second item on the list.  And
473       so on.
474
475            handles_via => 'Array',
476            handles     => {
477              'first_food'   => [ 'get' => 0 ],
478              'second_food'  => [ 'get' => 1 ],
479            },
480
481       I think you already know what this does. Right?
482
483       And yes, currying works with coderefs.
484
485            handles_via => 'Array',
486            handles     => {
487              'blargy'       => [ sub { ... }, @curried ],
488            },
489
490   Pick and Mix
491           isa         => ArrayRef|HashRef,
492           handles_via => [ 'Array', 'Hash' ],
493           handles     => {
494             the_keys     => 'keys',
495             ship_shape   => 'sort_in_place',
496           }
497
498       Here you have an attribute which might be an arrayref or a hashref.
499       When it's an arrayref, "$object->ship_shape" will work nicely, but
500       "$object->the_keys" will fail badly.
501
502       Still, this sort of thing can kind of make sense if you have an object
503       that overloads both "@{}" and "%{}".
504
505       Sometime a method will be ambiguous. For example, there's a "get"
506       method for both hashes and arrays. In this case, the array one will win
507       because you listed it first in "handles_via".
508
509       But you can be specific:
510
511           isa         => ArrayRef|HashRef,
512           handles_via => [ 'Array', 'Hash' ],
513           handles     => {
514             get_foo => 'Array->get',
515             get_bar => 'Hash->get',
516           }
517

BUGS

519       Please report any bugs to
520       <http://rt.cpan.org/Dist/Display.html?Queue=Sub-HandlesVia>.
521
522       (There are known bugs for Moose native types that do coercion.)
523

SEE ALSO

525       Moose, MouseX::NativeTraits, Data::Perl, MooX::HandlesVia.
526

AUTHOR

528       Toby Inkster <tobyink@cpan.org>.
529
531       This software is copyright (c) 2020 by Toby Inkster.
532
533       This is free software; you can redistribute it and/or modify it under
534       the same terms as the Perl 5 programming language system itself.
535

DISCLAIMER OF WARRANTIES

537       THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
538       WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
539       MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
540
541
542
543perl v5.34.0                      2021-10-22                Sub::HandlesVia(3)
Impressum