File Coverage

blib/lib/Bio/Polloc/Polloc/IO.pm
Criterion Covered Total %
statement 94 151 62.2
branch 33 90 36.6
condition 18 47 38.3
subroutine 20 25 80.0
pod 11 11 100.0
total 176 324 54.3


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Bio::Polloc::Polloc::IO - I/O interface for the Bio::Polloc::* packages
4              
5             =head1 AUTHOR - Luis M. Rodriguez-R
6              
7             Email lmrodriguezr at gmail dot com
8              
9             =cut
10              
11             package Bio::Polloc::Polloc::IO;
12 12     12   57 use base qw(Bio::Polloc::Polloc::Root);
  12         26  
  12         1042  
13 12     12   59 use strict;
  12         34  
  12         326  
14 12     12   60 use File::Path;
  12         20  
  12         793  
15 12     12   72 use File::Spec;
  12         21  
  12         303  
16 12     12   17879 use File::Temp;
  12         283388  
  12         1102  
17 12     12   136 use Symbol;
  12         26  
  12         5552  
18             our $VERSION = 1.0503; # [a-version] from Bio::Polloc::Polloc::Version
19              
20              
21             =head1 GLOBALS
22              
23             Global variables controling the behavior of the package
24              
25             =cut
26              
27             our($PATHSEP, $TEMPDIR, $ROOTDIR, $IOTRIALS);
28              
29             =head2 PATHSEP
30              
31             The system's path separator
32              
33             =cut
34              
35             unless (defined $PATHSEP){
36             if($^O =~ m/mswin/i){
37             $PATHSEP = "\\";
38             }elsif($^O =~ m/macos/i){
39             $PATHSEP = ":";
40             }else{
41             $PATHSEP = "/";
42             }
43             }
44              
45             =head2 TEMPDIR
46              
47             The system's temporal directory
48              
49             =cut
50              
51             $TEMPDIR =File::Spec->tmpdir() unless defined $TEMPDIR;
52 0 0 0 0 1 0 sub TEMPDIR { shift if ref $_[0] || $_[0] =~ m/^Bio::Polloc::/ ; $TEMPDIR = shift }
  0         0  
