File Coverage

blib/lib/Sub/HandlesVia.pm
Criterion Covered Total %
statement 62 62 100.0
branch 20 30 66.6
condition 32 48 66.6
subroutine 12 12 100.0
pod 0 1 0.0
total 126 153 82.3


line stmt bran cond sub pod time code
1 95     95   13967640 use 5.008;
  95         808  
2 95     95   564 use strict;
  95         209  
  95         2155  
3 95     95   489 use warnings;
  95         200  
  95         4150  
4              
5             package Sub::HandlesVia;
6              
7 95     95   42994 use Exporter::Shiny qw( delegations );
  95         414928  
  95         2037  
8              
9             our $AUTHORITY = 'cpan:TOBYINK';
10             our $VERSION = '0.050000';
11              
12             sub _generate_delegations {
13 4     4   333 my ($me, $name, $args, $globals) = (shift, @_);
14            
15 4         17 my $target = $globals->{into};
16 4 50       18 !defined $target and die;
17 4 50       13 ref $target and die;
18              
19 4         15 my $toolkit = $me->detect_toolkit($target);
20 4     6   41 return sub { $toolkit->install_delegations(target => $target, @_) };
  6         3228  
21             }
22              
23             sub _exporter_validate_opts {
24 299     299   18844991 my ($me, $globals) = (shift, @_);
25              
26 299         887 my $target = $globals->{into};
27 299 50       2776 !defined $target and die;
28 299 50       1273 ref $target and die;
29              
30 299         1092 my $toolkit = $me->detect_toolkit($target);
31 299 100       5822 $toolkit->setup_for($target) if $toolkit->can('setup_for');
32             }
33              
34             sub detect_toolkit {
35 303     303 0 1268 my $toolkit = sprintf(
36             '%s::Toolkit::%s',
37             __PACKAGE__,
38             shift->_detect_framework(@_),
39             );
40 303 50       20970 eval "require $toolkit" or Exporter::Tiny::_croak($@);
41 303         1611 return $toolkit;
42             }
43              
44             sub _detect_framework {
45 304     304   983 my ($me, $target) = (shift, @_);
46            
47             # Need to ask Role::Tiny too because Moo::Role will pretend
48             # that Moose::Role and Mouse::Role roles are Moo::Role roles!
49             #
50 304 100 100     1555 if ($INC{'Moo/Role.pm'}
      66        
51             and Role::Tiny->is_role($target)
52             and Moo::Role->is_role($target)) {
53 3         158 return 'Moo';
54             }
55            
56 301 50 66     2329 if ($INC{'Moo.pm'}
      33        
57             and $Moo::MAKERS{$target}
58             and $Moo::MAKERS{$target}{is_class}) {
59 105         722 return 'Moo';
60             }
61            
62 196 100 66     1881 if ($INC{'Moose/Role.pm'}
      100        
63             and $target->can('meta')
64             and $target->meta->isa('Moose::Meta::Role')) {
65 3         104 return 'Moose';
66             }
67            
68 193 50 66     3368 if ($INC{'Moose.pm'}
      66        
69             and $target->can('meta')
70             and $target->meta->isa('Moose::Meta::Class')) {
71 86         2231 return 'Moose';
72             }
73              
74 107 100 66     1778 if ($INC{'Mouse/Role.pm'}
      100        
75             and $target->can('meta')
76             and $target->meta->isa('Mouse::Meta::Role')) {
77 4         129 return 'Mouse';
78             }
79            
80 103 50 66     2382 if ($INC{'Mouse.pm'}
      66        
81             and $target->can('meta')
82             and $target->meta->isa('Mouse::Meta::Class')) {
83 85         1823 return 'Mouse';
84             }
85            
86             {
87 95     95   46841 no warnings;
  95         244  
  95         14779  
88 18 50 66     106 if ($INC{'Object/Pad.pm'}
      66        
      33        
89             and 'Object::Pad'->VERSION ge 0.67
90 2         11 and do { require Object::Pad::MOP::Class; 1 }
  2         9  
91 2         10 and eval { Object::Pad::MOP::Class->for_class($target) } ) {
92 2         308 require Scalar::Util;
93 2         31 my $META = Object::Pad::MOP::Class->for_class($target);
94 2 50 33     167 return 'ObjectPad'
95             if Scalar::Util::blessed($META) && $META->isa('Object::Pad::MOP::Class');
96             }
97             }
98            
99             {
100 95     95   2206 no strict 'refs';
  95         266  
  95         3488  
  18         32  
  16         27  
101 95     95   643 no warnings 'once';
  95         240  
  95         12281  
102 16 100       34 if ( ${"$target\::USES_MITE"} ) {
  16         103  
103 10         77 return 'Mite';
104             }
105             }
106            
107 6         41 return 'Plain';
108             }
109              
110             1;
111              
112             __END__
113              
114             =pod
115              
116             =encoding utf-8
117              
118             =head1 NAME
119              
120             Sub::HandlesVia - alternative handles_via implementation
121              
122             =head1 SYNOPSIS
123              
124             package Kitchen {
125             use Moo;
126             use Sub::HandlesVia;
127             use Types::Standard qw( ArrayRef Str );
128            
129             has food => (
130             is => 'ro',
131             isa => ArrayRef[Str],
132             handles_via => 'Array',
133             default => sub { [] },
134             handles => {
135             'add_food' => 'push',
136             'find_food' => 'grep',
137             },
138             );
139             }
140              
141             my $kitchen = Kitchen->new;
142             $kitchen->add_food('Bacon');
143             $kitchen->add_food('Eggs');
144             $kitchen->add_food('Sausages');
145             $kitchen->add_food('Beans');
146            
147             my @foods = $kitchen->find_food(sub { /^B/i });
148              
149             =head1 DESCRIPTION
150              
151             If you've used L<Moose>'s native attribute traits, or L<MooX::HandlesVia>
152             before, you should have a fairly good idea what this does.
153              
154             Why re-invent the wheel? Well, this is an implementation that should work
155             okay with Moo, Moose, Mouse, and any other OO toolkit you throw at it.
156             One ring to rule them all, so to speak.
157              
158             For details of how to use it, see the manual.
159              
160             =over
161              
162             =item L<Sub::HandlesVia::Manual::WithMoo>
163              
164             How to use Sub::HandlesVia with L<Moo> and L<Moo::Role>.
165              
166             =item L<Sub::HandlesVia::Manual::WithMoose>
167              
168             How to use Sub::HandlesVia with L<Moose> and L<Moose::Role>.
169              
170             =item L<Sub::HandlesVia::Manual::WithMouse>
171              
172             How to use Sub::HandlesVia with L<Mouse> and L<Mouse::Role>.
173              
174             =item L<Sub::HandlesVia::Manual::WithMite>
175              
176             How to use Sub::HandlesVia with L<Mite>.
177              
178             =item L<Sub::HandlesVia::Manual::WithClassTiny>
179              
180             How to use Sub::HandlesVia with L<Class::Tiny>.
181              
182             =item L<Sub::HandlesVia::Manual::WithObjectPad>
183              
184             How to use Sub::HandlesVia with L<Object::Pad> classes.
185              
186             =item L<Sub::HandlesVia::Manual::WithGeneric>
187              
188             How to use Sub::HandlesVia with other OO toolkits, and hand-written
189             Perl classes.
190              
191             =back
192              
193             Note: as Sub::HandlesVia needs to detect which toolkit you are using, and
194             often needs to detect whether your package is a class or a role, it needs
195             to be loaded I<after> Moo/Moose/Mouse/etc. Your C<< use Moo >> or
196             C<< use Moose::Role >> or whatever needs to be I<before> your
197             C<< use Sub::HandlesVia >>.
198              
199             =head1 BUGS
200              
201             Please report any bugs to
202             L<https://github.com/tobyink/p5-sub-handlesvia/issues>.
203              
204             (There are known bugs for Moose native types that do coercion.)
205              
206             =head1 SEE ALSO
207              
208             Guides for use with different OO toolkits:
209             L<Sub::HandlesVia::Manual::WithMoo>,
210             L<Sub::HandlesVia::Manual::WithMoose>,
211             L<Sub::HandlesVia::Manual::WithMouse>,
212             L<Sub::HandlesVia::Manual::WithMite>,
213             L<Sub::HandlesVia::Manual::WithClassTiny>,
214             L<Sub::HandlesVia::Manual::WithObjectPad>,
215             L<Sub::HandlesVia::Manual::WithGeneric>.
216              
217             Documentation for delegatable methods:
218             L<Sub::HandlesVia::HandlerLibrary::Array>,
219             L<Sub::HandlesVia::HandlerLibrary::Blessed>,
220             L<Sub::HandlesVia::HandlerLibrary::Bool>,
221             L<Sub::HandlesVia::HandlerLibrary::Code>,
222             L<Sub::HandlesVia::HandlerLibrary::Counter>,
223             L<Sub::HandlesVia::HandlerLibrary::Enum>,
224             L<Sub::HandlesVia::HandlerLibrary::Hash>,
225             L<Sub::HandlesVia::HandlerLibrary::Number>,
226             L<Sub::HandlesVia::HandlerLibrary::Scalar>, and
227             L<Sub::HandlesVia::HandlerLibrary::String>.
228              
229             Other implementations of the same concept:
230             L<Moose::Meta::Attribute::Native>, L<MouseX::NativeTraits>, and
231             L<MooX::HandlesVia> with L<Data::Perl>.
232              
233             Comparison of those: L<Sub::HandlesVia::Manual::Comparison>
234              
235             L<Sub::HandlesVia::Declare> is a helper for declaring Sub::HandlesVia
236             delegations at compile-time, useful for L<Object::Pad> and (to a lesser
237             extent) L<Class::Tiny>.
238              
239             =head1 AUTHOR
240              
241             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
242              
243             =head1 COPYRIGHT AND LICENCE
244              
245             This software is copyright (c) 2020, 2022 by Toby Inkster.
246              
247             This is free software; you can redistribute it and/or modify it under
248             the same terms as the Perl 5 programming language system itself.
249              
250             =head1 DISCLAIMER OF WARRANTIES
251              
252             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
253             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
254             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
255