diff options
Diffstat (limited to 'upstream/debian-unstable/man3/autodie::hints.3perl')
-rw-r--r-- | upstream/debian-unstable/man3/autodie::hints.3perl | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/upstream/debian-unstable/man3/autodie::hints.3perl b/upstream/debian-unstable/man3/autodie::hints.3perl new file mode 100644 index 00000000..eef4531f --- /dev/null +++ b/upstream/debian-unstable/man3/autodie::hints.3perl @@ -0,0 +1,413 @@ +.\" -*- mode: troff; coding: utf-8 -*- +.\" Automatically generated by Pod::Man 5.01 (Pod::Simple 3.43) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. +.ie n \{\ +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is >0, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.nr rF 0 +.if \n(.g .if rF .nr rF 1 +.if (\n(rF:(\n(.g==0)) \{\ +. if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 +. \} +. \} +.\} +.rr rF +.\" ======================================================================== +.\" +.IX Title "autodie::hints 3perl" +.TH autodie::hints 3perl 2024-01-12 "perl v5.38.2" "Perl Programmers Reference Guide" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH NAME +autodie::hints \- Provide hints about user subroutines to autodie +.SH SYNOPSIS +.IX Header "SYNOPSIS" +.Vb 1 +\& package Your::Module; +\& +\& our %DOES = ( \*(Aqautodie::hints::provider\*(Aq => 1 ); +\& +\& sub AUTODIE_HINTS { +\& return { +\& foo => { scalar => HINTS, list => SOME_HINTS }, +\& bar => { scalar => HINTS, list => MORE_HINTS }, +\& } +\& } +\& +\& # Later, in your main program... +\& +\& use Your::Module qw(foo bar); +\& use autodie qw(:default foo bar); +\& +\& foo(); # succeeds or dies based on scalar hints +\& +\& # Alternatively, hints can be set on subroutines we\*(Aqve +\& # imported. +\& +\& use autodie::hints; +\& use Some::Module qw(think_positive); +\& +\& BEGIN { +\& autodie::hints\->set_hints_for( +\& \e&think_positive, +\& { +\& fail => sub { $_[0] <= 0 } +\& } +\& ) +\& } +\& use autodie qw(think_positive); +\& +\& think_positive(...); # Returns positive or dies. +.Ve +.SH DESCRIPTION +.IX Header "DESCRIPTION" +.SS Introduction +.IX Subsection "Introduction" +The autodie pragma is very smart when it comes to working with +Perl's built-in functions. The behaviour for these functions are +fixed, and \f(CW\*(C`autodie\*(C'\fR knows exactly how they try to signal failure. +.PP +But what about user-defined subroutines from modules? If you use +\&\f(CW\*(C`autodie\*(C'\fR on a user-defined subroutine then it assumes the following +behaviour to demonstrate failure: +.IP \(bu 4 +A false value, in scalar context +.IP \(bu 4 +An empty list, in list context +.IP \(bu 4 +A list containing a single undef, in list context +.PP +All other return values (including the list of the single zero, and the +list containing a single empty string) are considered successful. However, +real-world code isn't always that easy. Perhaps the code you're working +with returns a string containing the word "FAIL" upon failure, or a +two element list containing \f(CW\*(C`(undef, "human error message")\*(C'\fR. To make +autodie work with these sorts of subroutines, we have +the \fIhinting interface\fR. +.PP +The hinting interface allows \fIhints\fR to be provided to \f(CW\*(C`autodie\*(C'\fR +on how it should detect failure from user-defined subroutines. While +these \fIcan\fR be provided by the end-user of \f(CW\*(C`autodie\*(C'\fR, they are ideally +written into the module itself, or into a helper module or sub-class +of \f(CW\*(C`autodie\*(C'\fR itself. +.SS "What are hints?" +.IX Subsection "What are hints?" +A \fIhint\fR is a subroutine or value that is checked against the +return value of an autodying subroutine. If the match returns true, +\&\f(CW\*(C`autodie\*(C'\fR considers the subroutine to have failed. +.PP +If the hint provided is a subroutine, then \f(CW\*(C`autodie\*(C'\fR will pass +the complete return value to that subroutine. If the hint is +any other value, then \f(CW\*(C`autodie\*(C'\fR will smart-match against the +value provided. In Perl 5.8.x there is no smart-match operator, and as such +only subroutine hints are supported in these versions. +.PP +Hints can be provided for both scalar and list contexts. Note +that an autodying subroutine will never see a void context, as +\&\f(CW\*(C`autodie\*(C'\fR always needs to capture the return value for examination. +Autodying subroutines called in void context act as if they're called +in a scalar context, but their return value is discarded after it +has been checked. +.SS "Example hints" +.IX Subsection "Example hints" +Hints may consist of subroutine references, objects overloading +smart-match, regular expressions, and depending on Perl version possibly +other things. You can specify different hints for how +failure should be identified in scalar and list contexts. +.PP +These examples apply for use in the \f(CW\*(C`AUTODIE_HINTS\*(C'\fR subroutine and when +calling \f(CW\*(C`autodie::hints\->set_hints_for()\*(C'\fR. +.PP +The most common context-specific hints are: +.PP +.Vb 2 +\& # Scalar failures always return undef: +\& { scalar => sub { !defined($_[0]) } } +\& +\& # Scalar failures return any false value [default expectation]: +\& { scalar => sub { ! $_[0] } } +\& +\& # Scalar failures always return zero explicitly: +\& { scalar => sub { defined($_[0]) && $_[0] eq \*(Aq0\*(Aq } } +\& +\& # List failures always return an empty list: +\& { list => sub { !@_ } } +\& +\& # List failures return () or (undef) [default expectation]: +\& { list => sub { ! @_ || @_ == 1 && !defined $_[0] } } +\& +\& # List failures return () or a single false value: +\& { list => sub { ! @_ || @_ == 1 && !$_[0] } } +\& +\& # List failures return (undef, "some string") +\& { list => sub { @_ == 2 && !defined $_[0] } } +\& +\& # Unsuccessful foo() returns \*(AqFAIL\*(Aq or \*(Aq_FAIL\*(Aq in scalar context, +\& # returns (\-1) in list context... +\& autodie::hints\->set_hints_for( +\& \e&foo, +\& { +\& scalar => qr/^ _? FAIL $/xms, +\& list => sub { @_ == 1 && $_[0] eq \-1 }, +\& } +\& ); +\& +\& # Unsuccessful foo() returns 0 in all contexts... +\& autodie::hints\->set_hints_for( +\& \e&foo, +\& { +\& scalar => sub { defined($_[0]) && $_[0] == 0 }, +\& list => sub { @_ == 1 && defined($_[0]) && $_[0] == 0 }, +\& } +\& ); +.Ve +.PP +This "in all contexts" construction is very common, and can be +abbreviated, using the 'fail' key. This sets both the \f(CW\*(C`scalar\*(C'\fR +and \f(CW\*(C`list\*(C'\fR hints to the same value: +.PP +.Vb 7 +\& # Unsuccessful foo() returns 0 in all contexts... +\& autodie::hints\->set_hints_for( +\& \e&foo, +\& { +\& fail => sub { @_ == 1 and defined $_[0] and $_[0] == 0 } +\& } +\& ); +\& +\& # Unsuccessful think_positive() returns negative number on failure... +\& autodie::hints\->set_hints_for( +\& \e&think_positive, +\& { +\& fail => sub { $_[0] < 0 } +\& } +\& ); +\& +\& # Unsuccessful my_system() returns non\-zero on failure... +\& autodie::hints\->set_hints_for( +\& \e&my_system, +\& { +\& fail => sub { $_[0] != 0 } +\& } +\& ); +.Ve +.SH "Manually setting hints from within your program" +.IX Header "Manually setting hints from within your program" +If you are using a module which returns something special on failure, then +you can manually create hints for each of the desired subroutines. Once +the hints are specified, they are available for all files and modules loaded +thereafter, thus you can move this work into a module and it will still +work. +.PP +.Vb 2 +\& use Some::Module qw(foo bar); +\& use autodie::hints; +\& +\& autodie::hints\->set_hints_for( +\& \e&foo, +\& { +\& scalar => SCALAR_HINT, +\& list => LIST_HINT, +\& } +\& ); +\& autodie::hints\->set_hints_for( +\& \e&bar, +\& { fail => SOME_HINT, } +\& ); +.Ve +.PP +It is possible to pass either a subroutine reference (recommended) or a fully +qualified subroutine name as the first argument. This means you can set hints +on modules that \fImight\fR get loaded: +.PP +.Vb 4 +\& use autodie::hints; +\& autodie::hints\->set_hints_for( +\& \*(AqSome::Module:bar\*(Aq, { fail => SCALAR_HINT, } +\& ); +.Ve +.PP +This technique is most useful when you have a project that uses a +lot of third-party modules. You can define all your possible hints +in one-place. This can even be in a sub-class of autodie. For +example: +.PP +.Vb 1 +\& package my::autodie; +\& +\& use parent qw(autodie); +\& use autodie::hints; +\& +\& autodie::hints\->set_hints_for(...); +\& +\& 1; +.Ve +.PP +You can now \f(CW\*(C`use my::autodie\*(C'\fR, which will work just like the standard +\&\f(CW\*(C`autodie\*(C'\fR, but is now aware of any hints that you've set. +.SH "Adding hints to your module" +.IX Header "Adding hints to your module" +\&\f(CW\*(C`autodie\*(C'\fR provides a passive interface to allow you to declare hints for +your module. These hints will be found and used by \f(CW\*(C`autodie\*(C'\fR if it +is loaded, but otherwise have no effect (or dependencies) without autodie. +To set these, your module needs to declare that it \fIdoes\fR the +\&\f(CW\*(C`autodie::hints::provider\*(C'\fR role. This can be done by writing your +own \f(CW\*(C`DOES\*(C'\fR method, using a system such as \f(CW\*(C`Class::DOES\*(C'\fR to handle +the heavy-lifting for you, or declaring a \f(CW%DOES\fR package variable +with a \f(CW\*(C`autodie::hints::provider\*(C'\fR key and a corresponding true value. +.PP +Note that checking for a \f(CW%DOES\fR hash is an \f(CW\*(C`autodie\*(C'\fR\-only +short-cut. Other modules do not use this mechanism for checking +roles, although you can use the \f(CW\*(C`Class::DOES\*(C'\fR module from the +CPAN to allow it. +.PP +In addition, you must define a \f(CW\*(C`AUTODIE_HINTS\*(C'\fR subroutine that returns +a hash-reference containing the hints for your subroutines: +.PP +.Vb 1 +\& package Your::Module; +\& +\& # We can use the Class::DOES from the CPAN to declare adherence +\& # to a role. +\& +\& use Class::DOES \*(Aqautodie::hints::provider\*(Aq => 1; +\& +\& # Alternatively, we can declare the role in %DOES. Note that +\& # this is an autodie specific optimisation, although Class::DOES +\& # can be used to promote this to a true role declaration. +\& +\& our %DOES = ( \*(Aqautodie::hints::provider\*(Aq => 1 ); +\& +\& # Finally, we must define the hints themselves. +\& +\& sub AUTODIE_HINTS { +\& return { +\& foo => { scalar => HINTS, list => SOME_HINTS }, +\& bar => { scalar => HINTS, list => MORE_HINTS }, +\& baz => { fail => HINTS }, +\& } +\& } +.Ve +.PP +This allows your code to set hints without relying on \f(CW\*(C`autodie\*(C'\fR and +\&\f(CW\*(C`autodie::hints\*(C'\fR being loaded, or even installed. In this way your +code can do the right thing when \f(CW\*(C`autodie\*(C'\fR is installed, but does not +need to depend upon it to function. +.SH "Insisting on hints" +.IX Header "Insisting on hints" +When a user-defined subroutine is wrapped by \f(CW\*(C`autodie\*(C'\fR, it will +use hints if they are available, and otherwise reverts to the +\&\fIdefault behaviour\fR described in the introduction of this document. +This can be problematic if we expect a hint to exist, but (for +whatever reason) it has not been loaded. +.PP +We can ask autodie to \fIinsist\fR that a hint be used by prefixing +an exclamation mark to the start of the subroutine name. A lone +exclamation mark indicates that \fIall\fR subroutines after it must +have hints declared. +.PP +.Vb 2 +\& # foo() and bar() must have their hints defined +\& use autodie qw( !foo !bar baz ); +\& +\& # Everything must have hints (recommended). +\& use autodie qw( ! foo bar baz ); +\& +\& # bar() and baz() must have their hints defined +\& use autodie qw( foo ! bar baz ); +\& +\& # Enable autodie for all of Perl\*(Aqs supported built\-ins, +\& # as well as for foo(), bar() and baz(). Everything must +\& # have hints. +\& use autodie qw( ! :all foo bar baz ); +.Ve +.PP +If hints are not available for the specified subroutines, this will cause a +compile-time error. Insisting on hints for Perl's built-in functions +(eg, \f(CW\*(C`open\*(C'\fR and \f(CW\*(C`close\*(C'\fR) is always successful. +.PP +Insisting on hints is \fIstrongly\fR recommended. +.SH Diagnostics +.IX Header "Diagnostics" +.IP "Attempts to set_hints_for unidentifiable subroutine" 4 +.IX Item "Attempts to set_hints_for unidentifiable subroutine" +You've called \f(CW\*(C`autodie::hints\->set_hints_for()\*(C'\fR using a subroutine +reference, but that reference could not be resolved back to a +subroutine name. It may be an anonymous subroutine (which can't +be made autodying), or may lack a name for other reasons. +.Sp +If you receive this error with a subroutine that has a real name, +then you may have found a bug in autodie. See "BUGS" in autodie +for how to report this. +.ie n .IP "fail hints cannot be provided with either scalar or list hints for %s" 4 +.el .IP "fail hints cannot be provided with either scalar or list hints for \f(CW%s\fR" 4 +.IX Item "fail hints cannot be provided with either scalar or list hints for %s" +When defining hints, you can either supply both \f(CW\*(C`list\*(C'\fR and +\&\f(CW\*(C`scalar\*(C'\fR keywords, \fIor\fR you can provide a single \f(CW\*(C`fail\*(C'\fR keyword. +You can't mix and match them. +.ie n .IP "%s hint missing for %s" 4 +.el .IP "\f(CW%s\fR hint missing for \f(CW%s\fR" 4 +.IX Item "%s hint missing for %s" +You've provided either a \f(CW\*(C`scalar\*(C'\fR hint without supplying +a \f(CW\*(C`list\*(C'\fR hint, or vice-versa. You \fImust\fR supply both \f(CW\*(C`scalar\*(C'\fR +and \f(CW\*(C`list\*(C'\fR hints, \fIor\fR a single \f(CW\*(C`fail\*(C'\fR hint. +.SH ACKNOWLEDGEMENTS +.IX Header "ACKNOWLEDGEMENTS" +.IP \(bu 4 +Dr Damian Conway for suggesting the hinting interface and providing the +example usage. +.IP \(bu 4 +Jacinta Richardson for translating much of my ideas into this +documentation. +.SH AUTHOR +.IX Header "AUTHOR" +Copyright 2009, Paul Fenwick <pjf@perltraining.com.au> +.SH LICENSE +.IX Header "LICENSE" +This module is free software. You may distribute it under the +same terms as Perl itself. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +autodie, Class::DOES |