File Coverage

blib/lib/autodie/hints.pm
Criterion Covered Total %
statement 82 95 86.3
branch 23 34 67.6
condition 3 12 25.0
subroutine 17 17 100.0
pod 1 5 20.0
total 126 163 77.3


line stmt bran cond sub pod time code
1             package autodie::hints;
2              
3 12     12   1578 use strict;
  12         17  
  12         489  
4 12     12   53 use warnings;
  12         16  
  12         453  
5              
6 12     12   46 use constant PERL58 => ( $] < 5.009 );
  12         15  
  12         1949  
7              
8             our $VERSION = '2.29'; # VERSION: Generated by DZP::OurPkg:Version
9              
10             # ABSTRACT: Provide hints about user subroutines to autodie
11              
12             =head1 NAME
13              
14             autodie::hints - Provide hints about user subroutines to autodie
15              
16             =head1 SYNOPSIS
17              
18             package Your::Module;
19              
20             our %DOES = ( 'autodie::hints::provider' => 1 );
21              
22             sub AUTODIE_HINTS {
23             return {
24             foo => { scalar => HINTS, list => SOME_HINTS },
25             bar => { scalar => HINTS, list => MORE_HINTS },
26             }
27             }
28              
29             # Later, in your main program...
30              
31             use Your::Module qw(foo bar);
32             use autodie qw(:default foo bar);
33              
34             foo(); # succeeds or dies based on scalar hints
35              
36             # Alternatively, hints can be set on subroutines we've
37             # imported.
38              
39             use autodie::hints;
40             use Some::Module qw(think_positive);
41              
42             BEGIN {
43             autodie::hints->set_hints_for(
44             \&think_positive,
45             {
46             fail => sub { $_[0] <= 0 }
47             }
48             )
49             }
50             use autodie qw(think_positive);
51              
52             think_positive(...); # Returns positive or dies.
53              
54              
55             =head1 DESCRIPTION
56              
57             =head2 Introduction
58              
59             The L<autodie> pragma is very smart when it comes to working with
60             Perl's built-in functions. The behaviour for these functions are
61             fixed, and C<autodie> knows exactly how they try to signal failure.
62              
63             But what about user-defined subroutines from modules? If you use
64             C<autodie> on a user-defined subroutine then it assumes the following
65             behaviour to demonstrate failure:
66              
67             =over
68              
69             =item *
70              
71             A false value, in scalar context
72              
73             =item *
74              
75             An empty list, in list context
76              
77             =item *
78              
79             A list containing a single undef, in list context
80              
81             =back
82              
83             All other return values (including the list of the single zero, and the
84             list containing a single empty string) are considered successful. However,
85             real-world code isn't always that easy. Perhaps the code you're working
86             with returns a string containing the word "FAIL" upon failure, or a
87             two element list containing C<(undef, "human error message")>. To make
88             autodie work with these sorts of subroutines, we have
89             the I<hinting interface>.
90              
91             The hinting interface allows I<hints> to be provided to C<autodie>
92             on how it should detect failure from user-defined subroutines. While
93             these I<can> be provided by the end-user of C<autodie>, they are ideally
94             written into the module itself, or into a helper module or sub-class
95             of C<autodie> itself.
96              
97             =head2 What are hints?
98              
99             A I<hint> is a subroutine or value that is checked against the
100             return value of an autodying subroutine. If the match returns true,
101             C<autodie> considers the subroutine to have failed.
102              
103             If the hint provided is a subroutine, then C<autodie> will pass
104             the complete return value to that subroutine. If the hint is
105             any other value, then C<autodie> will smart-match against the
106             value provided. In Perl 5.8.x there is no smart-match operator, and as such
107             only subroutine hints are supported in these versions.
108              
109             Hints can be provided for both scalar and list contexts. Note
110             that an autodying subroutine will never see a void context, as
111             C<autodie> always needs to capture the return value for examination.
112             Autodying subroutines called in void context act as if they're called
113             in a scalar context, but their return value is discarded after it
114             has been checked.
115              
116             =head2 Example hints
117              
118             Hints may consist of scalars, array references, regular expressions and
119             subroutine references. You can specify different hints for how
120             failure should be identified in scalar and list contexts.
121              
122             These examples apply for use in the C<AUTODIE_HINTS> subroutine and when
123             calling C<autodie::hints->set_hints_for()>.
124              
125             The most common context-specific hints are:
126              
127             # Scalar failures always return undef:
128             { scalar => undef }
129              
130             # Scalar failures return any false value [default expectation]:
131             { scalar => sub { ! $_[0] } }
132              
133             # Scalar failures always return zero explicitly:
134             { scalar => '0' }
135              
136             # List failures always return an empty list:
137             { list => [] }
138              
139             # List failures return () or (undef) [default expectation]:
140             { list => sub { ! @_ || @_ == 1 && !defined $_[0] } }
141              
142             # List failures return () or a single false value:
143             { list => sub { ! @_ || @_ == 1 && !$_[0] } }
144              
145             # List failures return (undef, "some string")
146             { list => sub { @_ == 2 && !defined $_[0] } }
147              
148             # Unsuccessful foo() returns 'FAIL' or '_FAIL' in scalar context,
149             # returns (-1) in list context...
150             autodie::hints->set_hints_for(
151             \&foo,
152             {
153             scalar => qr/^ _? FAIL $/xms,
154             list => [-1],
155             }
156             );
157              
158             # Unsuccessful foo() returns 0 in all contexts...
159             autodie::hints->set_hints_for(
160             \&foo,
161             {
162             scalar => 0,
163             list => [0],
164             }
165             );
166              
167             This "in all contexts" construction is very common, and can be
168             abbreviated, using the 'fail' key. This sets both the C<scalar>
169             and C<list> hints to the same value:
170              
171             # Unsuccessful foo() returns 0 in all contexts...
172             autodie::hints->set_hints_for(
173             \&foo,
174             {
175             fail => sub { @_ == 1 and defined $_[0] and $_[0] == 0 }
176             }
177             );
178              
179             # Unsuccessful think_positive() returns negative number on failure...
180             autodie::hints->set_hints_for(
181             \&think_positive,
182             {
183             fail => sub { $_[0] < 0 }
184             }
185             );
186              
187             # Unsuccessful my_system() returns non-zero on failure...
188             autodie::hints->set_hints_for(
189             \&my_system,
190             {
191             fail => sub { $_[0] != 0 }
192             }
193             );
194              
195             =head1 Manually setting hints from within your program
196              
197             If you are using a module which returns something special on failure, then
198             you can manually create hints for each of the desired subroutines. Once
199             the hints are specified, they are available for all files and modules loaded
200             thereafter, thus you can move this work into a module and it will still
201             work.
202              
203             use Some::Module qw(foo bar);
204             use autodie::hints;
205              
206             autodie::hints->set_hints_for(
207             \&foo,
208             {
209             scalar => SCALAR_HINT,
210             list => LIST_HINT,
211             }
212             );
213             autodie::hints->set_hints_for(
214             \&bar,
215             { fail => SOME_HINT, }
216             );
217              
218             It is possible to pass either a subroutine reference (recommended) or a fully
219             qualified subroutine name as the first argument. This means you can set hints
220             on modules that I<might> get loaded:
221              
222             use autodie::hints;
223             autodie::hints->set_hints_for(
224             'Some::Module:bar', { fail => SCALAR_HINT, }
225             );
226              
227             This technique is most useful when you have a project that uses a
228             lot of third-party modules. You can define all your possible hints
229             in one-place. This can even be in a sub-class of autodie. For
230             example:
231              
232             package my::autodie;
233              
234             use parent qw(autodie);
235             use autodie::hints;
236              
237             autodie::hints->set_hints_for(...);
238              
239             1;
240              
241             You can now C<use my::autodie>, which will work just like the standard
242             C<autodie>, but is now aware of any hints that you've set.
243              
244             =head1 Adding hints to your module
245              
246             C<autodie> provides a passive interface to allow you to declare hints for
247             your module. These hints will be found and used by C<autodie> if it
248             is loaded, but otherwise have no effect (or dependencies) without autodie.
249             To set these, your module needs to declare that it I<does> the
250             C<autodie::hints::provider> role. This can be done by writing your
251             own C<DOES> method, using a system such as C<Class::DOES> to handle
252             the heavy-lifting for you, or declaring a C<%DOES> package variable
253             with a C<autodie::hints::provider> key and a corresponding true value.
254              
255             Note that checking for a C<%DOES> hash is an C<autodie>-only
256             short-cut. Other modules do not use this mechanism for checking
257             roles, although you can use the C<Class::DOES> module from the
258             CPAN to allow it.
259              
260             In addition, you must define a C<AUTODIE_HINTS> subroutine that returns
261             a hash-reference containing the hints for your subroutines:
262              
263             package Your::Module;
264              
265             # We can use the Class::DOES from the CPAN to declare adherence
266             # to a role.
267              
268             use Class::DOES 'autodie::hints::provider' => 1;
269              
270             # Alternatively, we can declare the role in %DOES. Note that
271             # this is an autodie specific optimisation, although Class::DOES
272             # can be used to promote this to a true role declaration.
273              
274             our %DOES = ( 'autodie::hints::provider' => 1 );
275              
276             # Finally, we must define the hints themselves.
277              
278             sub AUTODIE_HINTS {
279             return {
280             foo => { scalar => HINTS, list => SOME_HINTS },
281             bar => { scalar => HINTS, list => MORE_HINTS },
282             baz => { fail => HINTS },
283             }
284             }
285              
286             This allows your code to set hints without relying on C<autodie> and
287             C<autodie::hints> being loaded, or even installed. In this way your
288             code can do the right thing when C<autodie> is installed, but does not
289             need to depend upon it to function.
290              
291             =head1 Insisting on hints
292              
293             When a user-defined subroutine is wrapped by C<autodie>, it will
294             use hints if they are available, and otherwise reverts to the
295             I<default behaviour> described in the introduction of this document.
296             This can be problematic if we expect a hint to exist, but (for
297             whatever reason) it has not been loaded.
298              
299             We can ask autodie to I<insist> that a hint be used by prefixing
300             an exclamation mark to the start of the subroutine name. A lone
301             exclamation mark indicates that I<all> subroutines after it must
302             have hints declared.
303              
304             # foo() and bar() must have their hints defined
305             use autodie qw( !foo !bar baz );
306              
307             # Everything must have hints (recommended).
308             use autodie qw( ! foo bar baz );
309              
310             # bar() and baz() must have their hints defined
311             use autodie qw( foo ! bar baz );
312              
313             # Enable autodie for all of Perl's supported built-ins,
314             # as well as for foo(), bar() and baz(). Everything must
315             # have hints.
316             use autodie qw( ! :all foo bar baz );
317              
318             If hints are not available for the specified subroutines, this will cause a
319             compile-time error. Insisting on hints for Perl's built-in functions
320             (eg, C<open> and C<close>) is always successful.
321              
322             Insisting on hints is I<strongly> recommended.
323              
324             =cut
325              
326             # TODO: implement regular expression hints
327              
328 12     12   60 use constant UNDEF_ONLY => sub { not defined $_[0] };
  12         16  
  12         834  
  0         0  