53              
54              
55             =head2 ROOTDIR
56              
57             The system's root directory
58              
59             =cut
60              
61             $ROOTDIR = File::Spec->rootdir() unless defined $ROOTDIR;
62              
63              
64             =head2 IOTRIALS
65              
66             Number of trials before giving up (for network retrieve)
67              
68             =cut
69              
70             $IOTRIALS = 5 unless defined $IOTRIALS;
71              
72              
73              
74             =head1 PUBLIC METHODS
75              
76             Methods provided by the package
77              
78             =cut
79              
80             =head2 new
81              
82             The basic initialization method
83              
84             =head3 Arguments
85              
86             All the parameters are optional:
87              
88             =over
89              
90             =item -input
91              
92             The input resource
93              
94             =item -file
95              
96             The file to read/write
97              
98             =item -fh
99              
100             The GLOB file handle
101              
102             =item -flush
103              
104             Should I flush on every write
105              
106             =item -url
107              
108             The URL to read
109              
110             =back
111              
112             =head3 Returns
113              
114             A L<Bio::Polloc::Polloc::IO> object
115              
116             =cut
117              
118             sub new {
119 246     246 1 377 my($caller, @args) = @_;
120 246         954 my $self = $caller->SUPER::new(@args);
121 246         757 $self->_initialize_io(@args);
122 246         547 return $self;
123             }
124              
125             =head2 file
126              
127             =cut
128              
129             sub file {
130 18     18 1 30 my($self,$value) = @_;
131 18 100       53 $self->{'_file'} = $value if defined $value;
132 18         90 return $self->{'_file'};
133             }
134              
135             =head2 resource
136              
137             =cut
138              
139             sub resource {
140 5     5 1 12 my ($self,@args) = @_;
141 5 50       15 return $self->file if $self->file;
142 0 0       0 return $self->_fh if $self->_fh;
143 0         0 return "";
144             }
145              
146             =head2 mode
147              
148             =cut
149              
150             sub mode {
151 0     0 1 0 my($self,@args) = @_;
152 0 0       0 return $self->{'_mode'} if defined $self->{'_mode'};
153 0 0       0 my $fh = $self->_fh or return '?';
154            
155 12     12   90 no warnings "io";
  12         65  
  12         19473  
156 0         0 my $line = <$fh>;
157 0 0       0 if ( defined $line ){
158 0         0 $self->_pushback($line);
159 0         0 $self->{'_mode'} = 'r';
160             }else{
161 0         0 $self->{'_mode'} = 'w';
162             }
163 0         0 return $self->{'_mode'};
164             }
165              
166             =head2 close
167              
168             =cut
169              
170             sub close {
171 256     256 1 304 my $self = shift;
172 256 100       597 if(defined $self->{'_filehandle'}){
173 10         90 $self->flush;
174 10 50 66     41 return if \*STDOUT == $self->_fh ||
      66        
175             \*STDIN == $self->_fh ||
176             \*STDERR == $self->_fh;
177 8 50 33     136 if( ! ref($self->{'_filehandle'}) ||
178             ! ! $self->{'_filehandle'}->isa('IO::String') ) {
179 0         0 close($self->{'_filehandle'});
180             }
181             }
182 254         394 $self->{'_filehandle'} = undef;
183 254         628 delete $self->{'_readbuffer'};
184             }
185              
186             =head2 flush
187              
188             =cut
189              
190             sub flush {
191 10     10 1 18 my $self = shift;
192 10 50       40 $self->throw("Attempting to call flush but no filehandle active")
193             if !defined $self->{'_filehandle'};
194 10 50       57 if(ref($self->{'_filehandle'}) =~ /GLOB/){
195 10         47 my $oldh = select $self->{'_filehandle'};
196 10         28 $| = 1;
197 10         42 select $oldh;
198             }else{
199 0         0 $self->{'_filehandle'}->flush;
200             }
201             }
202              
203             =head2 exists_exe
204              
205             =cut
206              
207             sub exists_exe {
208 100     100 1 160 my($self,$exe) = @_;
209 100 50 33     435 $exe = $self if(!(ref($self) || $exe));
210 100 50 33     394 $exe .= '.exe' if(($^O =~ /mswin/i) && ($exe !~ /\.(exe|com|bat|cmd)$/i));
211 100 50       743 return $exe if(-e $exe);
212 100         1371 for my $dir ( File::Spec->path ){
213 700         1579 my $f = Bio::Polloc::Polloc::IO->catfile($dir, $exe);
214 700 50 33     13982 return $f if -e $f && -x $f;
215             }
216 100         353 return 0;
217             }
218              
219             =head2 tempfile
220              
221             =cut
222              
223             sub tempfile {
224 0     0 1 0 my($self,@args) = @_;
225 0         0 my($tfh, $file);
226 0         0 my($dir, $unlink, $template, $suffix) =
227             $self->_rearrange([qw(DIR UNLINK TEMPLATE SUFFIX)], @args);
228 0 0       0 $dir = $TEMPDIR unless defined $dir;
229 0 0       0 $unlink = 1 unless defined $unlink;
230            
231 0         0 my @targs = ();
232 0 0       0 push (@targs, $template) if $template;
233 0 0       0 push (@targs, "SUFFIX", $suffix) if defined $suffix;
234 0 0       0 push (@targs, "DIR", $dir) if defined $dir;
235 0 0       0 push (@targs, "UNLINK", $unlink) if defined $unlink;
236 0         0 ($tfh, $file) = File::Temp::tempfile(@targs);
237              
238 0 0       0 push @{$self->{'_rootio_tempfiles'}}, $file if $unlink;
  0         0  
239 0 0       0 return wantarray ? ($tfh, $file) : $tfh;
240             }
241              
242             =head2 tempdir
243              
244             =cut
245              
246             sub tempdir {
247 0     0 1 0 my($self, @args) = @_;
248 0         0 return File::Temp::tempdir(@args);
249             }
250              
251             =head2 catfile
252              
253             =cut
254              
255             sub catfile {
256 946     946 1 9215 my($self, @args) = @_;
257 946         11152 return File::Spec->catfile(@args);
258             }
259              
260             =head1 INTERNAL METHODS
261              
262             Methods intended to be used only within the scope of Bio::Polloc::*
263              
264             =head2 _print
265              
266             =cut
267              
268             sub _print {
269 4     4   7 my $self = shift;
270 4   50     9 my $fh = $self->_fh || \*STDOUT;
271 4         764 my $ret = print $fh @_;
272 4         17 return $ret;
273             }
274              
275             =head2 _readline
276              
277             =cut
278              
279             sub _readline {
280 372     372   444 my $self = shift;
281 372         536 my %param = @_;
282 372 50       690 my $fh = $self->_fh or return;
283 372         485 my $line="";
284              
285 372 100       762 $self->{'_readbuffer'} = [] unless defined $self->{'_readbuffer'};
286 372 50       383 if( @{ $self->{'_readbuffer'} } ){
  372         722  
287 0         0 $line = shift @{$self->{'_readbuffer'}};
  0         0  
288             }else{
289 372         935 $line = <$fh>;
290             }
291              
292 372 100       703 if( defined $line ){
293 364         545 $line =~ s/\015\012/\012/g;
294 364         473 $line =~ tr/\015/\n/;
295             }
296 372         1524 return $line;
297             }
298              
299             =head2 _pushback
300              
301             =cut
302              
303             sub _pushback {
304 0     0   0 my($self,$line) = @_;
305 0 0       0 return unless $line;
306 0         0 push @{$self->{'_readbuffer'}}, $line;
  0         0  
307             }
308              
309             =head2 _io_cleanup
310              
311             =cut
312              
313             sub _io_cleanup {
314 250     250   299 my $self = shift;
315 250         502 $self->close;
316 250 50 33     2275 if( exists($self->{'_rootio_tempfiles'}) &&
317             ref($self->{'_rootio_tempfiles'}) =~ /array/i ) {
318 0         0 unlink @{$self->{'_rootio_tempfiles'}};
  0         0  
319             }
320             }
321              
322             =head2 _initialize_io
323              
324             =cut
325              
326             sub _initialize_io {
327 255     255   430 my($self, @args) = @_;
328 255         1016 $self->_register_cleanup_method(\&_io_cleanup);
329 255         1468 my ($input, $file, $fh, $flush, $url, $createtemp) =
330             $self->_rearrange([qw(INPUT FILE FH FLUSH URL CREATETEMP)], @args);
331            
332 255 50       901 if($createtemp){
333 0         0 ($fh, $file) = $self->tempfile();
334 0         0 $self->file($file);
335             }
336            
337 255 50       468 if($url){
338 0         0 require LWP::Simple;
339              
340 0         0 my($handle,$tempfile) = $self->tempfile();
341 0         0 CORE::close($handle);
342              
343 0         0 my $http_result;
344 0         0 for my $try ( 1 .. $IOTRIALS ){
345 0         0 $http_result = LWP::Simple::getstore($url, $tempfile);
346 0 0       0 last if $http_result == 200;
347 0         0 $self->warn("[$try/$IOTRIALS] Failed to fetch $url, ".
348             "server threw $http_result. Retrying...");
349             }
350 0 0       0 $self->throw("Failed to fetch $url, server threw $http_result")
351             if $http_result != 200;
352 0         0 $input = $tempfile;
353 0         0 $file = $tempfile;
354             }
355 255         505 delete $self->{'_readbuffer'};
356 255         332 delete $self->{'_filehandle'};
357 255 50       399 if($input){
358 0 0 0     0 if(ref(\$input) eq 'SCALAR'){
    0 0        
359 0 0 0     0 $self->throw("Input file given twice: $file and $input disagree")
360             if $file && $file ne $input;
361 0         0 $file = $input;
362             }elsif(ref($input) && ((ref($input) eq 'GLOB') || ($input->isa("IO::Handle")))){
363 0         0 $fh = $input;
364             }else{
365 0         0 $self->throw("Unable to determine type of input", $input);
366             }
367             }
368 255 50 66     581 $self->warn("Bad practice to provide both file and filehandle for reading, ignoring file")
      33        
369             if defined($file) and defined($fh) and not $createtemp;
370              
371 255 100 100     1488 if((!defined $fh) && defined($file) && $file ne ''){
      66        
372 8         49 $fh = Symbol::gensym();
373 8 50       552 open($fh, $file) or $self->throw("Could not open $file: $!");
374 8         73 $self->file($file);# unless $fh;
375             }
376 255 100       635 $self->_fh($fh) if $fh;
377 255 50       708 $self->_flush_on_write(defined $flush ? $flush : 1);
378 255         380 return 1;
379             }
380              
381             =head2 _fh
382              
383             =cut
384              
385             sub _fh {
386 411     411   522 my($self,$value) = @_;
387 411 100       749 $self->{'_filehandle'} = $value if defined $value;
388 411         1215 return $self->{'_filehandle'};
389             }
390              
391             =head2 _flush_on_write
392              
393             =cut
394              
395             sub _flush_on_write {
396 255     255   321 my($self,$value) = @_;
397 255 50       870 $self->{'_flush_on_write'} = $value if defined $value;
398 255         388 return $self->{'_flush_on_write'};
399             }
400              
401             1;