.\" -*- 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 "IO::Detect 3pm" .TH IO::Detect 3pm 2024-01-21 "perl v5.38.2" "User Contributed Perl Documentation" .\" 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 IO::Detect \- is this a frickin' filehandle or what?! .SH SYNOPSIS .IX Header "SYNOPSIS" .Vb 1 \& use IO::Detect; \& \& if (is_filehandle $fh) \& { \& my $line = <$fh>; \& } .Ve .SH DESCRIPTION .IX Header "DESCRIPTION" It is stupidly complicated to detect whether a given scalar is a filehandle (or something filehandle like) in Perl. This module attempts to do so, but probably falls short in some cases. The primary advantage of using this module is that it gives you somebody to blame (me) if your code can't detect a\ filehandle. .PP The main use case for IO::Detect is for when you are writing functions and you want to allow the caller to pass a file as an argument without being fussy as to whether they pass a file name or a file handle. .SS Functions .IX Subsection "Functions" Each function takes a single argument, or if called with no argument, operates on \f(CW$_\fR. .ie n .IP """is_filehandle $thing""" 4 .el .IP "\f(CWis_filehandle $thing\fR" 4 .IX Item "is_filehandle $thing" Theoretically returns true if and only if \f(CW$thing\fR is a file handle, or may be treated as a filehandle. That includes blessed references to filehandles, things that inherit from IO::Handle, etc. .Sp It's never going to work 100%. What Perl allows you to use as a filehandle is mysterious and somewhat context-dependent, as the following code illustrates. .Sp .Vb 2 \& my $fh = "STD" . "OUT"; \& print $fh "Hello World!\en"; .Ve .ie n .IP """is_filename $thing""" 4 .el .IP "\f(CWis_filename $thing\fR" 4 .IX Item "is_filename $thing" Returns true if \f(CW$thing\fR is a IO::All object or Path::Class::Entity or "any non-reference, non-zero-length string with no line breaks". That's because depending on your operating system, virtually anything can be used as a filename. (In fact, on many systems, including Linux, filenames can contain line breaks. However, this is unlikely to be intentional.) .Sp This function doesn't tell you whether \f(CW$thing\fR is an existing file on your system. It attempts to tell you whether \f(CW$thing\fR could possibly be a filename on some system somewhere. .ie n .IP """is_fileuri $thing""" 4 .el .IP "\f(CWis_fileuri $thing\fR" 4 .IX Item "is_fileuri $thing" Returns true if \f(CW$thing\fR is a URI beginning with "file://". It allows for URI objects, RDF::Trine::Node::Resource objects, strings and objects that overload stringification. .Sp This function actually returns an "interesting value of true". The value returned is a URI::file object. .ie n .IP """as_filehandle $thing, $mode""" 4 .el .IP "\f(CWas_filehandle $thing, $mode\fR" 4 .IX Item "as_filehandle $thing, $mode" Returns \f(CW$thing\fR if it is a filehandle; otherwise opens it with mode \&\f(CW$mode\fR (croaking if it cannot be opened). \f(CW$mode\fR defaults to "<" (read access). .Sp This function is not exported by default, but needs to be requested explicitly: .Sp .Vb 1 \& use IO::Detect qw(as_filehandle); .Ve .Sp You may even specify a different default mode, or import it several times with different names: .Sp .Vb 3 \& use IO::Detect \& as_filehandle => { \-as => \*(Aqas_filehandle_read\*(Aq, mode => \*(Aq<\*(Aq }, \& as_filehandle => { \-as => \*(Aqas_filehandle_write\*(Aq, mode => \*(Aq>\*(Aq }; .Ve .SS "Smart Matching" .IX Subsection "Smart Matching" You can import three constants for use in smart matching: .PP .Vb 1 \& use IO::Detect \-smartmatch; .Ve .PP These constants are: .ie n .IP """FileHandle""" 4 .el .IP \f(CWFileHandle\fR 4 .IX Item "FileHandle" .PD 0 .ie n .IP """FileName""" 4 .el .IP \f(CWFileName\fR 4 .IX Item "FileName" .ie n .IP """FileUri""" 4 .el .IP \f(CWFileUri\fR 4 .IX Item "FileUri" .PD .PP They can be used like this: .PP .Vb 4 \& if ($file ~~ FileHandle) \& { \& ... \& } .Ve .PP Note that there does exist a FileHandle package in Perl core. This module attempts to do the right thing so that \f(CW\*(C`FileHandle\->new\*(C'\fR still works, but there are conceivably places this could go wrong, or be plain old confusing. .PP Although \f(CW\*(C`is_filehandle\*(C'\fR and its friends support Perl 5.8 and above, smart match is only available in Perl 5.10 onwards. .SS "Use with Scalar::Does" .IX Subsection "Use with Scalar::Does" The smart match constants can also be used with Scalar::Does: .PP .Vb 8 \& if (does $file, FileHandle) \& { \& ...; \& } \& elsif (does $file, FileName) \& { \& ...; \& } .Ve .SS Precedence .IX Subsection "Precedence" Because there is some overlap/ambiguity between what is a filehandle and what is a filename, etc, if you need to detect between them, I recommend checking \f(CW\*(C`is_filehandle\*(C'\fR first, then \f(CW\*(C`is_fileuri\*(C'\fR and falling back to \f(CW\*(C`is_filename\*(C'\fR. .PP .Vb 7 \& for ($file) \& { \& when (FileHandle) { ... } \& when (FileUri) { ... } \& when (FileName) { ... } \& default { die "$file is not a file!" } \& } .Ve .SS Export .IX Subsection "Export" Like Scalar::Does, IO::Detect plays some tricks with namespace::clean to ensure that any functions it exports to your namespace are cleaned up when you're finished with them. .PP \fIDuck Typing\fR .IX Subsection "Duck Typing" .PP In some cases you might be happy to accept something less than a complete file handle. In this case you can import a customised "duck type" test... .PP .Vb 6 \& use IO::Detect \& \-default, \& ducktype => { \& \-as => \*(Aqis_slurpable\*(Aq, \& methods => [qw(getlines close)], \& }; \& \& sub do_something_with_a_file \& { \& my $f = shift; \& if ( is_filehandle $f or is_slurpable $f ) \& { ... } \& elsif ( is_filename $f ) \& { ... } \& } .Ve .PP Duck type test functions only test that the argument is blessed and can do all of the specified methods. They don't test any other aspect of "filehandliness". .SH BUGS .IX Header "BUGS" Please report any bugs to . .SH "SEE ALSO" .IX Header "SEE ALSO" This module is an attempt to capture some of the wisdom from this PerlMonks thread into executable code. .PP Various other modules that may be of interest, in no particular order... Scalar::Does, Scalar::Util, FileHandle, IO::Handle, IO::Handle::Util, IO::All, Path::Class, URI::file. .SH AUTHOR .IX Header "AUTHOR" Toby Inkster . .SH "COPYRIGHT AND LICENCE" .IX Header "COPYRIGHT AND LICENCE" This software is copyright (c) 2012\-2014, 2017 by Toby Inkster. .PP This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. .SH "DISCLAIMER OF WARRANTIES" .IX Header "DISCLAIMER OF WARRANTIES" THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.