File Coverage

blib/lib/IO/Handle/Util.pm
Criterion Covered Total %
statement 54 120 45.0
branch 12 44 27.2
condition 4 19 21.0
subroutine 16 29 55.1
pod 17 17 100.0
total 103 229 44.9


line stmt bran cond sub pod time code
1             package IO::Handle::Util;
2              
3 3     3   27232 use strict;
  3         6  
  3         94  
4 3     3   15 use warnings;
  3         2  
  3         168  
5              
6             our $VERSION = "0.01_01";
7             $VERSION = eval $VERSION;
8              
9              
10 3     3   16 use warnings::register;
  3         9  
  3         437  
11              
12 3     3   19 use Scalar::Util ();
  3         4  
  3         69  
13              
14             # we use this to create errors
15             #use autodie ();
16              
17             # perl blesses IO objects into these namespaces, make sure they are loaded
18 3     3   1819 use IO::Handle ();
  3         17725  
  3         73  
19 3     3   1509 use FileHandle ();
  3         9882  
  3         233  
20              
21             # fake handle types
22             #use IO::String ();
23             #use IO::Handle::Iterator ();
24              
25             #use IO::Handle::Prototype::Fallback ();
26              
27 3         65 use Sub::Exporter -setup => {
28             exports => [qw(
29             io_to_write_cb
30             io_to_read_cb
31             io_to_string
32             io_to_array
33             io_to_list
34             io_to_glob
35              
36             io_from_any
37             io_from_ref
38             io_from_string
39             io_from_object
40             io_from_array
41             io_from_scalar_ref
42             io_from_thunk
43             io_from_getline
44             io_from_write_cb
45             io_prototype
46              
47             is_real_fh
48             )],
49             groups => {
50             io_to => [qw(
51             io_to_write_cb
52             io_to_read_cb
53             io_to_string
54             io_to_array
55             io_to_list
56             io_to_glob
57             )],
58              
59             io_from => [qw(
60             io_from_any
61             io_from_ref
62             io_from_string
63             io_from_object
64             io_from_array
65             io_from_scalar_ref
66             io_from_thunk
67             io_from_getline
68             io_from_write_cb
69             )],
70              
71             coercion => [qw(
72             :io_to
73             :io_from
74             )],
75              
76             misc => [qw(
77             io_prototype
78             is_real_fh
79             )],
80             },
81 3     3   1570 };
  3         29579  
