File Coverage

blib/lib/Bio/MUST/Drivers/Roles/Blastable.pm
Criterion Covered Total %
statement 44 104 42.3
branch 0 20 0.0
condition 0 10 0.0
subroutine 15 23 65.2
pod 0 7 0.0
total 59 164 35.9


line stmt bran cond sub pod time code
1             package Bio::MUST::Drivers::Roles::Blastable;
2             # ABSTRACT: BLAST database-related methods
3             $Bio::MUST::Drivers::Roles::Blastable::VERSION = '0.210160';
4 5     5   4193 use 5.018; # to avoid a crash due to call to "can" below
  5         37  
5 5     5   41 use Moose::Role;
  5         12  
  5         56  
6              
7 5     5   29979 use autodie;
  5         16  
  5         54  
8 5     5   28480 use feature qw(say);
  5         111  
  5         621  
9              
10 5     5   41 use Smart::Comments '###';
  5         11  
  5         55  
11              
12 5     5   15375 use Carp;
  5         13  
  5         380  
13 5     5   40 use File::Temp;
  5         12  
  5         410  
14 5     5   40 use IPC::System::Simple qw(system);
  5         11  
  5         284  
15 5     5   38 use Module::Runtime qw(use_module);
  5         59  
  5         47  
16 5     5   432 use Path::Class;
  5         12  
  5         300  
17              
18 5     5   31 use aliased 'Bio::MUST::Core::Ali::Stash';
  5         11  
  5         69  
19 5     5   1466 use aliased 'Bio::FastParsers::Blast::Table';
  5         13  
  5         20  
20 5     5   830908 use aliased 'Bio::FastParsers::Blast::Xml';
  5         13  
  5         33  
21              
22 5     5   1110842 use Bio::MUST::Drivers::Utils qw(stringify_args);
  5         15  
  5         6467  
