speelink fixes, patch courtesy Charles Plessy, fixes #3256
[bioperl-run.git] / lib / Bio / Tools / Run / AssemblerBase.pm
blob2941470987767ea62121011ce22c2dae4a525f1d
1 # $Id$
3 # BioPerl module for Bio::Tools::Run::AssemblerBase
5 # Please direct questions and support issues to <bioperl-l@bioperl.org>
7 # Cared for by Florent Angly <florent dot angly at gmail dot com>
9 # Copyright Florent Angly
11 # You may distribute this module under the same terms as perl itself
13 # POD documentation - main docs before the code
15 =head1 NAME
17 Bio::Tools::Run::AssemblerBase - base class for wrapping external assemblers
19 =head1 SYNOPSIS
21 Give standard usage here
23 =head1 DESCRIPTION
25 Describe the object here
26 # use of globals for configuration...
27 # I've created the separate Config.pm module, and 'use'd it in the
28 # main module, for instance...
29 # other configuration globals:
30 # $use_dash = [1|single|double|mixed]
32 =head1 FEEDBACK
34 =head2 Mailing Lists
36 User feedback is an integral part of the evolution of this and other
37 Bioperl modules. Send your comments and suggestions preferably to
38 the Bioperl mailing list. Your participation is much appreciated.
40 bioperl-l@bioperl.org - General discussion
41 http://bioperl.org/wiki/Mailing_lists - About the mailing lists
43 =head2 Support
45 Please direct usage questions or support issues to the mailing list:
47 L<bioperl-l@bioperl.org>
49 rather than to the module maintainer directly. Many experienced and
50 reponsive experts will be able look at the problem and quickly
51 address it. Please include a thorough description of the problem
52 with code and data examples if at all possible.
54 =head2 Reporting Bugs
56 Report bugs to the Bioperl bug tracking system to help us keep track
57 of the bugs and their resolution. Bug reports can be submitted via
58 the web:
60 http://redmine.open-bio.org/projects/bioperl/
62 =head1 AUTHOR - Florent Angly
64 Email florent dot angly at gmail dot com
66 =head1 CONTRIBUTORS
68 Mark A. Jensen - maj -at- fortinbras -dot- us
70 =head1 APPENDIX
72 The rest of the documentation details each of the object methods.
73 Internal methods are usually preceded with a _
75 =cut
77 package Bio::Tools::Run::AssemblerBase;
79 use strict;
80 use Bio::SeqIO;
81 use Bio::Assembly::IO;
83 use base qw(Bio::Root::Root Bio::Tools::Run::WrapperBase Bio::ParameterBaseI);
85 our $default_out_type = 'Bio::Assembly::ScaffoldI';
87 =head2 program_name
89 Title : program_name
90 Usage : $assembler>program_name()
91 Function: get/set the executable name
92 Returns: string
93 Args : string
95 =cut
97 sub program_name {
98 my ($self, $val) = @_;
99 $self->{'_program_name'} = $val if $val;
100 return $self->{'_program_name'};
104 =head2 program_dir
106 Title : program_dir
107 Usage : $assembler->program_dir()
108 Function: get/set the program dir
109 Returns: string
110 Args : string
112 =cut
114 sub program_dir {
115 my ($self, $val) = @_;
116 $self->{'_program_dir'} = $val if $val;
117 return $self->{'_program_dir'};
121 =head2 out_type
123 Title : out_type
124 Usage : $assembler->out_type('Bio::Assembly::ScaffoldI')
125 Function: get/set the desired type of output
126 Returns : The type of results to return
127 Args : Type of results to return (optional):
128 'Bio::Assembly::IO' object
129 'Bio::Assembly::ScaffoldI' object (default)
130 The name of a file to save the results in
132 =cut
134 sub out_type {
135 my ($self, $val) = @_;
136 if (defined $val) {
137 $self->{'_out_type'} = $val;
138 } else {
139 if (not defined $self->{'_out_type'}) {
140 $self->{'_out_type'} = $default_out_type;
143 return $self->{'_out_type'};
147 =head2 _assembly_format
149 Title : _assembly_format
150 Usage : $assembler->_assembly_format('ace')
151 Function: get/set the driver to use to parse the assembly results
152 Returns : the driver to use to parse the assembly results
153 Args : the driver to use to parse the assembly results (optional)
155 =cut
157 sub _assembly_format {
158 my ($self, $asm_format) = @_;
159 if (defined $asm_format) {
160 $self->{'_assembly_format'} = $asm_format;
162 return $self->{'_assembly_format'};
166 =head2 _assembly_variant
168 Title : _assembly_variant
169 Usage : $assembler->_assembly_variant('454')
170 Function: get/set the driver variant to use to parse the assembly results. For
171 example, the ACE format has the ACE-454 and the ACE-consed variants
172 Returns : the driver variant to use to parse the assembly results
173 Args : the driver variant to use to parse the assembly results (optional)
175 =cut
177 sub _assembly_variant {
178 my ($self, $asm_variant) = @_;
179 if (defined $asm_variant) {
180 $self->{'_assembly_variant'} = $asm_variant;
182 return $self->{'_assembly_variant'};
186 =head2 _check_executable
188 Title : _check_executable
189 Usage : $assembler->_check_executable()
190 Function: Verifies that the program executable can be found, or throw an error.
191 Returns: 1 for success
192 Args : -
194 =cut
196 sub _check_executable {
197 my ($self) = @_;
198 if (not defined $self->executable()) {
199 $self->throw("Could not find the executable '".$self->program_name()."'. ".
200 'You can use $self->program_dir() and $self->program_name() to '.
201 "specify the location of the program.");
203 return 1;
206 =head2 _check_sequence_input
208 Title : _check_sequence_input
209 Usage : $assembler->_check_sequence_input($seqs)
210 Function: Check that the sequence input is a valid file, or an arrayref of
211 sequence objects (Bio::PrimarySeqI or Bio::SeqI). If not, an
212 exception is thrown.
213 Returns : 1 if the check passed
214 Args : sequence input
216 =cut
218 sub _check_sequence_input {
219 my ($self, $seqs) = @_;
220 if (not $seqs) {
221 $self->throw("Must supply sequences as a FASTA filename or a sequence object".
222 " (Bio::PrimarySeqI or Bio::SeqI) array reference");
223 } else {
224 if (ref($seqs) =~ m/ARRAY/i ) {
225 for my $seq (@$seqs) {
226 unless ($seq->isa('Bio::PrimarySeqI') || $seq->isa('Bio::SeqI')) {
227 $self->throw("Not a valid Bio::PrimarySeqI or Bio::SeqI object");
230 } else {
231 if (not -f $seqs) {
232 $self->throw("Input file '$seqs' does not seem to exist.");
236 return 1;
239 =head2 _check_optional_quality_input
241 Title : _check_optional_quality_input
242 Usage : $assembler->_check_optional_quality_input($quals)
243 Function: If a quality score input is provided, check that it is either a
244 valid file or an arrayref of quality score objects (Bio::Seq::
245 QualI or Bio::Seq::Quality). If not, an exception is thrown.
246 Returns : 1 if the check passed (or quality score input was provided)
247 Args : quality score input
249 =cut
251 sub _check_optional_quality_input {
252 my ($self, $quals) = @_;
253 if (defined $quals) {
254 if (ref($quals) =~ m/ARRAY/i) {
255 for my $qual (@$quals) {
256 unless ($qual->isa('Bio::Seq::QualI') || $qual->isa('Bio::Seq::Quality')) {
257 $self->throw("Not a valid Bio::Seq::QualI or Bio::Seq::Quality object");
260 } else {
261 if (not -f $quals) {
262 $self->throw("Input file '$quals' does not seem to exist.");
266 return 1;
270 =head2 _prepare_input_file
272 Title : _prepare_input_file
273 Usage : ($fasta_file, $qual_file) = $assembler->_prepare_input_file(\@seqs, \@quals);
274 Function: Create the input FASTA and QUAL files as needed. If the input
275 sequences are provided in a (FASTA) file, the optional input quality
276 scores are also expected to be in a (QUAL) file. If the input
277 sequences are an arrayref of bioperl sequence objects, the optional
278 input quality scores are expected to be an arrayref of bioperl
279 quality score objects, in the same order as the sequence objects.
280 Returns : - input filehandle
281 - input filename
282 Args : - sequence input (FASTA file or sequence object arrayref)
283 - optional quality score input (QUAL file or quality score object
284 arrayref)
286 =cut
288 sub _prepare_input_files {
289 my ($self, $seqs, $quals) = @_;
290 # Set up input FASTA and QUAL files
291 $self->io->_initialize_io();
292 #$self->tempdir();
293 my $fasta_file;
294 my $qual_file;
295 if ( ref($seqs) =~ m/ARRAY/i ) {
296 # Input sequences are an arrayref of Bioperl sequence objects
297 if (defined $quals && not ref($quals) =~ m/ARRAY/i) {
298 $self->throw("The input sequences are an arrayref of sequence objects. ".
299 "Expecting the quality scores as an arrayref of quality score objects");
300 } else {
301 # The input qualities are not defined or are an arrayref of quality objects
302 # Write temp FASTA and QUAL input files
303 ($fasta_file, $qual_file) = $self->_write_seq_file($seqs, $quals);
305 } else {
306 # Sequence input is a FASTA file
307 $fasta_file = $seqs;
308 if (defined $quals && ref($quals) =~ m/ARRAY/i) {
309 # Quality input is defined and is an arrayref of quality objects
310 $self->throw("The input sequences are in a FASTA file. Expecting the ".
311 "quality scores in a QUAL file.");
312 } else {
313 # Input quality scores is either not defined or is a QUAL file
314 $qual_file = $quals;
317 return $fasta_file, $qual_file;
321 =head2 _write_seq_file
323 Title : _write_seq_file
324 Usage : ($fasta_file, $qual_file) = $assembler->_write_seq_file(\@seqs, \@quals)
325 Function: Write temporary FASTA and QUAL files on disk
326 Returns : name of FASTA file
327 name of QUAL file (undef if no quality scoress)
328 Args : - arrayref of sequence objects
329 - optional arrayref of quality score objects
331 =cut
333 sub _write_seq_file {
334 my ($self, $seqs, $quals) = @_;
335 # Store the sequences in temporary FASTA files
336 my $tmpdir = $self->tempdir();
337 my ($fasta_h, $fasta_file) = $self->io->tempfile( -dir => $tmpdir );
338 my ($qual_h, $qual_file ) = $self->io->tempfile( -dir => $tmpdir );
339 my $fasta_out = Bio::SeqIO->new( -fh => $fasta_h , -format => 'fasta');
340 my $qual_out = Bio::SeqIO->new( -fh => $qual_h , -format => 'qual' );
341 my $use_qual_file = 0;
342 my $size = scalar @$seqs;
343 for ( my $i = 0 ; $i < $size ; $i++ ) {
344 my $seq = $$seqs[$i];
345 # Make sure that all sequences have an ID (to prevent TIGR Assembler crash)
346 if (not defined $seq->id) {
347 my $newid = 'tmp'.$i;
348 print $newid."\n";
349 $seq->id($newid);
350 $self->warn("A sequence had no ID. Its ID is now $newid");
352 my $seqid = $seq->id;
353 # Write the FASTA entries in files (and QUAL if appropriate)
354 $fasta_out->write_seq($seq);
355 if ($seq->isa('Bio::Seq::Quality')) {
356 # Quality scores embedded in seq object
357 if (scalar @{$seq->qual} > 0) {
358 $qual_out->write_seq($seq);
359 $use_qual_file = 1;
361 } else {
362 # Quality score in a different object from the sequence object
363 my $qual = $$quals[$i];
364 if (defined $qual) {
365 my $qualid = $qual->id;
366 if ($qualid eq $seqid) {
367 # valid quality score information
368 $qual_out->write_seq($qual);
369 $use_qual_file = 1;
370 } else {
371 # ID mismatch between sequence and quality score
372 $self->warn("Sequence object with ID $seqid does not match quality ".
373 "score object with ID $qualid");
378 close($fasta_h);
379 close($qual_h);
380 $fasta_out->close();
381 $qual_out->close();
382 return undef if scalar @$seqs <= 0;
383 $qual_file = undef if $use_qual_file == 0;
384 return $fasta_file, $qual_file;
388 =head2 _prepare_output_file
390 Title : _prepare_output_file
391 Usage : ($out_fh, $out_file) = $assembler->_prepare_output_file( );
392 Function: Prepare the output file
393 Returns : - output filehandle
394 - output filename
395 Args : none
397 =cut
399 sub _prepare_output_file {
400 my ($self) = @_;
401 my ($output_fh, $output_file);
402 my $out_type = $self->out_type();
403 if ( (not $out_type eq 'Bio::Assembly::ScaffoldI') &&
404 (not $out_type eq 'Bio::Assembly::IO' ) ) {
405 # Output is a file with specified name
406 $output_file = $out_type;
407 open $output_fh, '>', $output_file or $self->throw("Could not write file ".
408 "'$output_file': $!");
409 } else {
410 ( $output_fh, $output_file ) = $self->io->tempfile( -dir => $self->tempdir() );
412 $self->outfile_name($output_file);
413 return $output_fh, $output_file;
416 =head2 _export_results
418 Title : _export_results
419 Usage : $results = $assembler->_export_results($asm_file);
420 Function: Export the assembly results
421 Returns : Exported assembly (file or IO object or assembly object)
422 Args : -Name of the file containing an assembly
423 - -keep_asm => boolean (if true, do not unlink $asm_file)
424 -[optional] additional named args required by the B:A:IO object
426 =cut
428 sub _export_results {
429 my ($self, $asm_file, @named_args) = @_;
430 my $results;
431 my $asm_io;
432 my $asm;
433 my %args = @named_args;
434 my $keep_asm = $args{'-keep_asm'};
435 delete $args{'-keep_asm'};
436 my $out_type = $self->out_type();
437 if ( (not $out_type eq 'Bio::Assembly::ScaffoldI') &&
438 (not $out_type eq 'Bio::Assembly::IO' ) ) {
439 # Results are the assembler output file
440 $results = $asm_file;
441 } else {
442 $asm_io = Bio::Assembly::IO->new(
443 -file => "<$asm_file",
444 -format => $self->_assembly_format(),
445 -variant => $self->_assembly_variant(),
446 @named_args );
447 # this unlink is a problem for Bio::DB::Sam (in B:A:I:sam), which needs
448 # the original bam file around.
449 unlink $asm_file unless $keep_asm;
450 if ($out_type eq 'Bio::Assembly::IO') {
451 # Results are a Bio::Assembly::IO object
452 $results = $asm_io;
453 } else {
454 $asm = $asm_io->next_assembly();
455 $asm_io->close;
456 if ($out_type eq 'Bio::Assembly::ScaffoldI') {
457 # Results are a Bio::Assembly::Scaffold object
458 $results = $asm;
459 } else {
460 $self->throw("The return type has to be 'Bio::Assembly::IO', 'Bio::".
461 "Assembly::ScaffoldI' or a file name.");
465 $self->cleanup();
466 return $results;
470 =head2 _register_program_commands()
472 Title : _register_program_commands
473 Usage : $assembler->_register_program_commands( \@commands, \%prefixes )
474 Function: Register the commands a program accepts (for programs that act
475 as frontends for a set of commands, each command having its own
476 set of params/switches)
477 Returns : true on success
478 Args : arrayref to a list of commands (scalar strings),
479 hashref to a translation table of the form
480 { $prefix1 => $command1, ... } [optional]
481 Note : To implement a program with this kind of calling structure,
482 include a parameter called 'command' in the
483 @program_params global
484 Note : The translation table is used to associate parameters and
485 switches specified in _set_program_options with the correct
486 program command. In the globals @program_params and
487 @program_switches, specify elements as 'prefix1|param' and
488 'prefix1|switch', etc.
490 =cut
492 sub _register_program_commands {
493 my ($self, $commands, $prefixes) = @_;
494 $self->{'_options'}->{'_commands'} = $commands;
495 $self->{'_options'}->{'_prefixes'} = $prefixes;
496 return 1;
499 =head2 _set_program_options
501 Title : _set_program_options
502 Usage : $assembler->_set_program_options( \@ args );
503 Function: Register the parameters and flags that an assembler takes.
504 Returns : 1 for success
505 Args : - arguments passed by the user
506 - parameters that the program accepts, optional (default: none)
507 - switches that the program accepts, optional (default: none)
508 - parameter translation, optional (default: no translation occurs)
509 - dash option for the program parameters, [1|single|double|mixed],
510 optional (default: yes, use single dashes only)
511 - join, optional (default: ' ')
513 =cut
515 sub _set_program_options {
516 my ($self, $args, $params, $switches, $translation, $qual_param, $use_dash, $join) = @_;
517 # I think we need to filter on the basis of -command here...
518 my %args = @$args;
519 my $cmd = $args{'-command'} || $args{'command'};
520 if ($cmd) {
521 my (@p,@s, %x);
522 $self->warn('Command found, but no commands registered; invoke _register_program_commands') unless $self->{'_options'}->{'_commands'};
523 $self->throw("Command '$cmd' not registered") unless grep /^$cmd$/, @{$self->{'_options'}->{'_commands'}};
524 if ($self->{'_options'}->{'_prefixes'}) {
525 $cmd = $self->{'_options'}->{'_prefixes'}->{$cmd};
526 } # else, the command is its own prefix
528 # problem here: if a param/switch does not have a prefix (pfx|), then
529 # should probably allow it to pass thru...
530 @p = (grep(!/^.*?\|/, @$params), $cmd ? grep(/^${cmd}\|/, @$params) : ());
531 @s = (grep(!/^.*?\|/, @$switches), $cmd ? grep(/^${cmd}\|/, @$switches) : ());
532 s/.*?\|// for @p;
533 s/.*?\|// for @s;
534 @x{@p, @s} = @{$translation}{
535 grep( !/^.*?\|/, @$params, @$switches),
536 $cmd ? grep(/^${cmd}\|/, @$params, @$switches) : () };
537 $translation = \%x;
538 $params = \@p;
539 $switches = \@s;
541 $self->{'_options'}->{'_params'} = $params;
542 $self->{'_options'}->{'_switches'} = $switches;
543 $self->{'_options'}->{'_translation'} = $translation;
544 $self->{'_options'}->{'_qual_param'} = $qual_param;
545 if (not defined $use_dash) {
546 $self->{'_options'}->{'_dash'} = 1;
547 } else {
548 $self->{'_options'}->{'_dash'} = $use_dash;
550 if (not defined $join) {
551 $self->{'_options'}->{'_join'} = ' ';
552 } else {
553 $self->{'_options'}->{'_join'} = $join;
555 # if there is a parameter 'command' in @program_params, and
556 # new is called with new( -command => $cmd, ... ), then
557 # _set_from_args will create an accessor $self->command containing
558 # the value $cmd...
559 $self->_set_from_args(
560 $args,
561 -methods => [ @$params, @$switches, 'program_name', 'program_dir', 'out_type' ],
562 -create => 1,
563 # when our parms are accessed, signal parameters are unchanged for
564 # future reads (until set_parameters is called)
565 -code =>
566 'my $self = shift;
567 $self->parameters_changed(0);
568 return $self->{\'_\'.$method} = shift if @_;
569 return $self->{\'_\'.$method};'
571 return 1;
575 =head2 _translate_params
577 Title : _translate_params
578 Usage : @options = $assembler->_translate_params( );
579 Function: Translate the Bioperl arguments into the arguments to pass to the
580 assembler on the command line
581 Returns : Arrayref of arguments
582 Args : none
584 =cut
586 sub _translate_params {
587 my ($self) = @_;
589 # Get option string
590 my $params = $self->{'_options'}->{'_params'};
591 my $switches = $self->{'_options'}->{'_switches'};
592 my $join = $self->{'_options'}->{'_join'};
593 my $dash = $self->{'_options'}->{'_dash'};
594 my $translat = $self->{'_options'}->{'_translation'};
595 # patch to access the multiple dash choices of _setparams...
596 my @dash_args;
597 $dash ||= 1; # default as advertised
598 for ($dash) {
599 $_ == 1 && do {
600 @dash_args = ( -dash => 1 );
601 last;
603 /^s/ && do { #single dash only
604 @dash_args = ( -dash => 1);
605 last;
607 /^d/ && do { # double dash only
608 @dash_args = ( -double_dash => 1);
609 last;
611 /^m/ && do { # mixed dash: one-letter opts get -,
612 # long opts get --
613 @dash_args = ( -mixed_dash => 1);
614 last;
616 do {
617 $self->warn( "Dash spec '$dash' not recognized; using 'single'" );
618 @dash_args = ( -dash => 1 );
621 my $options = $self->_setparams(
622 -params => $params,
623 -switches => $switches,
624 -join => $join,
625 @dash_args
628 # Translate options
629 my @options = split(/(\s|$join)/, $options);
630 for (my $i = 0; $i < scalar @options; $i++) {
631 my ($prefix, $name) = ( $options[$i] =~ m/^(-{0,2})(.+)$/ );
632 if (defined $name) {
633 if ($name =~ /command/i) {
634 $name = $options[$i+2]; # get the command
635 splice @options, $i, 4;
636 unshift @options, $name; # put it first
638 elsif (defined $$translat{$name}) {
639 $options[$i] = $prefix.$$translat{$name};
642 else {
643 splice @options, $i, 1;
644 $i--;
647 $options = join('', @options);
649 # this is a kludge for mixed options: the reason mixed doesn't
650 # work right on the pass through _setparams is that the
651 # *aliases* and not the actual params are passed to it.
652 # here we just rejigger the dashes
653 if ($dash =~ /^m/) {
654 $options =~ s/--([a-z0-9](?:\s|$))/-$1/gi;
657 # Now arrayify the options
658 @options = split(' ', $options);
660 return \@options;
664 =head2 _prepare_input_sequences
666 Title : _prepare_input_sequences
667 Usage : ($seqs, $quals) = $assembler->_prepare_input_sequences(\@seqs, \@quals);
668 Function: Do something to the input sequence and qual objects. By default,
669 nothing happens. Overload this method in the specific assembly module
670 if processing of the sequences is needed (e.g. as in the
671 TigrAssembler module).
672 Returns : - sequence input
673 - optional quality score input
674 Args : - sequence input (FASTA file or sequence object arrayref)
675 - optional quality score input (QUAL file or quality score object
676 arrayref)
678 =cut
680 sub _prepare_input_sequences {
681 my ($self, $seqs, $quals) = @_;
682 return $seqs, $quals;
685 =head2 _collate_subcmd_args()
687 Title : _collate_subcmd_args
688 Usage : $args_hash = $self->_collate_subcmd_args
689 Function: collate parameters and switches into command-specific
690 arg lists for passing to new()
691 Returns : hash of named argument lists
692 Args : [optional] composite cmd prefix (scalar string)
693 [default is 'run']
695 =cut
697 sub _collate_subcmd_args {
698 my $self = shift;
699 my $cmd = shift;
700 my %ret;
701 # default command is 'run'
702 $cmd ||= 'run';
703 my @subcmds = @{$self->{'_options'}->{'_composite_commands'}->{$cmd}};
704 my %subcmds;
705 my $cur_options = $self->{'_options'};
707 # collate
708 foreach my $subcmd (@subcmds) {
709 # find the composite cmd form of the argument in
710 # the current params and switches
711 # e.g., map_max_mismatches
712 my @params = grep /^${subcmd}_/, @{$$cur_options{'_params'}};
713 my @switches = grep /^${subcmd}_/, @{$$cur_options{'_switches'}};
714 $ret{$subcmd} = [];
715 # create an argument list suitable for passing to new() of
716 # the subcommand factory...
717 foreach my $opt (@params, @switches) {
718 my $subopt = $opt;
719 $subopt =~ s/^${subcmd}_//;
720 push(@{$ret{$subcmd}}, '-'.$subopt => $self->$opt) if defined $self->$opt;
723 return \%ret;
726 =head2 run
728 Title : run
729 Usage : $assembly = $assembler->run(\@seqs, \@quals);
731 $assembly = $assembler->run($fasta_file, $qual_file);
732 Function: Run the assembler. The specific assembler wrapper needs to provide
733 the $assembler->_run() method.
734 Returns : Assembly results (file, IO object or Assembly object)
735 Args : - sequence input (FASTA file or sequence object arrayref)
736 - optional quality score input (QUAL file or quality score object
737 arrayref)
739 =cut
741 sub run {
742 my ($self, $seqs, $quals) = @_;
744 # Sanity checks
745 $self->_check_executable();
746 $self->_check_sequence_input($seqs);
747 $self->_check_optional_quality_input($quals);
749 # Process objects if needed
750 $self->_prepare_input_sequences($seqs, $quals);
752 # Write input files
753 my ($fasta_file, $qual_file) = $self->_prepare_input_files($seqs,$quals);
755 # If needed, set the program argument for a QUAL file
756 my $qual_param = $self->{'_options'}->{'_qual_param'};
757 if (defined $qual_param) {
758 if ($qual_file) {
759 # Set the quality input parameter
760 $quals = $self->$qual_param($qual_file);
761 } else {
762 # Remove the quality input parameter
763 $quals = $self->$qual_param(undef);
767 # Assemble
768 my $output_file = $self->_run($fasta_file, $qual_file);
770 # Export results in desired object type
771 my $asm = $self->_export_results($output_file);
772 return $asm;
775 =head1 Bio:ParameterBaseI compliance
777 =head2 set_parameters()
779 Title : set_parameters
780 Usage : $pobj->set_parameters(%params);
781 Function: sets the parameters listed in the hash or array
782 Returns : true on success
783 Args : [optional] hash or array of parameter/values.
785 =cut
787 sub set_parameters {
788 my ($self, @args) = @_;
790 # currently stored stuff
791 my $opts = $self->{'_options'};
792 my $params = $opts->{'_params'};
793 my $switches = $opts->{'_switches'};
794 my $translation = $opts->{'_translation'};
795 my $qual_param = $opts->{'_qual_param'};
796 my $use_dash = $opts->{'_dash'};
797 my $join = $opts->{'_join'};
799 $self->_set_program_options(\@args, $params, $switches, $translation,
800 $qual_param, $use_dash, $join);
801 # the question is, are previously-set parameters left alone when
802 # not specified in @args?
803 $self->parameters_changed(1);
804 return 1;
807 =head2 reset_parameters()
809 Title : reset_parameters
810 Usage : resets values
811 Function: resets parameters to either undef or value in passed hash
812 Returns : none
813 Args : [optional] hash of parameter-value pairs
815 =cut
817 sub reset_parameters {
818 my ($self, @args) = @_;
820 my @reset_args;
821 # currently stored stuff
822 my $opts = $self->{'_options'};
823 my $params = $opts->{'_params'};
824 my $switches = $opts->{'_switches'};
825 my $translation = $opts->{'_translation'};
826 my $qual_param = $opts->{'_qual_param'};
827 my $use_dash = $opts->{'_dash'};
828 my $join = $opts->{'_join'};
830 # don't like this, b/c _set_program_args will create a bunch of
831 # accessors with undef values, but oh well for now /maj
833 for my $p (@$params) {
834 push(@reset_args, $p => undef) unless grep /^$p$/, @args;
836 for my $s (@$switches) {
837 push(@reset_args, $s => undef) unless grep /^$s$/, @args;
839 push @args, @reset_args;
841 $self->_set_program_options(\@args, $params, $switches, $translation,
842 $qual_param, $use_dash, $join);
843 $self->parameters_changed(1);
846 =head2 parameters_changed()
848 Title : parameters_changed
849 Usage : if ($pobj->parameters_changed) {...}
850 Function: Returns boolean true (1) if parameters have changed
851 Returns : Boolean (0 or 1)
852 Args : [optional] Boolean
854 =cut
856 sub parameters_changed {
857 my $self = shift;
858 return $self->{'_parameters_changed'} = shift if @_;
859 return $self->{'_parameters_changed'};
862 =head2 available_parameters()
864 Title : available_parameters
865 Usage : @params = $pobj->available_parameters()
866 Function: Returns a list of the available parameters
867 Returns : Array of parameters
868 Args : 'params' for settable program parameters
869 'switches' for boolean program switches
870 default: all
872 =cut
874 sub available_parameters {
875 my $self = shift;
876 my $subset = shift;
877 my $opts = $self->{'_options'};
878 my @ret;
879 for ($subset) {
880 (!defined || /^a/) && do {
881 @ret = (@{$opts->{'_params'}}, @{$opts->{'_switches'}});
882 last;
884 m/^p/i && do {
885 @ret = @{$opts->{'_params'}};
886 last;
888 m/^s/i && do {
889 @ret = @{$opts->{'_switches'}};
890 last;
892 do { #fail
893 $self->throw("available_parameters: unrecognized subset");
896 return @ret;
899 =head2 get_parameters()
901 Title : get_parameters
902 Usage : %params = $pobj->get_parameters;
903 Function: Returns list of key-value pairs of parameter => value
904 Returns : List of key-value pairs
905 Args : [optional] A string is allowed if subsets are wanted or (if a
906 parameter subset is default) 'all' to return all parameters
908 =cut
910 sub get_parameters {
911 my $self = shift;
912 my $subset = shift;
913 $subset ||= 'all';
914 my @ret;
915 my $opts = $self->{'_options'};
916 for ($subset) {
917 m/^p/i && do { #params only
918 for (@{$opts->{'_params'}}) {
919 push(@ret, $_, $self->$_) if $self->can($_) && defined $self->$_;
921 last;
923 m/^s/i && do { #switches only
924 for (@{$opts->{'_switches'}}) {
925 push(@ret, $_, $self->$_) if $self->can($_) && defined $self->$_;
927 last;
929 m/^a/i && do { # all
930 for (@{$opts->{'_params'}},@{$opts->{'_switches'}}) {
931 push(@ret, $_, $self->$_) if $self->can($_) && defined $self->$_;
933 last;
935 do {
936 $self->throw("get_parameters: unrecognized subset");
939 return @ret;