82              
83             sub io_to_write_cb ($) {
84 2     2 1 2790 my $fh = io_from_any(shift);
85              
86             return sub {
87 2     2   702 local $,;
88 2         4 local $\;
89 2 50       13 $fh->print(@_) or do {
90 0         0 my $e = $!;
91 0         0 require autodie;
92 0         0 die autodie::exception->new(
93             function => q{CORE::print}, args => [@_],
94             message => "\$E", errno => $e,
95             );
96             }
97             }
98 1         7 }
99              
100             sub io_to_read_cb ($) {
101 0     0 1 0 my $fh = io_from_any(shift);
102              
103 0     0   0 return sub { scalar $fh->getline() };
  0         0  
104             }
105              
106             sub io_to_string ($) {
107 0     0 1 0 my $thing = shift;
108              
109 0 0 0     0 if ( defined $thing and not ref $thing ) {
110 0         0 return $thing;
111             } else {
112 0         0 my $fh = io_from_any($thing);
113              
114             # list context is in case ->getline ignores $/,
115             # which is likely the case with ::Iterator
116 0         0 local $/;
117 0         0 return join "", <$fh>;
118             }
119             }
120              
121             sub io_to_list ($) {
122 0     0 1 0 my $thing = shift;
123              
124 0 0       0 warnings::warnif(__PACKAGE__, "io_to_list not invoked in list context")
125             unless wantarray;
126              
127 0 0       0 if ( ref $thing eq 'ARRAY' ) {
128 0         0 return @$thing;
129             } else {
130 0         0 my $fh = io_from_any($thing);
131 0         0 return <$fh>;
132             }
133             }
134              
135             sub io_to_array ($) {
136 0     0 1 0 my $thing = shift;
137              
138 0 0       0 if ( ref $thing eq 'ARRAY' ) {
139 0         0 return $thing;
140             } else {
141 0         0 my $fh = io_from_any($thing);
142              
143 0         0 return [ <$fh> ];
144             }
145             }
146              
147             sub io_to_glob {
148 10     10 1 10 my $thing = shift;
149              
150 10         23 my $fh = io_from_any($thing);
151              
152 10 50 33     48 if ( ref($fh) eq 'GLOB' or ref($fh) eq 'IO::Handle' ) {
153 0         0 return $fh;
154             } else {
155             # wrap in a tied handle
156 10         29 my $glob = Symbol::gensym();
157              
158 10         644 require IO::Handle::Util::Tie;
159 10         83 tie *$glob, 'IO::Handle::Util::Tie', $fh;
160              
161 10         44 return $glob;
162             }
163             }
164              
165             sub io_from_any ($) {
166 12     12 1 12 my $thing = shift;
167              
168 12 50       32 if ( ref $thing ) {
169 12         24 return io_from_ref($thing);
170             } else {
171 0         0 return io_from_string($thing);
172             }
173             }
174              
175             sub io_from_ref ($) {
176 12     12 1 14 my $ref = shift;
177              
178 12 100 100     46 if ( Scalar::Util::blessed($ref) ) {
    100          
    50          
    50          
    0          
179 10         18 return io_from_object($ref);
180 1         12 } elsif ( ref $ref eq 'GLOB' and *{$ref}{IO}) {
181             # once IO::Handle is required, entersub DWIMs method invoked on globs
182             # there is no need to bless or IO::Wrap if there's a valid IO slot
183 1         3 return $ref;
184             } elsif ( ref $ref eq 'ARRAY' ) {
185 0         0 return io_from_array($ref);
186             } elsif ( ref $ref eq 'SCALAR' ) {
187 1         4 return io_from_scalar_ref($ref);
188             } elsif ( ref $ref eq 'CODE' ) {
189 0         0 Carp::croak("Coercing an IO object from a coderef is ambiguous. Please use io_from_thunk, io_from_getline or io_from_write_cb directly.");
190             } else {
191 0         0 Carp::croak("Don't know how to make an IO from $ref");
192             }
193             }
194              
195             sub io_from_object ($) {
196 10     10 1 8 my $obj = shift;
197              
198 10 50 0     198 if ( $obj->isa("IO::Handle") or $obj->can("getline") && $obj->can("print") ) {
    0 33        
199 10         67 return $obj;
200             } elsif ( $obj->isa("Path::Class::File") ) {
201 0         0 return $obj->openr; # safe default or open for rw?
202             } else {
203             # FIXME URI? IO::File? IO::Scalar, IO::String etc? make sure they all pass
204 0         0 Carp::croak("Object does not seem to be an IO::Handle lookalike");
205             }
206             }
207              
208             sub io_from_string ($) {
209 0     0 1 0 my $string = shift; # make sure it's a copy, IO::String will use \$_[0]
210 0         0 require IO::String;
211 0         0 return IO::String->new($string);
212             }
213              
214             sub io_from_array ($) {
215 1     1 1 10 my $array = shift;
216              
217 1         3 my @array = @$array;
218              
219 1         8 require IO::Handle::Iterator;
220              
221             # IO::Lines/IO::ScalarArray is part of IO::stringy which is considered bad.
222             IO::Handle::Iterator->new(sub {
223 9 100   9   16 if ( @array ) {
224 8         18 return shift @array;
225             } else {
226 1         2 return;
227             }
228 1         14 });
229             }
230              
231             sub io_from_scalar_ref ($) {
232 1     1 1 1 my $ref = shift;
233 1         303 require IO::String;
234 0           return IO::String->new($ref);
235             }
236              
237             sub io_from_thunk ($) {
238 0     0 1   my $thunk = shift;
239              
240 0           my @lines;
241              
242 0           require IO::Handle::Iterator;
243              
244             return IO::Handle::Iterator->new(sub {
245 0 0   0     if ( $thunk ) {
246 0           @lines = $thunk->();
247 0           undef $thunk;
248             }
249              
250 0 0         if ( @lines ) {
251 0           return shift @lines;
252             } else {
253 0           return;
254             }
255 0           });
256             }
257              
258             sub io_from_getline ($) {
259 0     0 1   my $cb = shift;
260              
261 0           require IO::Handle::Iterator;
262              
263 0           return IO::Handle::Iterator->new($cb);
264             }
265              
266             sub io_from_write_cb ($) {
267 0     0 1   my $cb = shift;
268              
269             io_prototype( __write => sub {
270 0     0     local $,;
271 0           local $\;
272 0           $cb->($_[1]);
273 0           } );
274             }
275              
276             sub io_prototype {
277 0     0 1   require IO::Handle::Prototype::Fallback;
278 0           IO::Handle::Prototype::Fallback->new(@_);
279             }
280              
281             # returns true if the handle is (hopefully) suitable for passing to things that
282             # want to do non method operations on it, including operations that need a
283             # proper file descriptor
284             sub is_real_fh ($) {
285 0     0 1   my $fh = shift;
286              
287 0           my $reftype = Scalar::Util::reftype($fh);
288              
289 0 0 0       if ( $reftype eq 'IO'
      0        
290 0           or $reftype eq 'GLOB' && *{$fh}{IO}
291             ) {
292             # if it's a blessed glob make sure to not break encapsulation with
293             # fileno($fh) (e.g. if you are filtering output then file descriptor
294             # based operations might no longer be valid).
295             # then ensure that the fileno *opcode* agrees too, that there is a
296             # valid IO object inside $fh either directly or indirectly and that it
297             # corresponds to a real file descriptor.
298              
299 0           my $m_fileno = $fh->fileno;
300              
301 0 0         return '' unless defined $m_fileno;
302 0 0         return '' unless $m_fileno >= 0;
303              
304 0           my $f_fileno = fileno($fh);
305              
306 0 0         return '' unless defined $f_fileno;
307 0 0         return '' unless $f_fileno >= 0;
308              
309 0           return 1;
310             } else {
311             # anything else, including GLOBS without IO (even if they are blessed)
312             # and non GLOB objects that look like filehandle objects cannot have a
313             # valid file descriptor in fileno($fh) context so may break.
314 0           return '';
315             }
316             }
317              
318             __PACKAGE__
319              
320             # ex: set sw=4 et:
321              
322             __END__