Fix for bug 2413. Shouldn't we delegate all IO-related functions to the internal...
[bioperl-run.git] / Bio / Tools / Run / WrapperBase.pm
blob0cec80af97e8eb019f5bd6f010b299063f66c2e1
1 # $Id$
3 # BioPerl module for Bio::Tools::Run::WrapperBase
5 # Cared for by Jason Stajich <jason@bioperl.org>
7 # Copyright Jason Stajich
9 # You may distribute this module under the same terms as perl itself
11 # POD documentation - main docs before the code
13 =head1 NAME
15 Bio::Tools::Run::WrapperBase - A Base object for wrappers around executables
17 =head1 SYNOPSIS
19 # do not use this object directly, it provides the following methods
20 # for its subclasses
22 my $errstr = $obj->error_string();
23 my $exe = $obj->executable();
24 $obj->save_tempfiles($booleanflag)
25 my $outfile= $obj->outfile_name();
26 my $tempdir= $obj->tempdir(); # get a temporary dir for executing
27 my $io = $obj->io; # Bio::Root::IO object
28 my $cleanup= $obj->cleanup(); # remove tempfiles
30 $obj->run({-arg1 => $value});
32 =head1 DESCRIPTION
34 This is a basic module from which to build executable wrapper modules.
35 It has some basic methods to help when implementing new modules.
37 =head1 FEEDBACK
39 =head2 Mailing Lists
41 User feedback is an integral part of the evolution of this and other
42 Bioperl modules. Send your comments and suggestions preferably to
43 the Bioperl mailing list. Your participation is much appreciated.
45 bioperl-l@bioperl.org - General discussion
46 http://bioperl.org/wiki/Mailing_lists - About the mailing lists
48 =head2 Reporting Bugs
50 Report bugs to the Bioperl bug tracking system to help us keep track of
51 the bugs and their resolution. Bug reports can be submitted via the
52 web:
54 http://bugzilla.open-bio.org/
56 =head1 AUTHOR - Jason Stajich
58 Email jason-at-bioperl.org
60 =head1 CONTRIBUTORS
62 Sendu Bala, bix@sendu.me.uk
64 =head1 APPENDIX
66 The rest of the documentation details each of the object methods.
67 Internal methods are usually preceded with a _
69 =cut
72 # Let the code begin...
75 package Bio::Tools::Run::WrapperBase;
76 use strict;
78 # Object preamble - inherits from Bio::Root::Root
80 use base qw(Bio::Root::Root);
82 use File::Spec;
83 use File::Path qw(); # don't import anything
85 =head2 run
87 Title : run
88 Usage : $wrapper->run({ARGS HERE});
89 Function: Support generic running with args passed in
90 as a hashref
91 Returns : Depends on the implementation, status OR data
92 Args : hashref of named arguments
95 =cut
97 sub run {
98 my ($self,@args) = @_;
99 $self->throw_not_implemented();
103 =head2 error_string
105 Title : error_string
106 Usage : $obj->error_string($newval)
107 Function: Where the output from the last analysis run is stored.
108 Returns : value of error_string
109 Args : newvalue (optional)
112 =cut
114 sub error_string{
115 my ($self,$value) = @_;
116 if( defined $value) {
117 $self->{'_error_string'} = $value;
119 return $self->{'_error_string'} || '';
122 =head2 arguments
124 Title : arguments
125 Usage : $obj->arguments($newval)
126 Function: Commandline parameters
127 Returns : value of arguments
128 Args : newvalue (optional)
131 =cut
133 sub arguments {
134 my ($self,$value) = @_;
135 if(defined $value) {
136 $self->{'_arguments'} = $value;
138 return $self->{'_arguments'} || '';
142 =head2 no_param_checks
144 Title : no_param_checks
145 Usage : $obj->no_param_checks($newval)
146 Function: Boolean flag as to whether or not we should
147 trust the sanity checks for parameter values
148 Returns : value of no_param_checks
149 Args : newvalue (optional)
152 =cut
154 sub no_param_checks{
155 my ($self,$value) = @_;
156 if( defined $value || ! defined $self->{'no_param_checks'} ) {
157 $value = 0 unless defined $value;
158 $self->{'no_param_checks'} = $value;
160 return $self->{'no_param_checks'};
163 =head2 save_tempfiles
165 Title : save_tempfiles
166 Usage : $obj->save_tempfiles($newval)
167 Function: Get/set the choice of if tempfiles in the temp dir (see tempdir())
168 are kept or cleaned up. Default is '0', ie. delete temp files.
169 NB:ÊThis must be set to the desired value PRIOR to first creating
170 a temp dir with tempdir().
171 Returns : boolean
172 Args : none to get, boolean to set
174 =cut
176 sub save_tempfiles{
177 my $self = shift;
178 return $self->io->save_tempfiles(@_);
181 =head2 outfile_name
183 Title : outfile_name
184 Usage : my $outfile = $wrapper->outfile_name();
185 Function: Get/Set the name of the output file for this run
186 (if you wanted to do something special)
187 Returns : string
188 Args : [optional] string to set value to
191 =cut
193 sub outfile_name{
194 my ($self,$nm) = @_;
195 if( defined $nm || ! defined $self->{'_outfilename'} ) {
196 $nm = 'mlc' unless defined $nm;
197 $self->{'_outfilename'} = $nm;
199 return $self->{'_outfilename'};
203 =head2 tempdir
205 Title : tempdir
206 Usage : my $tmpdir = $self->tempdir();
207 Function: Retrieve a temporary directory name (which is created)
208 Returns : string which is the name of the temporary directory
209 Args : none
212 =cut
214 sub tempdir{
215 my ($self) = shift;
217 $self->{'_tmpdir'} = shift if @_;
218 unless( $self->{'_tmpdir'} ) {
219 $self->{'_tmpdir'} = $self->io->tempdir(CLEANUP => ! $self->save_tempfiles );
221 unless( -d $self->{'_tmpdir'} ) {
222 mkdir($self->{'_tmpdir'},0777);
224 return $self->{'_tmpdir'};
227 =head2 cleanup
229 Title : cleanup
230 Usage : $wrapper->cleanup();
231 Function: Will cleanup the tempdir directory
232 Returns : none
233 Args : none
236 =cut
238 sub cleanup{
239 my ($self) = @_;
240 $self->io->_io_cleanup();
241 if( defined $self->{'_tmpdir'} && -d $self->{'_tmpdir'} ) {
242 my $verbose = ($self->verbose >= 1) ? 1 : 0;
243 File::Path::rmtree( $self->{'_tmpdir'}, $verbose);
247 =head2 io
249 Title : io
250 Usage : $obj->io($newval)
251 Function: Gets a Bio::Root::IO object
252 Returns : Bio::Root::IO object
253 Args : none
256 =cut
258 sub io{
259 my ($self) = @_;
260 unless( defined $self->{'io'} ) {
261 $self->{'io'} = Bio::Root::IO->new(-verbose => $self->verbose);
263 return $self->{'io'};
266 =head2 version
268 Title : version
269 Usage : $version = $wrapper->version()
270 Function: Returns the program version (if available)
271 Returns : string representing version of the program
272 Args : [Optional] value to (re)set version string
275 =cut
277 sub version{
278 my ($self,@args) = @_;
279 return;
282 =head2 executable
284 Title : executable
285 Usage : my $exe = $factory->executable();
286 Function: Finds the full path to the executable
287 Returns : string representing the full path to the exe
288 Args : [optional] name of executable to set path to
289 [optional] boolean flag whether or not warn when exe is not found
291 =cut
293 sub executable {
294 my ($self, $exe, $warn) = @_;
296 if (defined $exe) {
297 $self->{'_pathtoexe'} = $exe;
300 unless( defined $self->{'_pathtoexe'} ) {
301 my $prog_path = $self->program_path;
303 if ($prog_path) {
304 if (-e $prog_path && -x $prog_path) {
305 $self->{'_pathtoexe'} = $prog_path;
307 elsif ($self->program_dir) {
308 $self->warn("executable not found in $prog_path, trying system path...") if $warn;
311 unless ($self->{'_pathtoexe'}) {
312 my $exe;
313 if (($exe = $self->io->exists_exe($self->program_name)) && -x $exe) {
314 $self->{'_pathtoexe'} = $exe;
316 else {
317 $self->warn("Cannot find executable for ".$self->program_name) if $warn;
318 $self->{'_pathtoexe'} = undef;
322 $self->{'_pathtoexe'};
325 =head2 program_path
327 Title : program_path
328 Usage : my $path = $factory->program_path();
329 Function: Builds path for executable
330 Returns : string representing the full path to the exe
331 Args : none
333 =cut
335 sub program_path {
336 my ($self) = @_;
337 my @path;
338 push @path, $self->program_dir if $self->program_dir;
339 push @path, $self->program_name.($^O =~ /mswin/i ?'.exe':'');
341 return File::Spec->catfile(@path);
344 =head2 program_dir
346 Title : program_dir
347 Usage : my $dir = $factory->program_dir();
348 Function: Abstract get method for dir of program. To be implemented
349 by wrapper.
350 Returns : string representing program directory
351 Args : none
353 =cut
355 sub program_dir {
356 my ($self) = @_;
357 $self->throw_not_implemented();
360 =head2 program_name
362 Title : program_name
363 Usage : my $name = $factory->program_name();
364 Function: Abstract get method for name of program. To be implemented
365 by wrapper.
366 Returns : string representing program name
367 Args : none
369 =cut
371 sub program_name {
372 my ($self) = @_;
373 $self->throw_not_implemented();
376 =head2 quiet
378 Title : quiet
379 Usage : $factory->quiet(1);
380 if ($factory->quiet()) { ... }
381 Function: Get/set the quiet state. Can be used by wrappers to control if
382 program output is printed to the console or not.
383 Returns : boolean
384 Args : none to get, boolean to set
386 =cut
388 sub quiet {
389 my $self = shift;
390 if (@_) { $self->{quiet} = shift }
391 return $self->{quiet} || 0;
394 =head2 _setparams()
396 Title : _setparams
397 Usage : $params = $self->_setparams(-params => [qw(window evalue_cutoff)])
398 Function: For internal use by wrapper modules to build parameter strings
399 suitable for sending to the program being wrapped. For each method
400 name supplied, calls the method and adds the method name (as modified
401 by optional things) along with its value (unless a switch) to the
402 parameter string
403 Example : $params = $self->_setparams(-params => [qw(window evalue_cutoff)],
404 -switches => [qw(simple large all)],
405 -double_dash => 1,
406 -underscore_to_dash => 1);
407 If window() and simple() had not been previously called, but
408 evalue_cutoff(0.5), large(1) and all(0) had been called, $params
409 would be ' --evalue-cutoff 0.5 --large'
410 Returns : parameter string
411 Args : -params => [] or {} # array ref of method names to call,
412 or hash ref where keys are method names and
413 values are how those names should be output
414 in the params string
415 -switches => [] or {}# as for -params, but no value is printed for
416 these methods
417 -join => string # define how parameters and their values are
418 joined, default ' '. (eg. could be '=' for
419 param=value)
420 -lc => boolean # lc() method names prior to output in string
421 -dash => boolean # prefix all method names with a single dash
422 -double_dash => bool # prefix all method names with a double dash
423 -mixed_dash => bool # prefix single-character method names with a
424 # single dash, and multi-character method names
425 # with a double-dash
426 -underscore_to_dash => boolean # convert all underscores in method
427 names to dashes
429 =cut
431 sub _setparams {
432 my ($self, @args) = @_;
434 my ($params, $switches, $join, $lc, $d, $dd, $md, $utd) =
435 $self->_rearrange([qw(PARAMS
436 SWITCHES
437 JOIN
439 DASH
440 DOUBLE_DASH
441 MIXED_DASH
442 UNDERSCORE_TO_DASH)], @args);
443 $self->throw('at least one of -params or -switches is required') unless ($params || $switches);
444 $self->throw("-dash, -double_dash and -mixed_dash are mutually exclusive") if (defined($d) + defined($dd) + defined($md) > 1);
445 $join ||= ' ';
447 my %params = ref($params) eq 'HASH' ? %{$params} : map { $_ => $_ } @{$params};
448 my %switches = ref($switches) eq 'HASH' ? %{$switches} : map { $_ => $_ } @{$switches};
450 my $param_string = '';
451 for my $hash_ref (\%params, \%switches) {
452 while (my ($method, $method_out) = each %{$hash_ref}) {
453 my $value = $self->$method();
454 next unless (defined $value);
455 next if (exists $switches{$method} && ! $value);
457 $method_out = lc($method_out) if $lc;
458 my $method_length = length($method_out) if $md;
459 $method_out = '-'.$method_out if ($d || ($md && ($method_length == 1)));
460 $method_out = '--'.$method_out if ($dd || ($md && ($method_length > 1)));
461 $method_out =~ s/_/-/g if $utd;
463 # quote values that contain spaces
464 if (exists $params{$method} && $value =~ /^[^'"\s]+\s+[^'"\s]+$/) {
465 $value = '"'.$value.'"';
468 $param_string .= ' '.$method_out.(exists $switches{$method} ? '' : $join.$value);
472 return $param_string;
475 sub DESTROY {
476 my $self= shift;
477 unless ( $self->save_tempfiles ) {
478 #$self->cleanup();
480 $self->SUPER::DESTROY();