File Coverage

blib/lib/Bio/MUST/Drivers/Roles/Blastable.pm
Criterion Covered Total %
statement 41 97 42.2
branch 0 18 0.0
condition 0 10 0.0
subroutine 14 22 63.6
pod 0 7 0.0
total 55 154 35.7


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.191910';
4 5     5   4096 use 5.018; # to avoid a crash due to call to "can" below
  5         34  
5 5     5   35 use Moose::Role;
  5         12  
  5         58  
6              
7 5     5   30006 use autodie;
  5         14  
  5         83  
8 5     5   29039 use feature qw(say);
  5         15  
  5         756  
9              
10             # use Smart::Comments;
11              
12 5     5   41 use Carp;
  5         22  
  5         414  
13 5     5   37 use File::Temp;
  5         13  
  5         538  
14 5     5   44 use IPC::System::Simple qw(system);
  5         10  
  5         338  
15 5     5   36 use Module::Runtime qw(use_module);
  5         14  
  5         52  
16 5     5   449 use Path::Class;
  5         86  
  5         333  
17              
18 5     5   37 use aliased 'Bio::MUST::Core::Ali::Stash';
  5         10  
  5         50  
19 5     5   1323 use aliased 'Bio::FastParsers::Blast::Table';
  5         10  
  5         23  
20 5     5   842361 use aliased 'Bio::FastParsers::Blast::Xml';
  5         13  
  5         35  
21              
22 5     5   1140977 use Bio::MUST::Drivers::Utils qw(stringify_args);
  5         14  
  5         5930  
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 0           $pgm = file($ENV{BMD_BLAST_BINDIR}, $pgm);
112 0           my $cmd = join q{ }, $pgm, $args_str, '> /dev/null 2> /dev/null';
113             ### $cmd
114              
115             # try to robustly execute BLAST
116 0           my $ret_code = system( [ 0, 127 ], $cmd);
117 0 0         if ($ret_code == 127) {
118 0           carp "[BMD] Warning: cannot execute $pgm command;"
119             . ' returning without parser!';
120 0           return;
121             }
122              
123             # return Bio::FastParsers::Blast of the right subclass
124             # depending on the output format (XML or tabular)
125             # or the Path::Class::File of the report for HTML output
126             return exists $args->{-html} ? $out->filename :
127 0 0         $args->{-outfmt} == 5 ? Xml->new(file => $out->filename) :
    0          
128             Table->new(file => $out->filename)
129             ;
130              
131             # TODO: devise a way to unlink report without affecting parsing
132             # should be an option of the FastParsers?
133             }
134              
135             sub blastdbcmd {
136 0     0 0   my $self = shift;
137 0           my $ids = shift;
138 0   0       my $args = shift // {};
139              
140             # setup temporary input/output files (will be automatically unlinked)
141 0           my $in = File::Temp->new(UNLINK => 1, EXLOCK => 0);
142 0           my $out = File::Temp->new(UNLINK => 1, EXLOCK => 0);
143             # TODO: check if lifespan of $out temp file long enough for loading
144              
145             # write id list for -entry_batch
146 0           say {$in} join "\n", @{$ids};
  0            
  0            
147 0           $in->flush; # for robustness ; might be not needed
148              
149             # format blastdbcmd (optional) arguments
150 0           $args->{-db} = $self->filename;
151 0           $args->{-entry_batch} = $in->filename;
152 0           $args->{-out} = $out->filename;
153 0           my $args_str = stringify_args($args);
154              
155             # create blastdbcmd command
156 0           my $pgm = file($ENV{BMD_BLAST_BINDIR}, 'blastdbcmd');
157 0           my $cmd = join q{ }, $pgm, $args_str;
158             ### $cmd
159              
160             # try to robustly execute blastdbcmd
161 0           my $ret_code = system( [ 0, 127 ], $cmd);
162 0 0         if ($ret_code == 127) {
163 0           carp "[BMD] Warning: cannot execute $pgm command;"
164             . ' returning without seqs!';
165 0           return;
166             }
167              
168 0           return Stash->load( $out->filename );
169             }
170              
171 5     5   51 no Moose::Role;
  5         14  
  5         60  
172             1;
173              
174             __END__
175              
176             =pod
177              
178             =head1 NAME
179              
180             Bio::MUST::Drivers::Roles::Blastable - BLAST database-related methods
181              
182             =head1 VERSION
183              
184             version 0.191910
185              
186             =head1 SYNOPSIS
187              
188             # TODO
189              
190             =head1 DESCRIPTION
191              
192             # TODO
193              
194             =head1 AUTHOR
195              
196             Denis BAURAIN <denis.baurain@uliege.be>
197              
198             =head1 COPYRIGHT AND LICENSE
199              
200             This software is copyright (c) 2013 by University of Liege / Unit of Eukaryotic Phylogenomics / Denis BAURAIN.
201              
202             This is free software; you can redistribute it and/or modify it under
203             the same terms as the Perl 5 programming language system itself.
204              
205             =cut