File Coverage

blib/lib/IO/Detect.pm
Criterion Covered Total %
statement 124 140 88.5
branch 35 56 62.5
condition 24 49 48.9
subroutine 36 38 94.7
pod 3 3 100.0
total 222 286 77.6


line stmt bran cond sub pod time code
1             package IO::Detect;
2              
3 27     9   173570 use 5.008;
  9         25  
4 27     9   170 use constant { false => !1, true => !0 };
  13         27  
  13         694  
5 13     9   53 use strict;
  13         64  
  10         191  
6 9     9   29 use warnings;
  9         10  
  9         312  
7 9     9   3888 use if $] < 5.010, 'UNIVERSAL::DOES';
  13         73  
  13         62  
8              
9             BEGIN {
10 13     9   450 $IO::Detect::AUTHORITY = 'cpan:TOBYINK';
11 13         207 $IO::Detect::VERSION = '0.203';
12             }
13              
14 9     9   3195 use namespace::clean 0.19;
  9         3399393  
  9         44  
15              
16             EXPORTER:
17             {
18 9     9   1225 use base "Exporter::Tiny";
  9         14  
  9         3646  
19            
20             our %_CONSTANTS;
21             our @EXPORT = qw( is_filehandle is_filename is_fileuri );
22             our @EXPORT_OK = (
23             qw( is_filehandle is_filename is_fileuri ),
24             qw( FileHandle FileName FileUri ),
25             qw( ducktype as_filehandle ),
26             );
27             our %EXPORT_TAGS = (
28             smartmatch => [qw( FileHandle FileName FileUri )],
29             );
30            
31             sub _exporter_validate_opts
32             {
33 7     7   1071 require B;
34 7         11 my $class = shift;
35             $_[0]{exporter} ||= sub {
36 13     13   666 my $into = $_[0]{into};
37 13         16 my ($name, $sym) = @{ $_[1] };
  13         19  
38 13         106 for (grep ref, $into->can($name))
39             {
40 0 50       0 B::svref_2object($_)->STASH->NAME eq $into
41             and _croak("Refusing to overwrite local sub '$name' with export from $class");
42             }
43 13         65 "namespace::clean"->import(-cleanee => $_[0]{into}, $name);
44 9     9   17057 no strict qw(refs);
  9         10  
  9         264  
45 9     9   28 no warnings qw(redefine prototype);
  9         54  
  9         776  
46 13         480 *{"$into\::$name"} = $sym;
  13         77  
47             }
48 7   100     64 }
49             }
50              
51 9     9   4833 use overload qw<>;
  9         7542  
  9         207  
52 9     9   38 use Scalar::Util qw< blessed openhandle reftype >;
  9         10  
  9         608  
53 9     9   35 use Carp qw;
  9         9  
  9         314  
54 9     9   3620 use URI::file;
  9         69382  
  9         6467  
