File Coverage

blib/lib/IO/Handle/Util.pm
Criterion Covered Total %
statement 112 120 93.3
branch 33 44 75.0
condition 11 19 57.8
subroutine 29 29 100.0
pod 17 17 100.0
total 202 229 88.2


line stmt bran cond sub pod time code
1             package IO::Handle::Util;
2              
3 3     3   40995 use strict;
  3         6  
  3         122  
4 3     3   19 use warnings;
  3         4  
  3         178  
5              
6             our $VERSION = "0.01";
7             $VERSION = eval $VERSION;
8              
9              
10 3     3   17 use warnings::register;
  3         11  
  3         505  
11              
12 3     3   17 use Scalar::Util ();
  3         5  
  3         65  
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   4213 use IO::Handle ();
  3         68025  
  3         74  
19 3     3   2934 use FileHandle ();
  3         15033  
  3         393  
20              
21             # fake handle types
22             #use IO::String ();
23             #use IO::Handle::Iterator ();
24              
25             #use IO::Handle::Prototype::Fallback ();
26              
27 3         99 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   3573 };
  3         96278  
82              
83             sub io_to_write_cb ($) {
84 2     2 1 3691 my $fh = io_from_any(shift);
85              
86             return sub {
87 4     4   1244 local $,;
88 4         12 local $\;
89 4 50       21 $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 2         63 }
99              
100             sub io_to_read_cb ($) {
101 1     1 1 656 my $fh = io_from_any(shift);
102              
103 1     3   6 return sub { scalar $fh->getline() };
  3         1341  
104             }
105              
106             sub io_to_string ($) {
107 3     3 1 844 my $thing = shift;
108              
109 3 100 66     24 if ( defined $thing and not ref $thing ) {
110 1         5 return $thing;
111             } else {
112 2         5 my $fh = io_from_any($thing);
113              
114             # list context is in case ->getline ignores $/,
115             # which is likely the case with ::Iterator
116 2         6 local $/;
117 2         23 return join "", <$fh>;
118             }
119             }
120              
121             sub io_to_list ($) {
122 2     2 1 4 my $thing = shift;
123              
124 2 50       6 warnings::warnif(__PACKAGE__, "io_to_list not invoked in list context")
125             unless wantarray;
126              
127 2 100       6 if ( ref $thing eq 'ARRAY' ) {
128 1         7 return @$thing;
129             } else {
130 1         3 my $fh = io_from_any($thing);
131 1         11 return <$fh>;
132             }
133             }
134              
135             sub io_to_array ($) {
136 2     2 1 353 my $thing = shift;
137              
138 2 100       7 if ( ref $thing eq 'ARRAY' ) {
139 1         7 return $thing;
140             } else {
141 1         3 my $fh = io_from_any($thing);
142              
143 1         21 return [ <$fh> ];
144             }
145             }
146              
147             sub io_to_glob {
148 14     14 1 1233 my $thing = shift;
149              
150 14         49 my $fh = io_from_any($thing);
151              
152 14 100 66     111 if ( ref($fh) eq 'GLOB' or ref($fh) eq 'IO::Handle' ) {
153 1         4 return $fh;
154             } else {
155             # wrap in a tied handle
156 13         75 my $glob = Symbol::gensym();
157              
158 13         2046 require IO::Handle::Util::Tie;
159 13         161 tie *$glob, 'IO::Handle::Util::Tie', $fh;
160              
161 13         85 return $glob;
162             }
163             }
164              
165             sub io_from_any ($) {
166 27     27 1 8555 my $thing = shift;
167              
168 27 100       89 if ( ref $thing ) {
169 26         66 return io_from_ref($thing);
170             } else {
171 1         3 return io_from_string($thing);
172             }
173             }
174              
175             sub io_from_ref ($) {
176 26     26 1 44 my $ref = shift;
177              
178 26 100 100     161 if ( Scalar::Util::blessed($ref) ) {
  8 100       47  
    100          
    50          
    0          
179 14         46 return io_from_object($ref);
180             } 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 8         25 return $ref;
184             } elsif ( ref $ref eq 'ARRAY' ) {
185 2         6 return io_from_array($ref);
186             } elsif ( ref $ref eq 'SCALAR' ) {
187 2         8 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 14     14 1 32 my $obj = shift;
197              
198 14 50 33     1151 if ( $obj->isa("IO::Handle") or $obj->can("getline") && $obj->can("print") ) {
    0 66        
199 14         132 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 1     1 1 3 my $string = shift; # make sure it's a copy, IO::String will use \$_[0]
210 1         8 require IO::String;
211 1         8 return IO::String->new($string);
212             }
213              
214             sub io_from_array ($) {
215 5     5 1 1026 my $array = shift;
216              
217 5         15 my @array = @$array;
218              
219 5         1058 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 23 100   23   45 if ( @array ) {
224 18         68 return shift @array;
225             } else {
226 5         14 return;
227             }
228 5         56 });
229             }
230              
231             sub io_from_scalar_ref ($) {
232 2     2 1 6 my $ref = shift;
233 2         1075 require IO::String;
234 2         3052 return IO::String->new($ref);
235             }
236              
237             sub io_from_thunk ($) {
238 2     2 1 972 my $thunk = shift;
239              
240 2         4 my @lines;
241              
242 2         12 require IO::Handle::Iterator;
243              
244             return IO::Handle::Iterator->new(sub {
245 5 100   5   13 if ( $thunk ) {
246 2         6 @lines = $thunk->();
247 2         10 undef $thunk;
248             }
249              
250 5 100       18 if ( @lines ) {
251 3         13 return shift @lines;
252             } else {
253 2         5 return;
254             }
255 2         17 });
256             }
257              
258             sub io_from_getline ($) {
259 1     1 1 262 my $cb = shift;
260              
261 1         7 require IO::Handle::Iterator;
262              
263 1         5 return IO::Handle::Iterator->new($cb);
264             }
265              
266             sub io_from_write_cb ($) {
267 1     1 1 292 my $cb = shift;
268              
269             io_prototype( __write => sub {
270 5     5   6 local $,;
271 5         14 local $\;
272 5         14 $cb->($_[1]);
273 1         6 } );
274             }
275              
276             sub io_prototype {
277 1     1 1 1245 require IO::Handle::Prototype::Fallback;
278 1         10 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 5     5 1 1766 my $fh = shift;
286              
287 5         20 my $reftype = Scalar::Util::reftype($fh);
288              
289 5 50 50     25 if ( $reftype eq 'IO'
  5   33     22  
290             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 5         23 my $m_fileno = $fh->fileno;
300              
301 5 100       36 return '' unless defined $m_fileno;
302 3 100       15 return '' unless $m_fileno >= 0;
303              
304 1         3 my $f_fileno = fileno($fh);
305              
306 1 50       5 return '' unless defined $f_fileno;
307 1 50       15 return '' unless $f_fileno >= 0;
308              
309 1         4 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__
323              
324             =pod
325              
326             =head1 NAME
327              
328             IO::Handle::Util - Functions for working with L<IO::Handle> like objects.
329              
330             =head1 SYNOPSIS
331              
332             # make something that looks like a filehandle from a random data:
333             my $io = io_from_any $some_data;
334              
335             # or from a callback that returns strings:
336             my $io = io_from_getline sub { return $another_line };
337              
338             # create a callback that iterates through the handle
339             my $read_cb = io_to_read_cb $io;
340              
341             =head1 DESCRIPTION
342              
343             This module provides a number of helpful routines to manipulate or create
344             L<IO::Handle> like objects.
345              
346             =head1 EXPORTS
347              
348             =head2 Coercions resulting in IO objects
349              
350             These are available using the C<:io_from> export group.
351              
352             =over 4
353              
354             =item io_from_any $whatever
355              
356             Inspects the value of C<whatever> and calls the appropriate coercion function
357             on it, either C<io_from_ref> or C<io_from_string>.
358              
359             =item io_from_ref $some_ref
360              
361             Depending on the reference type of C<$some_ref> invokes either
362             C<io_from_object>, C<io_from_array> or C<io_from_scalar_ref>.
363              
364             Code references are not coerced automatically because either C<io_from_thunk>
365             or C<io_from_getline> or C<io_from_write_cb> could all make sense.
366              
367             Globs are returned as is B<only> if they have a valid C<IO> slot.
368              
369             =item io_from_object $obj
370              
371             Depending on the class of C<$obj> either returns or coerces the object.
372              
373             Objects that are passed through include anything that subclasses L<IO::Handle>
374             or seems to duck type (supports the C<print> and C<getline> methods, which
375             might be a bit too permissive).
376              
377             Objects that are coerced currently only include L<Path::Class::File>, which
378             will have the C<openr> method invoked on it.
379              
380             Anything else is an error.
381              
382             =over 4
383              
384             =item io_from_string $str
385              
386             Instantiates an L<IO::String> object using C<$str> as the buffer.
387              
388             Note that C<$str> is B<not> passed as an alias, so writing to the IO object
389             will not modify string. For that see C<io_from_scalar_ref>.
390              
391             =item io_from_array \@array
392              
393             Creates an L<IO::Handle::Iterator> that will return the elements of C<@array>
394             one by one.
395              
396             Note that a I<copy> of C<@array> is made.
397              
398             In order to be able to append more elements to the array or remove the ones
399             that have been returned use L<IO::Handle::Iterator> yourself directly.
400              
401             =item io_from_scalar_ref \$str
402              
403             Creates an L<IO::String> object using C<$str> as the buffer.
404              
405             Writing to the IO object will modify C<$str>.
406              
407             =item io_from_thunk sub { ... }
408              
409             Invokes the callback once in list context the first time it's needed, and then
410             returns each element of the list like C<io_from_array> would.
411              
412             =item io_from_getline sub { ... }
413              
414             Creates an L<IO::Handle::Iterator> object using the callback.
415              
416             =item io_from_write_cb sub { ... }
417              
418             Creates an L<IO::Handle::Prototype::Fallback> using the callback.
419              
420             The callback will always be invoked with one string argument and with the
421             values of C<$,> and C<$\> localized to C<undef>.
422              
423             =back
424              
425             =head2 Coercions utilizing IO objects
426              
427             These coercions will actually call C<io_from_any> on their argument first. This
428             allows you to do things like:
429              
430             my $str = '';
431             my $sub = io_to_write_cb(\$str);
432              
433             $sub->("foo");
434              
435             These are available using the C<:io_to> export group.
436              
437             =over 4
438              
439             =item io_to_write_cb $thing
440              
441             Creates a code ref that will invoke C<print> on the handle with the arguments
442             to the callback.
443              
444             C<$,> and C<$\> will both be localized to C<undef>.
445              
446             =item io_to_read_cb $thing
447              
448             Creates a code ref that will invoke C<getline> on the handle.
449              
450             C<$/> will not be localized and should probably be set to a reference to a
451             number if you want efficient iteration. See L<perlvar> for details.
452              
453             =item io_to_string $thing
454              
455             Slurps a string out of the IO object by reading all the data.
456              
457             If a string was passed it is returned as is.
458              
459             =item io_to_array $thing
460              
461             Returns an array reference containing all the lines of the IO object.
462              
463             If an array reference was passed it is returned as is.
464              
465             =item io_to_list $thing
466              
467             Returns the list of lines from the IO object.
468              
469             Warns if not invoked in list context.
470              
471             If an array reference was passed it is dereferenced an its elements are
472             returned.
473              
474             =item io_to_glob $thing
475              
476             If the filehandle is an unblessed glob returns it as is, otherwise returns a
477             new glob which is tied to delegate to the OO interface.
478              
479             This lets you use most of the builtins without the method syntax:
480              
481             my $fh = io_to_glob($some_kind_of_OO_handle);
482              
483             while ( defined( my $line = <$fh> ) ) {
484             ...
485             }
486              
487             =back
488              
489             =head2 Misc functions
490              
491             =over 4
492              
493             =item io_prototype %callbacks
494              
495             Given a key-value pair list of named callbacks, constructs an
496             L<IO::Handle::Prototype::Fallback> object with those callbacks.
497              
498             For example:
499              
500             my $io = io_prototype print => sub {
501             my $self = shift;
502              
503             no warnings 'uninitialized';
504             $string .= join($,, @_) . $\;
505             };
506              
507             $io->say("Hello"); # $string now has "Hello\n"
508              
509             See L<IO::Handle::Prototype::Fallback> for more details.
510              
511             =item is_real_fh $io
512              
513             Returns true if the IO handle probably could be passed to something like
514             L<AnyEvent::Handle> which would break encapsulation.
515              
516             Checks for the following conditions:
517              
518             =over 4
519              
520             =item *
521              
522             The handle has a reftype of either a C<GLOB> with an C<IO> slot, or is an C<IO>
523             itself.
524              
525             =item *
526              
527             The handle's C<fileno> method returns a positive number, corresponding to a
528             filedescriptor.
529              
530             =item *
531              
532             The C<fileno> builtin returns the same thing as C<fileno> invoked as a method.
533              
534             =back
535              
536             If these conditions hold the handle is I<probably> OK to work with using the IO
537             builtins directly, or passing the filedesctiptor to C land, instead of by
538             invoking methods on it.
539              
540             =back
541              
542             =head1 SEE ALSO
543              
544             L<IO::Handle>, L<FileHandle>, L<IO::String>, L<perlio>, L<perlfunc/open>
545              
546             =head1 VERSION CONTROL
547              
548             L<http://github.com/nothingmuch/io-handle-util>
549              
550             =head1 AUTHOR
551              
552             Yuval Kogman
553              
554             =head1 COPYRIGHT & LICENSE
555              
556             Copyright (c) 2009 Yuval Kogman. All rights reserved
557             This program is free software; you can redistribute
558             it and/or modify it under the same terms as Perl itself.
559              
560             =cut