23              
24              
25             # TODO: avoid hard-coded convenience methods?
26              
27             sub blastn { ## no critic (RequireArgUnpacking)
28 0     0 0   return shift->_blast( 'blastn', @_);
29             }
30              
31             sub blastp { ## no critic (RequireArgUnpacking)
32 0     0 0   return shift->_blast( 'blastp', @_);
33             }
34              
35             sub blastx { ## no critic (RequireArgUnpacking)
36 0     0 0   return shift->_blast( 'blastx', @_);
37             }
38              
39             sub tblastn { ## no critic (RequireArgUnpacking)
40 0     0 0   return shift->_blast('tblastn', @_);
41             }
42              
43             sub tblastx { ## no critic (RequireArgUnpacking)
44 0     0 0   return shift->_blast('tblastx', @_);
45             }
46              
47             my %pgm_for = ( # cannot be made constant to allow undefined keys
48             'nucl:nucl' => 'blastn',
49             'nucl:prot' => 'blastx',
50             'prot:prot' => 'blastp',
51             'prot:nucl' => 'tblastn',
52             );
53              
54             sub blast { ## no critic (RequireArgUnpacking)
55 0     0 0   my $self = shift;
56 0           my $query = shift;
57              
58             # abort if no Ali::Temporary-like object
59             # this seems to work both with Path::Class::File and plain filenames
60             # however, the can construct here requires perl-5.18 (cannot find why)
61 0 0 0       croak "[BMD] Error: Cannot autoselect BLAST program for $query; aborting!\n"
62             . 'Use Ali::Temporary to autodetect query sequence type.'
63             unless $query->can('type') && $query->can('filename');
64              
65             # auto-select BLAST program based on query/database type
66 0           my $pgm = $pgm_for{ $query->type . ':' . $self->type };
67              
68 0           return $self->_blast($pgm, $query->filename, @_);
69             }
70              
71             sub _blast {
72 0     0     my $self = shift;
73 0           my $pgm = shift;
74 0           my $query = shift;
75 0   0       my $args = shift // {};
76              
77             #### $pgm
78             #### $args
79              
80             # provision executable
81 0           my $app = use_module('Bio::MUST::Provision::Blast')->new;
82 0           $app->meet();
83              
84             # setup output file and output format
85             # Note: only tabular, XML and HTML outputs are allowed
86             # if specified -html takes precedence on -outfmt
87 0           my $suffix = ".$pgm";
88 0 0         if (exists $args->{-html}) {
89 0           $suffix .= '.html';
90 0           delete $args->{-outfmt}; # enforce precedence policy
91             }
92             else {
93 0 0 0       unless (defined $args->{-outfmt} && $args->{-outfmt} =~ m/[567]/xms) {
94 0           carp '[BMD] Warning: no valid -outfmt specified;'
95             . ' defaulting to tabular!';
96 0           $args->{-outfmt} = 6;
97             }
98             }
99 0           my $out = File::Temp->new(UNLINK => 0, EXLOCK => 0, SUFFIX => $suffix);
100              
101             # automatically setup remote BLAST based on database "class"
102 0 0         $args->{-remote} = undef if $self->remote;
103              
104             # format BLAST (optional) arguments
105 0 0         $args->{-query} = $query->can('filename') ? $query->filename : $query;
106 0           $args->{-db} = $self->filename; # handle query plain filenames too
107 0           $args->{-out} = $out->filename;
108 0           my $args_str = stringify_args($args);
109              
110             # create BLAST command
111             # Note: we need to untaint data here
112 0           ($pgm) = file($ENV{BMD_BLAST_BINDIR}, $pgm) =~ m/^(\S+)$/xms;
113 0 0         ### assert: $pgm
  0            
  0            
  0            
114 0           my $cmd = join q{ }, $pgm, $args_str, '> /dev/null 2> /dev/null';
115             #### $cmd
116              
117             # try to robustly execute BLAST
118 0           my $ret_code = system( [ 0, 127 ], $cmd);
119 0 0         if ($ret_code == 127) {
120 0           carp "[BMD] Warning: cannot execute $pgm command;"
121             . ' returning without parser!';
122 0           return;
123             }
124              
125             # return Bio::FastParsers::Blast of the right subclass
126             # depending on the output format (XML or tabular)
127             # or the Path::Class::File of the report for HTML output
128             return exists $args->{-html} ? $out->filename :
129 0 0         $args->{-outfmt} == 5 ? Xml->new(file => $out->filename) :
    0          
130             Table->new(file => $out->filename)
131             ;
132              
133             # TODO: devise a way to unlink report without affecting parsing
134             # should be an option of the FastParsers?
135             }
136              
137             sub blastdbcmd {
138 0     0 0   my $self = shift;
139 0           my $ids = shift;
140 0   0       my $args = shift // {};
141              
142             # setup temporary input/output files (will be automatically unlinked)
143 0           my $in = File::Temp->new(UNLINK => 1, EXLOCK => 0);
144 0           my $out = File::Temp->new(UNLINK => 1, EXLOCK => 0);
145             # TODO: check if lifespan of $out temp file long enough for loading
146              
147             # write id list for -entry_batch
148 0           say {$in} join "\n", @{$ids};
  0            
  0            
149 0           $in->flush; # for robustness ; might be not needed
150              
151             # format blastdbcmd (optional) arguments
152 0           $args->{-db} = $self->filename;
153 0           $args->{-entry_batch} = $in->filename;
154 0           $args->{-out} = $out->filename;
155 0           my $args_str = stringify_args($args);
156              
157             # create blastdbcmd command
158 0           my $pgm = file($ENV{BMD_BLAST_BINDIR}, 'blastdbcmd');
159 0           my $cmd = join q{ }, $pgm, $args_str;
160             #### $cmd
161              
162             # try to robustly execute blastdbcmd
163 0           my $ret_code = system( [ 0, 127 ], $cmd);
164 0 0         if ($ret_code == 127) {
165 0           carp "[BMD] Warning: cannot execute $pgm command;"
166             . ' returning without seqs!';
167 0           return;
168             }
169              
170 0           return Stash->load( $out->filename );
171             }
172              
173 5     5   51 no Moose::Role;
  5         13  
  5         57  
174             1;
175              
176             __END__
177              
178             =pod
179              
180             =head1 NAME
181              
182             Bio::MUST::Drivers::Roles::Blastable - BLAST database-related methods
183              
184             =head1 VERSION
185              
186             version 0.210160
187              
188             =head1 SYNOPSIS
189              
190             # TODO
191              
192             =head1 DESCRIPTION
193              
194             # TODO
195              
196             =head1 AUTHOR
197              
198             Denis BAURAIN <denis.baurain@uliege.be>
199              
200             =head1 COPYRIGHT AND LICENSE
201              
202             This software is copyright (c) 2013 by University of Liege / Unit of Eukaryotic Phylogenomics / Denis BAURAIN.
203              
204             This is free software; you can redistribute it and/or modify it under
205             the same terms as the Perl 5 programming language system itself.
206              
207             =cut