55              
56             sub _lu {
57 0     0   0 require lexical::underscore;
58 0         0 goto \&lexical::underscore;
59             }
60              
61             sub _ducktype
62             {
63 8     8   21 my ($object, $methods) = @_;
64 8 100       54 return unless blessed $object;
65            
66 2 100       3 foreach my $m (@{ $methods || [] })
  2         5  
67             {
68 2 100       19 return unless $object->can($m);
69             }
70            
71 1         4 return true;
72             }
73              
74             sub _generate_ducktype
75             {
76 1     1   25 my ($class, $name, $arg) = @_;
77 1         2 my $methods = $arg->{methods};
78             return sub (;$) {
79 2 50   2   59 @_ = ${+_lu} unless @_;
  0         0  
80 2         4 push @_, $methods;
81 2         6 goto \&_ducktype;
82 1         5 };
83             }
84              
85             my $expected_methods = [
86             qw(close eof fcntl fileno getc getline getlines ioctl read print stat)
87             ];
88              
89             sub is_filehandle (;$)
90             {
91 5 100   23 1 9 my $fh = @_ ? shift : ${+_lu};
  0         0  
92            
93 5 100       21 return true if openhandle $fh;
94            
95             # Logic from IO::Handle::Util
96             {
97 2         2 my $reftype = reftype($fh);
  2         5  
98 2 100       6 $reftype = '' unless defined $reftype;
99            
100 2 50 66     13 if ($reftype eq 'IO'
      66        
101 0         0 or $reftype eq 'GLOB' && *{$fh}{IO})
102             {
103 0         0 for ($fh->fileno, fileno($fh))
104             {
105 0 50       0 return unless defined;
106 0 0       0 return unless $_ >= 0;
107             }
108            
109 0         0 return true;
110             }
111             }
112            
113 2 50 33     8 return true if blessed $fh && $fh->DOES('IO::Handle');
114 2 50 33     10 return true if blessed $fh && $fh->DOES('FileHandle');
115 2 50 33     5 return true if blessed $fh && $fh->DOES('IO::All');
116            
117 2         9 return _ducktype $fh, $expected_methods;
118             }
119              
120             sub _oneline ($)
121             {
122 1     1   9 !! ( $_[0] !~ /\r?\n|\r/s )
123             }
124              
125             sub is_filename (;$)
126             {
127 4 50   4 1 35 my $f = @_ ? shift : ${+_lu};
  0         0  
128 4 50 33     15 return true if blessed $f && $f->DOES('IO::All');
129 4 50 33     8 return true if blessed $f && $f->DOES('Path::Class::Entity');
130 4 50 0     10 return ( length "$f" and _oneline "$f" )
      33        
131             if blessed $f && overload::Method($f, q[""]);
132 4 100 66     27 return ( length $f and _oneline $f )
      100        
133             if defined $f && !ref $f;
134 2         9 return;
135             }
136              
137             sub is_fileuri (;$)
138             {
139 3 50   3 1 342 my $f = @_ ? shift : ${+_lu};
  0         0  
140 3 50 33     12 return $f if blessed $f && $f->DOES('URI::file');
141 3 50 33     9 return URI::file->new($f->uri) if blessed $f && $f->DOES('RDF::Trine::Node::Resource');
142 3 50       12 return URI::file->new($f) if $f =~ m{^file://\S+}i;
143 3         9 return;
144             }
145              
146             sub _generate_as_filehandle
147             {
148 10     10   32 my ($class, $name, $arg) = @_;
149 10   100     61 my $default_mode = $arg->{mode} || '<';
150            
151             return sub (;$$)
152             {
153 1 50   1   6 my $f = @_ ? shift : ${+_lu};
  0         0  
154 1 50       3 return $f if is_filehandle($f);
155            
156 1 50       2 if (my $uri = is_fileuri($f))
157 0         0 { $f = $uri->file }
158            
159 1   33     10 my $mode = shift || $default_mode;
160 1 50   1   34 open my $fh, $mode, $f
  1         6  
  1         1  
  1         6  
161             or croak "Cannot open '$f' with mode '$mode': $!, died";
162 1         8562 return $fh;
163 10         46 };
164             }
165              
166             *as_filehandle = __PACKAGE__->_generate_as_filehandle('as_filehandle', +{});
167              
168             {
169             package IO::Detect::SmartMatcher;
170             BEGIN {
171 9     9   18 $IO::Detect::SmartMatcher::AUTHORITY = 'cpan:TOBYINK';
172 9         149 $IO::Detect::SmartMatcher::VERSION = '0.203';
173             }
174 9     9   60 use Scalar::Util qw< blessed >;
  9         25  
  9         383  
175 9     9   36 use overload (); no warnings 'overload'; # '~~' unavailable in Perl 5.8
  9     9   8  
  9         167  
  9         28  
  9         15  
  9         476  
176             use overload
177 9         58 '""' => 'to_string',
178             '~~' => 'check',
179             '==' => 'check',
180             'eq' => 'check',
181 9     9   33 fallback => 1;
  9         9  
182             sub check
183             {
184 0     0   0 my ($self, $thing) = @_;
185 0         0 $self->[1]->($thing);
186             }
187             sub to_string
188             {
189 2     2   55 shift->[0]
190             }
191             sub new
192             {
193 29     29   2004483 my $proto = shift;
194 29 100 66     197 if (blessed $proto and $proto->isa(__PACKAGE__))
195             {
196 2         60 return "$proto"->new(@_);
197             }
198 27         1692 bless \@_ => $proto;
199             }
200             }
201              
202 9     9   1843 use constant FileHandle => IO::Detect::SmartMatcher::->new(FileHandle => \&is_filehandle);
  9         11  
  9         37  
203 9     9   35 use constant FileName => IO::Detect::SmartMatcher::->new(FileName => \&is_filename);
  9         13  
  9         28  
204 9     9   34 use constant FileUri => IO::Detect::SmartMatcher::->new(FileUri => \&is_fileuri);
  9         8  
  9         22  
205              
206             true;
207              
208             __END__