329             use constant EMPTY_OR_UNDEF => sub {
330 0 0 0     0 ! @_ or
331             @_==1 && !defined $_[0]
332 12     12   52 };
  12         21  
  12         703  
333              
334 12     12   52 use constant EMPTY_ONLY => sub { @_ == 0 };
  12         21  
  12         782  
  0         0  
335             use constant EMPTY_OR_FALSE => sub {
336 0 0 0     0 ! @_ or
337             @_==1 && !$_[0]
338 12     12   59 };
  12         14  
  12         832  
339              
340 12 50   12   54 use constant SINGLE_TRUE => sub { @_ == 1 and not $_[0] };
  12         22  
  12         815  
  7         205  
341              
342 12         642 use constant DEFAULT_HINTS => {
343             scalar => UNDEF_ONLY,
344             list => EMPTY_OR_UNDEF,
345 12     12   63 };
  12         19  
346              
347              
348 12     12   64 use constant HINTS_PROVIDER => 'autodie::hints::provider';
  12         19  
  12         2594  
349              
350             our $DEBUG = 0;
351              
352             # Only ( undef ) is a strange but possible situation for very
353             # badly written code. It's not supported yet.
354              
355             my %Hints = (
356             'File::Copy::copy' => { scalar => SINGLE_TRUE, list => SINGLE_TRUE },
357             'File::Copy::move' => { scalar => SINGLE_TRUE, list => SINGLE_TRUE },
358             'File::Copy::cp' => { scalar => SINGLE_TRUE, list => SINGLE_TRUE },
359             'File::Copy::mv' => { scalar => SINGLE_TRUE, list => SINGLE_TRUE },
360             );
361              
362             # Start by using Sub::Identify if it exists on this system.
363              
364             eval { require Sub::Identify; Sub::Identify->import('get_code_info'); };
365              
366             # If it doesn't exist, we'll define our own. This code is directly
367             # taken from Rafael Garcia's Sub::Identify 0.04, used under the same
368             # license as Perl itself.
369              
370             if ($@) {
371             require B;
372              
373 12     12   55 no warnings 'once';
  12         15  
  12         2977  
374              
375             *get_code_info = sub ($) {
376              
377             my ($coderef) = @_;
378             ref $coderef or return;
379             my $cv = B::svref_2object($coderef);
380             $cv->isa('B::CV') or return;
381             # bail out if GV is undefined
382             $cv->GV->isa('B::SPECIAL') and return;
383              
384             return ($cv->GV->STASH->NAME, $cv->GV->NAME);
385             };
386              
387             }
388              
389             sub sub_fullname {
390 143     143 0 972 return join( '::', get_code_info( $_[1] ) );
391             }
392              
393             my %Hints_loaded = ();
394              
395             sub load_hints {
396 30     30 0 35 my ($class, $sub) = @_;
397              
398 30         142 my ($package) = ( $sub =~ /(.*)::/ );
399              
400 30 50       70 if (not defined $package) {
401 0         0 require Carp;
402 0         0 Carp::croak(
403             "Internal error in autodie::hints::load_hints - no package found.
404             ");
405             }
406              
407             # Do nothing if we've already tried to load hints for
408             # this package.
409 30 100       108 return if $Hints_loaded{$package}++;
410              
411 9         12 my $hints_available = 0;
412              
413             {
414 12     12   64 no strict 'refs'; ## no critic
  12         17  
  12         6454  
  9         13  
415              
416 9 100 66     208 if ($package->can('DOES') and $package->DOES(HINTS_PROVIDER) ) {
    100          
417 3         24 $hints_available = 1;
418             }
419 6         32 elsif ( PERL58 and $package->isa(HINTS_PROVIDER) ) {
420             $hints_available = 1;
421             }
422             elsif ( ${"${package}::DOES"}{HINTS_PROVIDER.""} ) {
423 2         3 $hints_available = 1;
424             }
425             }
426              
427 9 100       34 return if not $hints_available;
428              
429 5         11 my %package_hints = %{ $package->AUTODIE_HINTS };
  5         23  
430              
431 5         110 foreach my $sub (keys %package_hints) {
432              
433 15         21 my $hint = $package_hints{$sub};
434              
435             # Ensure we have a package name.
436 15 50       45 $sub = "${package}::$sub" if $sub !~ /::/;
437              
438             # TODO - Currently we don't check for conflicts, should we?
439 15         27 $Hints{$sub} = $hint;
440              
441 15         876 $class->normalise_hints(\%Hints, $sub);
442             }
443              
444 5         14 return;
445              
446             }
447              
448             sub normalise_hints {
449 24     24 0 29 my ($class, $hints, $sub) = @_;
450              
451 24 100       58 if ( exists $hints->{$sub}->{fail} ) {
452              
453 6 50 33     28 if ( exists $hints->{$sub}->{scalar} or
454             exists $hints->{$sub}->{list}
455             ) {
456             # TODO: Turn into a proper diagnostic.
457 0         0 require Carp;
458 0         0 local $Carp::CarpLevel = 1;
459 0         0 Carp::croak("fail hints cannot be provided with either scalar or list hints for $sub");
460             }
461              
462             # Set our scalar and list hints.
463              
464 6         14 $hints->{$sub}->{scalar} =
465             $hints->{$sub}->{list} = delete $hints->{$sub}->{fail};
466              
467 6         12 return;
468              
469             }
470              
471             # Check to make sure all our hints exist.
472              
473 18         26 foreach my $hint (qw(scalar list)) {
474 36 50       87 if ( not exists $hints->{$sub}->{$hint} ) {
475             # TODO: Turn into a proper diagnostic.
476 0         0 require Carp;
477 0         0 local $Carp::CarpLevel = 1;
478 0         0 Carp::croak("$hint hint missing for $sub");
479             }
480             }
481              
482 18         32 return;
483             }
484              
485             sub get_hints_for {
486 89     89 0 103 my ($class, $sub) = @_;
487              
488 89         149 my $subname = $class->sub_fullname( $sub );
489              
490             # If we have hints loaded for a sub, then return them.
491              
492 89 100       212 if ( exists $Hints{ $subname } ) {
493 59         137 return $Hints{ $subname };
494             }
495              
496             # If not, we try to load them...
497              
498 30         57 $class->load_hints( $subname );
499              
500             # ...and try again!
501              
502 30 100       60 if ( exists $Hints{ $subname } ) {
503 5         18 return $Hints{ $subname };
504             }
505              
506             # It's the caller's responsibility to use defaults if desired.
507             # This allows on autodie to insist on hints if needed.
508              
509 25         49 return;
510              
511             }
512              
513             sub set_hints_for {
514 9     9 1 46799 my ($class, $sub, $hints) = @_;
515              
516 9 100       23 if (ref $sub) {
517 8         15 $sub = $class->sub_fullname( $sub );
518              
519 8         26 require Carp;
520              
521 8 50       17 $sub or Carp::croak("Attempts to set_hints_for unidentifiable subroutine");
522             }
523              
524 9 50       17 if ($DEBUG) {
525 0         0 warn "autodie::hints: Setting $sub to hints: $hints\n";
526             }
527              
528 9         16 $Hints{ $sub } = $hints;
529              
530 9         19 $class->normalise_hints(\%Hints, $sub);
531              
532 9         16 return;
533             }
534              
535             1;
536              
537             __END__
538              
539              
540             =head1 Diagnostics
541              
542             =over 4
543              
544             =item Attempts to set_hints_for unidentifiable subroutine
545              
546             You've called C<< autodie::hints->set_hints_for() >> using a subroutine
547             reference, but that reference could not be resolved back to a
548             subroutine name. It may be an anonymous subroutine (which can't
549             be made autodying), or may lack a name for other reasons.
550              
551             If you receive this error with a subroutine that has a real name,
552             then you may have found a bug in autodie. See L<autodie/BUGS>
553             for how to report this.
554              
555             =item fail hints cannot be provided with either scalar or list hints for %s
556              
557             When defining hints, you can either supply both C<list> and
558             C<scalar> keywords, I<or> you can provide a single C<fail> keyword.
559             You can't mix and match them.
560              
561             =item %s hint missing for %s
562              
563             You've provided either a C<scalar> hint without supplying
564             a C<list> hint, or vice-versa. You I<must> supply both C<scalar>
565             and C<list> hints, I<or> a single C<fail> hint.
566              
567             =back
568              
569             =head1 ACKNOWLEDGEMENTS
570              
571             =over
572              
573             =item *
574              
575             Dr Damian Conway for suggesting the hinting interface and providing the
576             example usage.
577              
578             =item *
579              
580             Jacinta Richardson for translating much of my ideas into this
581             documentation.
582              
583             =back
584              
585             =head1 AUTHOR
586              
587             Copyright 2009, Paul Fenwick E<lt>pjf@perltraining.com.auE<gt>
588              
589             =head1 LICENSE
590              
591             This module is free software. You may distribute it under the
592             same terms as Perl itself.
593              
594             =head1 SEE ALSO
595              
596             L<autodie>, L<Class::DOES>
597              
598             =for Pod::Coverage get_hints_for load_hints normalise_hints sub_fullname get_code_info
599              
600             =cut