Bio::DB::Universal: move into its own distribution
[bioperl-live.git] / Bio / Tools / Run / WrapperBase.pm
blob74efe37fe1aec4587668d69d75cc73ecfa54905d
2 # BioPerl module for Bio::Tools::Run::WrapperBase
4 # Please direct questions and support issues to <bioperl-l@bioperl.org>
6 # Cared for by Jason Stajich <jason@bioperl.org>
8 # Copyright Jason Stajich
10 # You may distribute this module under the same terms as perl itself
12 # POD documentation - main docs before the code
14 =head1 NAME
16 Bio::Tools::Run::WrapperBase - A Base object for wrappers around executables
18 =head1 SYNOPSIS
20 # do not use this object directly, it provides the following methods
21 # for its subclasses
23 my $errstr = $obj->error_string();
24 my $exe = $obj->executable();
25 $obj->save_tempfiles($booleanflag)
26 my $outfile= $obj->outfile_name();
27 my $tempdir= $obj->tempdir(); # get a temporary dir for executing
28 my $io = $obj->io; # Bio::Root::IO object
29 my $cleanup= $obj->cleanup(); # remove tempfiles
31 $obj->run({-arg1 => $value});
33 =head1 DESCRIPTION
35 This is a basic module from which to build executable wrapper modules.
36 It has some basic methods to help when implementing new modules.
38 =head1 FEEDBACK
40 =head2 Mailing Lists
42 User feedback is an integral part of the evolution of this and other
43 Bioperl modules. Send your comments and suggestions preferably to
44 the Bioperl mailing list. Your participation is much appreciated.
46 bioperl-l@bioperl.org - General discussion
47 http://bioperl.org/wiki/Mailing_lists - About the mailing lists
49 =head2 Support
51 Please direct usage questions or support issues to the mailing list:
53 I<bioperl-l@bioperl.org>
55 rather than to the module maintainer directly. Many experienced and
56 reponsive experts will be able look at the problem and quickly
57 address it. Please include a thorough description of the problem
58 with code and data examples if at all possible.
60 =head2 Reporting Bugs
62 Report bugs to the Bioperl bug tracking system to help us keep track of
63 the bugs and their resolution. Bug reports can be submitted via the
64 web:
66 https://github.com/bioperl/bioperl-live/issues
68 =head1 AUTHOR - Jason Stajich
70 Email jason-at-bioperl.org
72 =head1 CONTRIBUTORS
74 Sendu Bala, bix@sendu.me.uk
76 =head1 APPENDIX
78 The rest of the documentation details each of the object methods.
79 Internal methods are usually preceded with a _
81 =cut
84 # Let the code begin...
87 package Bio::Tools::Run::WrapperBase;
88 use strict;
90 # Object preamble - inherits from Bio::Root::Root
92 use base qw(Bio::Root::Root);
94 use File::Spec;
95 use File::Path qw(); # don't import anything
97 =head2 run
99 Title : run
100 Usage : $wrapper->run({ARGS HERE});
101 Function: Support generic running with args passed in
102 as a hashref
103 Returns : Depends on the implementation, status OR data
104 Args : hashref of named arguments
107 =cut
109 sub run {
110 my ($self,@args) = @_;
111 $self->throw_not_implemented();
115 =head2 error_string
117 Title : error_string
118 Usage : $obj->error_string($newval)
119 Function: Where the output from the last analysis run is stored.
120 Returns : value of error_string
121 Args : newvalue (optional)
124 =cut
126 sub error_string{
127 my ($self,$value) = @_;
128 if( defined $value) {
129 $self->{'_error_string'} = $value;
131 return $self->{'_error_string'} || '';
134 =head2 arguments
136 Title : arguments
137 Usage : $obj->arguments($newval)
138 Function: Commandline parameters
139 Returns : value of arguments
140 Args : newvalue (optional)
143 =cut
145 sub arguments {
146 my ($self,$value) = @_;
147 if(defined $value) {
148 $self->{'_arguments'} = $value;
150 return $self->{'_arguments'} || '';
154 =head2 no_param_checks
156 Title : no_param_checks
157 Usage : $obj->no_param_checks($newval)
158 Function: Boolean flag as to whether or not we should
159 trust the sanity checks for parameter values
160 Returns : value of no_param_checks
161 Args : newvalue (optional)
164 =cut
166 sub no_param_checks{
167 my ($self,$value) = @_;
168 if( defined $value || ! defined $self->{'no_param_checks'} ) {
169 $value = 0 unless defined $value;
170 $self->{'no_param_checks'} = $value;
172 return $self->{'no_param_checks'};
175 =head2 save_tempfiles
177 Title : save_tempfiles
178 Usage : $obj->save_tempfiles($newval)
179 Function: Get/set the choice of if tempfiles in the temp dir (see tempdir())
180 are kept or cleaned up. Default is '0', ie. delete temp files.
181 NB: This must be set to the desired value PRIOR to first creating
182 a temp dir with tempdir(). Any attempt to set this after tempdir creation will get a warning.
183 Returns : boolean
184 Args : none to get, boolean to set
186 =cut
188 sub save_tempfiles{
189 my $self = shift;
190 my @args = @_;
191 if (($args[0]) && (exists ($self->{'_tmpdir'}))) {
192 $self->warn ("Tempdir already created; setting save_tempfiles will not affect cleanup behavior.");
194 return $self->io->save_tempfiles(@_);
197 =head2 outfile_name
199 Title : outfile_name
200 Usage : my $outfile = $wrapper->outfile_name();
201 Function: Get/Set the name of the output file for this run
202 (if you wanted to do something special)
203 Returns : string
204 Args : [optional] string to set value to
207 =cut
209 sub outfile_name{
210 my ($self,$nm) = @_;
211 if( defined $nm || ! defined $self->{'_outfilename'} ) {
212 $nm = 'mlc' unless defined $nm;
213 $self->{'_outfilename'} = $nm;
215 return $self->{'_outfilename'};
219 =head2 tempdir
221 Title : tempdir
222 Usage : my $tmpdir = $self->tempdir();
223 Function: Retrieve a temporary directory name (which is created)
224 Returns : string which is the name of the temporary directory
225 Args : none
228 =cut
230 sub tempdir{
231 my ($self) = shift;
233 $self->{'_tmpdir'} = shift if @_;
234 unless( $self->{'_tmpdir'} ) {
235 $self->{'_tmpdir'} = $self->io->tempdir(CLEANUP => ! $self->save_tempfiles );
237 unless( -d $self->{'_tmpdir'} ) {
238 mkdir($self->{'_tmpdir'},0777);
240 return $self->{'_tmpdir'};
243 =head2 cleanup
245 Title : cleanup
246 Usage : $wrapper->cleanup();
247 Function: Will cleanup the tempdir directory
248 Returns : none
249 Args : none
252 =cut
254 sub cleanup{
255 my ($self) = @_;
256 $self->io->_io_cleanup();
257 if( defined $self->{'_tmpdir'} && -d $self->{'_tmpdir'} ) {
258 my $verbose = ($self->verbose >= 1) ? 1 : 0;
259 File::Path::rmtree( $self->{'_tmpdir'}, $verbose);
263 =head2 io
265 Title : io
266 Usage : $obj->io($newval)
267 Function: Gets a Bio::Root::IO object
268 Returns : Bio::Root::IO object
269 Args : none
272 =cut
274 sub io{
275 my ($self) = @_;
276 unless( defined $self->{'io'} ) {
277 $self->{'io'} = Bio::Root::IO->new(-verbose => $self->verbose);
279 return $self->{'io'};
282 =head2 version
284 Title : version
285 Usage : $version = $wrapper->version()
286 Function: Returns the program version (if available)
287 Returns : string representing version of the program
288 Args : [Optional] value to (re)set version string
291 =cut
293 sub version{
294 my ($self,@args) = @_;
295 return;
298 =head2 executable
300 Title : executable
301 Usage : my $exe = $factory->executable();
302 Function: Finds the full path to the executable
303 Returns : string representing the full path to the exe
304 Args : [optional] name of executable to set path to
305 [optional] boolean flag whether or not warn when exe is not found
307 =cut
309 sub executable {
310 my ($self, $exe, $warn) = @_;
312 if (defined $exe) {
313 $self->{'_pathtoexe'} = $exe;
316 unless( defined $self->{'_pathtoexe'} ) {
317 my $prog_path = $self->program_path;
319 if ($prog_path) {
320 if (-f $prog_path && -x $prog_path) {
321 $self->{'_pathtoexe'} = $prog_path;
323 elsif ($self->program_dir) {
324 $self->warn("executable not found in $prog_path, trying system path...") if $warn;
327 unless ($self->{'_pathtoexe'}) {
328 my $exe;
329 if ( $exe = $self->io->exists_exe($self->program_name) ) {
330 $self->{'_pathtoexe'} = $exe;
332 else {
333 $self->warn("Cannot find executable for ".$self->program_name) if $warn;
334 $self->{'_pathtoexe'} = undef;
339 # bail if we never found the executable
340 unless ( defined $self->{'_pathtoexe'}) {
341 $self->throw("Cannot find executable for ".$self->program_name .
342 ". path=\"".$self->program_path."\"");
344 return $self->{'_pathtoexe'};
347 =head2 program_path
349 Title : program_path
350 Usage : my $path = $factory->program_path();
351 Function: Builds path for executable
352 Returns : string representing the full path to the exe
353 Args : none
355 =cut
357 sub program_path {
358 my ($self) = @_;
359 my @path;
360 push @path, $self->program_dir if $self->program_dir;
361 push @path, $self->program_name.($^O =~ /mswin/i ? '.exe' : '') if $self->program_name;
362 return File::Spec->catfile(@path);
365 =head2 program_dir
367 Title : program_dir
368 Usage : my $dir = $factory->program_dir();
369 Function: Abstract get method for dir of program. To be implemented
370 by wrapper.
371 Returns : string representing program directory
372 Args : none
374 =cut
376 sub program_dir {
377 my ($self) = @_;
378 $self->throw_not_implemented();
381 =head2 program_name
383 Title : program_name
384 Usage : my $name = $factory->program_name();
385 Function: Abstract get method for name of program. To be implemented
386 by wrapper.
387 Returns : string representing program name
388 Args : none
390 =cut
392 sub program_name {
393 my ($self) = @_;
394 $self->throw_not_implemented();
397 =head2 quiet
399 Title : quiet
400 Usage : $factory->quiet(1);
401 if ($factory->quiet()) { ... }
402 Function: Get/set the quiet state. Can be used by wrappers to control if
403 program output is printed to the console or not.
404 Returns : boolean
405 Args : none to get, boolean to set
407 =cut
409 sub quiet {
410 my $self = shift;
411 if (@_) { $self->{quiet} = shift }
412 return $self->{quiet} || 0;
415 =head2 _setparams()
417 Title : _setparams
418 Usage : $params = $self->_setparams(-params => [qw(window evalue_cutoff)])
419 Function: For internal use by wrapper modules to build parameter strings
420 suitable for sending to the program being wrapped. For each method
421 name supplied, calls the method and adds the method name (as modified
422 by optional things) along with its value (unless a switch) to the
423 parameter string
424 Example : $params = $self->_setparams(-params => [qw(window evalue_cutoff)],
425 -switches => [qw(simple large all)],
426 -double_dash => 1,
427 -underscore_to_dash => 1);
428 If window() and simple() had not been previously called, but
429 evalue_cutoff(0.5), large(1) and all(0) had been called, $params
430 would be ' --evalue-cutoff 0.5 --large'
431 Returns : parameter string
432 Args : -params => [] or {} # array ref of method names to call,
433 or hash ref where keys are method names and
434 values are how those names should be output
435 in the params string
436 -switches => [] or {}# as for -params, but no value is printed for
437 these methods
438 -join => string # define how parameters and their values are
439 joined, default ' '. (eg. could be '=' for
440 param=value)
441 -lc => boolean # lc() method names prior to output in string
442 -dash => boolean # prefix all method names with a single dash
443 -double_dash => bool # prefix all method names with a double dash
444 -mixed_dash => bool # prefix single-character method names with a
445 # single dash, and multi-character method names
446 # with a double-dash
447 -underscore_to_dash => boolean # convert all underscores in method
448 names to dashes
450 =cut
452 sub _setparams {
453 my ($self, @args) = @_;
455 my ($params, $switches, $join, $lc, $d, $dd, $md, $utd) =
456 $self->_rearrange([qw(PARAMS
457 SWITCHES
458 JOIN
460 DASH
461 DOUBLE_DASH
462 MIXED_DASH
463 UNDERSCORE_TO_DASH)], @args);
464 $self->throw('at least one of -params or -switches is required') unless ($params || $switches);
465 $self->throw("-dash, -double_dash and -mixed_dash are mutually exclusive") if (defined($d) + defined($dd) + defined($md) > 1);
466 $join ||= ' ';
468 my %params = ref($params) eq 'HASH' ? %{$params} : map { $_ => $_ } @{$params};
469 my %switches = ref($switches) eq 'HASH' ? %{$switches} : map { $_ => $_ } @{$switches};
471 my $param_string = '';
472 for my $hash_ref (\%params, \%switches) {
473 while (my ($method, $method_out) = each %{$hash_ref}) {
474 my $value = $self->$method();
475 next unless (defined $value);
476 next if (exists $switches{$method} && ! $value);
478 $method_out = lc($method_out) if $lc;
479 my $method_length = length($method_out) if $md;
480 $method_out = '-'.$method_out if ($d || ($md && ($method_length == 1)));
481 $method_out = '--'.$method_out if ($dd || ($md && ($method_length > 1)));
482 $method_out =~ s/_/-/g if $utd;
484 if ( exists $params{$method} ) {
485 # if value are quoted with " or ', re-quote it
486 if ( $value =~ m{^[\'\"]+(.+)[\'\"]+$} ) {
487 $value = '"'. $1 . '"';
489 # quote values that contain spaces
490 elsif ( $value =~ m{\s+} ) {
491 $value = '"'. $value . '"';
495 $param_string .= ' '.$method_out.(exists $switches{$method} ? '' : $join.$value);
499 return $param_string;
502 sub DESTROY {
503 my $self= shift;
504 unless ( $self->save_tempfiles ) {
505 $self->cleanup();
507 $self->SUPER::DESTROY();