File Coverage

blib/lib/Bio/Tools/Run/Maq.pm
Criterion Covered Total %
statement 47 204 23.0
branch 7 80 8.7
condition 0 26 0.0
subroutine 11 22 50.0
pod 6 8 75.0
total 71 340 20.8


line stmt bran cond sub pod time code
1             #
2             # BioPerl module for Bio::Tools::Run::Maq
3             #
4             # Please direct questions and support issues to
5             #
6             # Cared for by Mark A. Jensen
7             #
8             # Copyright Mark A. Jensen
9             #
10             # You may distribute this module under the same terms as perl itself
11              
12             # POD documentation - main docs before the code
13              
14             =head1 NAME
15              
16             Bio::Tools::Run::Maq - Run wrapper for the Maq short-read assembler *BETA*
17              
18             =head1 SYNOPSIS
19              
20             # create an assembly
21             $maq_fac = Bio::Tools::Run::Maq->new();
22             $maq_assy = $maq_fac->run( 'reads.fastq', 'refseq.fas' );
23             # if IO::Uncompress::Gunzip is available...
24             $maq_assy = $maq_fac->run( 'reads.fastq.gz', 'refseq.gz');
25             # paired-end
26             $maq_assy = $maq_fac->run( 'reads.fastq', 'refseq.fas', 'paired-reads.fastq');
27             # be more strict
28             $maq_fac->set_parameters( -c2q_min_map_quality => 60 );
29             $maq_assy = $maq_fac->run( 'reads.fastq', 'refseq.fas', 'paired-reads.fastq');
30              
31             # run maq commands separately
32             $maq_fac = Bio::Tools::Run::Maq->new(
33             -command => 'pileup',
34             -single_end_quality => 1 );
35             $maq_fac->run_maq( -bfa => 'refseq.bfa',
36             -map => 'maq_assy.map',
37             -txt => 'maq_assy.pup.txt' );
38              
39             =head1 DESCRIPTION
40              
41             This module provides a wrapper interface for Heng Li's
42             reference-directed short read assembly suite C (see
43             L for manuals and
44             downloads).
45              
46             There are two modes of action.
47              
48             =over
49              
50             =item * EasyMaq
51              
52             The first is a simple pipeline through the C commands, taking
53             your read data in and squirting out an assembly object of type
54             L. The pipeline is based on the one performed
55             by C:
56              
57             Action maq commands
58             ------ ------------
59             data conversion to fasta2bfa, fastq2bfq
60             maq binary formats
61              
62             map sequence reads map
63             to reference seq
64              
65             assemble, creating assemble
66             consensus
67              
68             convert map & cns mapview, cns2fq
69             files to plaintext
70             (for B:A:IO:maq)
71              
72             Command-line options can be directed to the C, C, and
73             C steps. See L below.
74              
75             =item * BigMaq
76              
77             The second mode is direct access to C commands. To run a C
78             command, construct a run factory, specifying the desired command using
79             the C<-command> argument in the factory constructor, along with
80             options specific to that command (see L):
81              
82             $maqfac->Bio::Tools::Run::Maq->new( -command => 'fasta2bfa' );
83              
84             To execute, use the C methods. Input and output files are
85             specified in the arguments of C (see L):
86              
87             $maqfac->run_maq( -fas => "myref.fas", -bfa => "myref.bfa" );
88              
89             =back
90              
91             =head1 OPTIONS
92              
93             C is complex, with many subprograms (commands) and command-line
94             options and file specs for each. This module attempts to provide
95             commands and options comprehensively. You can browse the choices like so:
96              
97             $maqfac = Bio::Tools::Run::Maq->new( -command => 'assemble' );
98             # all maq commands
99             @all_commands = $maqfac->available_parameters('commands');
100             @all_commands = $maqfac->available_commands; # alias
101             # just for assemble
102             @assemble_params = $maqfac->available_parameters('params');
103             @assemble_switches = $maqfac->available_parameters('switches');
104             @assemble_all_options = $maqfac->available_parameters();
105              
106             Reasonably mnemonic names have been assigned to the single-letter
107             command line options. These are the names returned by
108             C, and can be used in the factory constructor
109             like typical BioPerl named parameters.
110              
111             See L for the gory details.
112              
113             =head1 FILES
114              
115             When a command requires filenames, these are provided to the C method, not
116             the constructor (C). To see the set of files required by a command, use
117             C or the alias C:
118              
119             $maqfac = Bio::Tools::Run::Maq->new( -command => 'map' );
120             @filespec = $maqfac->filespec;
121              
122             This example returns the following array:
123              
124             map
125             bfa
126             bfq1
127             #bfq2
128             2>#log
129              
130             This indicates that map (C binary mapfile), bfa (C binary
131             fasta), and bfq (C binary fastq) files MUST be specified, another
132             bfq file MAY be specified, and a log file receiving STDERR also MAY be
133             specified. Use these in the C call like so:
134              
135             $maqfac->run_maq( -map => 'my.map', -bfa => 'myrefseq.bfa',
136             -bfq1 => 'reads1.bfq', -bfq2 => 'reads2.bfq' );
137              
138             Here, the C parameter was unspecified. Therefore, the object will store
139             the programs STDERR output for you in the C attribute:
140              
141             handle_map_warning($maqfac) if ($maqfac->stderr =~ /warning/);
142              
143             STDOUT for a run is also saved, in C, unless a file is specified
144             to slurp it according to the filespec. C STDOUT usually contains useful
145             information on the run.
146              
147             =head1 FEEDBACK
148              
149             =head2 Mailing Lists
150              
151             User feedback is an integral part of the evolution of this and other
152             Bioperl modules. Send your comments and suggestions preferably to
153             the Bioperl mailing list. Your participation is much appreciated.
154              
155             bioperl-l@bioperl.org - General discussion
156             http://bioperl.org/wiki/Mailing_lists - About the mailing lists
157              
158             =head2 Support
159              
160             Please direct usage questions or support issues to the mailing list:
161              
162             L
163              
164             rather than to the module maintainer directly. Many experienced and
165             reponsive experts will be able look at the problem and quickly
166             address it. Please include a thorough description of the problem
167             with code and data examples if at all possible.
168              
169             =head2 Reporting Bugs
170              
171             Report bugs to the Bioperl bug tracking system to help us keep track
172             of the bugs and their resolution. Bug reports can be submitted via
173             the web:
174              
175             http://redmine.open-bio.org/projects/bioperl/
176              
177             =head1 AUTHOR - Mark A. Jensen
178              
179             Email maj -at- fortinbras -dot- us
180              
181             =head1 APPENDIX
182              
183             The rest of the documentation details each of the object methods.
184             Internal methods are usually preceded with a _
185              
186             =cut
187              
188             # Let the code begin...
189              
190              
191             package Bio::Tools::Run::Maq;
192 1     1   132650 use strict;
  1         4  
  1         48  
193             our $HAVE_IO_UNCOMPRESS;
194              
195             BEGIN {
196 1     1   3 eval {require IO::Uncompress::Gunzip; $HAVE_IO_UNCOMPRESS = 1};
  1         314  
  1         29208  
197             }
198              
199 1     1   7 use IPC::Run;
  1         2  
  1         36  
200              
201             # Object preamble - inherits from Bio::Root::Root
202              
203 1     1   255 use lib '../../..';
  1         542  
  1         4  
204 1     1   376 use Bio::Root::Root;
  1         17869  
  1         41  
205 1     1   312 use Bio::Tools::Run::Maq::Config;
  1         2  
  1         104  
206 1     1   305 use Bio::Tools::GuessSeqFormat;
  1         3042  
  1         34  
207 1     1   6 use File::Basename qw(fileparse);
  1         2  
  1         74  
208              
209 1     1   9 use base qw(Bio::Root::Root Bio::Tools::Run::AssemblerBase );
  1         3  
  1         384  
210              
211             ## maq ( from tigr )
212             our $program_name = 'maq'; # name of the executable
213              
214             # Note:
215             # other globals required by Bio::Tools::Run::AssemblerBase are
216             # imported from Bio::Tools::Run::Maq::Config
217              
218             our $qual_param = 'quality_file';
219             our $use_dash = 1;
220             our $join = ' ';
221              
222             our $asm_format = 'maq';
223              
224             =head2 new()
225              
226             Title : new
227             Usage : my $obj = new Bio::Tools::Run::Maq();
228             Function: Builds a new Bio::Tools::Run::Maq object
229             Returns : an instance of Bio::Tools::Run::Maq
230             Args :
231              
232             =cut
233              
234             sub new {
235 1     1 1 23 my ($class,@args) = @_;
236 1         19 my $self = $class->SUPER::new(@args);
237 1         62 $self->parameters_changed(1);
238 1         8 $self->_register_program_commands( \@program_commands, \%command_prefixes );
239 1 50       13 unless (grep /command/, @args) {
240 0         0 push @args, '-command', 'run';
241             }
242 1         8 $self->_set_program_options(\@args, \@program_params, \@program_switches,
243             \%param_translation, $qual_param, $use_dash, $join);
244 1 50       4 $self->program_name($program_name) if not defined $self->program_name();
245 1 50       4 if ($^O =~ /cygwin/) {
246 0         0 my @kludge = `PATH=\$PATH:/usr/bin:/usr/local/bin which $program_name`;
247 0         0 chomp $kludge[0];
248 0         0 $self->program_name($kludge[0]);
249             }
250 1         4 $self->parameters_changed(1); # set on instantiation, per Bio::ParameterBaseI
251 1         7 $self->_assembly_format($asm_format);
252 1         7 return $self;
253             }
254              
255             =head2 run
256              
257             Title : run
258             Usage : $assembly = $maq_assembler->run($read1_fastq_file,
259             $refseq_fasta_file,
260             $read2_fastq_file);
261             Function: Run the maq assembly pipeline.
262             Returns : Assembly results (file, IO object or Assembly object)
263             Args : - fastq file containing single-end reads
264             - fasta file containing the reference sequence
265             - [optional] fastq file containing paired-end reads
266             Note : gzipped inputs are allowed if IO::Uncompress::Gunzip
267             is available
268            
269             =cut
270              
271             sub run {
272 0     0 1 0 my ($self, $rd1_file, $ref_file, $rd2_file) = @_;
273              
274             # Sanity checks
275 0         0 $self->_check_executable();
276 0 0       0 $rd1_file or $self->throw("Fastq reads file required at arg 1");
277 0 0       0 $ref_file or $self->throw("Fasta refseq file required at arg 2");
278             # expand gzipped files as nec.
279 0         0 for ($rd1_file, $ref_file, $rd2_file) {
280 0 0       0 next unless $_;
281 0 0       0 if (/\.gz[^.]*$/) {
282 0 0       0 unless ($HAVE_IO_UNCOMPRESS) {
283 0         0 croak( "IO::Uncompress::Gunzip not available, can't expand '$_'" );
284             }
285 0         0 my ($tfh, $tf) = $self->io->tempfile;
286 0         0 my $z = IO::Uncompress::Gunzip->new($_);
287 0         0 while (<$z>) { print $tfh $_ }
  0         0  
288 0         0 close $tfh;
289 0         0 $_ = $tf;
290             }
291             }
292 0         0 my $guesser = Bio::Tools::GuessSeqFormat->new(-file=>$rd1_file);
293              
294 0 0       0 $guesser->guess eq 'fastq' or $self->throw("Reads file doesn't look like fastq at arg 1");
295 0         0 $guesser = Bio::Tools::GuessSeqFormat->new(-file=>$ref_file);
296 0 0       0 $guesser->guess eq 'fasta' or $self->throw("Refseq file doesn't look like fasta at arg 2");
297 0 0       0 if ($rd2_file) {
298 0         0 $guesser = Bio::Tools::GuessSeqFormat->new(-file=>$rd2_file);
299 0 0       0 $guesser->guess eq 'fastq' or $self->throw("Reads file doesn't look like fastq at arg 3");
300             }
301              
302             # maq format conversion
303 0         0 ($rd1_file, $ref_file, $rd2_file) = $self->_prepare_input_sequences($rd1_file, $ref_file, $rd2_file);
304              
305             # Assemble
306 0         0 my ($maq_file, $faq_file) = $self->_run($rd1_file, $ref_file, $rd2_file);
307              
308             # Export results in desired object type
309 0         0 my $asm = $self->_export_results($maq_file);
310 0         0 return $asm;
311             }
312              
313             =head2 run_maq()
314              
315             Title : run_maq
316             Usage : $obj->run_maq( @file_args )
317             Function: Run a maq command as specified during object contruction
318             Returns :
319             Args : a specification of the files to operate on:
320              
321             =cut
322              
323             sub run_maq {
324 0     0 1 0 my ($self, @args) = @_;
325             # _translate_params will provide an array of command/parameters/switches
326             # -- these are set at object construction
327             # to set up the run, need to add the files to the call
328             # -- provide these as arguments to this function
329              
330 0 0       0 my $cmd = $self->command if $self->can('command');
331 0 0       0 $self->throw("No maq command specified for the object") unless $cmd;
332             # setup files necessary for this command
333 0         0 my $filespec = $command_files{$cmd};
334 0 0       0 $self->throw("No command-line file specification is defined for command '$cmd'; check Bio::Tools::Run::Maq::Config") unless $filespec;
335              
336             # parse args based on filespec
337             # require named args
338 0 0       0 $self->throw("Named args are required") unless !(@args % 2);
339 0         0 s/^-// for @args;
340 0         0 my %args = @args;
341             # validate
342             my @req = map {
343 0         0 my $s = $_;
  0         0  
344 0         0 $s =~ s/^[012]?[<>]//;
345 0         0 $s =~ s/[^a-zA-Z0-9_]//g;
346 0         0 $s
347             } grep !/[#]/, @$filespec;
348 0   0     0 !defined($args{$_}) && $self->throw("Required filearg '$_' not specified") for @req;
349             # set up redirects
350 0         0 my ($in, $out, $err);
351 0         0 for (@$filespec) {
352 0 0       0 m/^1?>(.*)/ && do {
353 0 0 0     0 defined($args{$1}) && ( open($out,">", $args{$1}) or $self->throw("Open for write error : $!"));
354 0         0 next;
355             };
356 0 0       0 m/^2>#?(.*)/ && do {
357 0 0 0     0 defined($args{$1}) && (open($err, ">", $args{$1}) or $self->throw("Open for write error : $!"));
358 0         0 next;
359             };
360 0 0       0 m/^<#?(.*)/ && do {
361 0 0 0     0 defined($args{$1}) && (open($in, "<", $args{$1}) or $self->throw("Open for read error : $!"));
362 0         0 next;
363             }
364             }
365 0         0 my $dum;
366 0 0       0 $in || ($in = \$dum);
367 0 0       0 $out || ($out = \$self->{'stdout'});
368 0 0       0 $err || ($err = \$self->{'stderr'});
369            
370             # Get program executable
371 0         0 my $exe = $self->executable;
372             # Get command-line options
373 0         0 my $options = $self->_translate_params();
374             # Get file specs sans redirects in correct order
375             my @specs = map {
376 0         0 my $s = $_;
  0         0  
377 0         0 $s =~ s/[^a-zA-Z0-9_]//g;
378 0         0 $s
379             } grep !/[<>]/, @$filespec;
380 0         0 my @files = @args{@specs};
381             # expand arrayrefs
382 0         0 my $l = $#files;
383 0         0 for (0..$l) {
384 0 0       0 splice(@files, $_, 1, @{$files[$_]}) if (ref($files[$_]) eq 'ARRAY');
  0         0  
385             }
386 0 0       0 @files = map { defined $_ ? $_ : () } @files; # squish undefs
  0         0  
387 0         0 my @ipc_args = ( $exe, @$options, @files );
388              
389 0         0 eval {
390 0 0       0 IPC::Run::run(\@ipc_args, $in, $out, $err) or
391             die ("There was a problem running $exe : $!");
392             };
393 0 0       0 if ($@) {
394 0         0 $self->throw("$exe call crashed: $@");
395             }
396              
397             # return arguments as specified on call
398 0         0 return @args;
399             }
400              
401             =head2 stdout()
402              
403             Title : stdout
404             Usage : $fac->stdout()
405             Function: store the output from STDOUT for the run,
406             if no file specified in run_maq()
407             Example :
408             Returns : scalar string
409             Args : on set, new value (a scalar or undef, optional)
410              
411             =cut
412              
413             sub stdout {
414 0     0 1 0 my $self = shift;
415            
416 0 0       0 return $self->{'stdout'} = shift if @_;
417 0         0 return $self->{'stdout'};
418             }
419              
420             =head2 stderr()
421              
422             Title : stderr
423             Usage : $fac->stderr()
424             Function: store the output from STDERR for the run,
425             if no file is specified in run_maq()
426             Example :
427             Returns : scalar string
428             Args : on set, new value (a scalar or undef, optional)
429              
430             =cut
431              
432             sub stderr {
433 0     0 1 0 my $self = shift;
434            
435 0 0       0 return $self->{'stderr'} = shift if @_;
436 0         0 return $self->{'stderr'};
437             }
438              
439              
440              
441             =head1 Bio::Tools::Run::AssemblerBase overrides
442              
443             =head2 _check_sequence_input()
444              
445             No-op.
446              
447             =cut
448              
449             sub _check_sequence_input {
450 0     0   0 return 1;
451             }
452              
453             =head2 _check_optional_quality_input()
454              
455             No-op.
456              
457             =cut
458              
459             sub _check_optional_quality_input {
460 0     0   0 return 1;
461             }
462              
463             =head2 _prepare_input_sequences
464              
465             Convert input fastq and fasta to maq format.
466              
467             =cut
468              
469             sub _prepare_input_sequences {
470              
471 0     0   0 my ($self, @args) = @_;
472 0         0 my (%args, $read1, $read2, $refseq);
473 0 0       0 if (grep /^-/, @args) { # named parms
474 0 0       0 $self->throw("Input args not an even number") unless !(@args % 2);
475 0         0 %args = @args;
476 0         0 ($read1, $refseq, $read2) = @args{qw( -read1 -refseq -read2 )};
477             }
478             else {
479 0         0 ($read1, $refseq, $read2) = @args;
480             }
481             # just handle file input for now...
482 0 0 0     0 $self->throw("maq requires at least one FASTQ read file and one FASTA reference sequence")
483             unless (defined $read1 && defined $refseq);
484 0 0 0     0 $self->throw("File cannot be found")
      0        
      0        
485             unless ( -e $read1 && -e $refseq && (!defined $read2 || -e $read2) );
486              
487             # maq needs its own fasta/fastq format. Use its own converters to
488             # create tempfiles in bfa, bfq format.
489 0         0 my ($ref_h, $ref_file, $rd1_h, $rd1_file, $rd2_h, $rd2_file);
490 0         0 ($ref_h, $ref_file) = $self->io->tempfile( -dir => $self->tempdir() );
491 0         0 ($rd1_h, $rd1_file) = $self->io->tempfile( -dir => $self->tempdir() );
492 0         0 $ref_h->close;
493 0         0 $rd1_h->close;
494 0         0 my $fac = Bio::Tools::Run::Maq->new( -command => 'fasta2bfa' );
495 0         0 $fac->run_maq( -bfa => $ref_file, -fas => $refseq );
496 0         0 $fac->set_parameters( -command => 'fastq2bfq' );
497 0         0 $fac->run_maq( -bfq => $rd1_file, -faq => $read1 );
498 0 0       0 if (defined $read2) {
499 0         0 ($rd2_h, $rd2_file) = $self->io->tempfile( -dir => $self->tempdir() );
500 0         0 $rd2_h->close;
501 0         0 $fac->run_maq( -bfq => $rd2_file, -faq => $read2);
502             }
503 0         0 return ($rd1_file, $ref_file, $rd2_file);
504             }
505              
506             =head2 _collate_subcmd_args()
507              
508             Title : _collate_subcmd_args
509             Usage : $args_hash = $self->_collate_subcmd_args
510             Function: collate parameters and switches into command-specific
511             arg lists for passing to new()
512             Returns : hash of named argument lists
513             Args : [optional] composite cmd prefix (scalar string)
514             [default is 'run']
515              
516             =cut
517              
518             sub _collate_subcmd_args {
519 0     0   0 my $self = shift;
520 0         0 my $cmd = shift;
521 0         0 my %ret;
522             # default command is 'run'
523 0   0     0 $cmd ||= 'run';
524 0         0 my @subcmds = @{$composite_commands{$cmd}};
  0         0  
525 0         0 my %subcmds;
526 0         0 my $cur_options = $self->{'_options'};
527              
528             # collate
529 0         0 foreach my $subcmd (@subcmds) {
530             # find the composite cmd form of the argument in
531             # the current params and switches
532             # e.g., map_max_mismatches
533 0         0 my @params = grep /^${subcmd}_/, @{$$cur_options{'_params'}};
  0         0  
534 0         0 my @switches = grep /^${subcmd}_/, @{$$cur_options{'_switches'}};
  0         0  
535 0         0 $ret{$subcmd} = [];
536             # create an argument list suitable for passing to new() of
537             # the subcommand factory...
538 0         0 foreach my $opt (@params, @switches) {
539 0         0 my $subopt = $opt;
540 0         0 $subopt =~ s/^${subcmd}_//;
541 0 0       0 push(@{$ret{$subcmd}}, '-'.$subopt => $self->$opt) if defined $self->$opt;
  0         0  
542             }
543             }
544 0         0 return \%ret;
545             }
546              
547             =head2 _run()
548              
549             Title : _run
550             Usage : $factory->_run()
551             Function: Run a maq assembly pipeline
552             Returns : depends on call (An assembly file)
553             Args : - single end read file in maq bfq format
554             - reference seq file in maq bfa format
555             - [optional] paired end read file in maq bfq format
556              
557             =cut
558              
559             sub _run {
560 0     0   0 my ($self, $rd1_file, $ref_file, $rd2_file) = @_;
561 0         0 my ($cmd, $filespec, @ipc_args);
562             # Get program executable
563 0         0 my $exe = $self->executable;
564              
565             # treat run() as a separate command and duplicate the component-specific
566             # parameters in the config globals
567              
568             # Setup needed files and filehandles first
569 0         0 my $tdir = $self->tempdir();
570 0         0 my ($maph, $mapf) = $self->io->tempfile( -template => 'mapXXXX', -dir => $tdir ); #map
571 0         0 my ($cnsh, $cnsf) = $self->io->tempfile( -template => 'cnsXXXX', -dir => $tdir ); #consensus
572 0         0 my ($maqh, $maqf) = $self->_prepare_output_file();
573 0         0 my ($nm,$dr,$suf) = fileparse($maqf,".maq");
574 0         0 my $faqf = $dr.$nm.".cns.fastq";
575              
576 0         0 $_->close for ($maph, $cnsh, $maqh);
577              
578             # Get command-line options for the component commands:
579 0         0 my $subcmd_args = $self->_collate_subcmd_args();
580             # map reads to ref seq
581             # set up subcommand options
582            
583             my $maq = Bio::Tools::Run::Maq->new(
584             -command => 'map',
585 0         0 @{$subcmd_args->{map}}
  0         0  
586             );
587 0         0 $maq->run_maq( -map => $mapf, -bfa => $ref_file, -bfq1 => $rd1_file,
588             -bfq2 => $rd2_file );
589             # assemble reads into consensus
590             $maq = Bio::Tools::Run::Maq->new(
591             -command => 'assemble',
592 0         0 @{$subcmd_args->{asm}}
  0         0  
593             );
594 0         0 $maq->run_maq( -cns => $cnsf, -bfa => $ref_file, -map => $mapf );
595             # convert map into plain text
596 0         0 $maq = Bio::Tools::Run::Maq->new(
597             -command => 'mapview'
598             );
599 0         0 $maq->run_maq( -map => $mapf, -txt => $maqf );
600              
601             # convert consensus into plain text fastq
602             $maq = Bio::Tools::Run::Maq->new(
603             -command => 'cns2fq',
604 0         0 @{$subcmd_args->{c2q}}
  0         0  
605             );
606 0         0 $maq->run_maq( -cns => $cnsf, -faq => $faqf );
607            
608 0         0 return ($maqf, $faqf);
609              
610             }
611              
612             =head2 available_parameters()
613              
614             Title : available_parameters
615             Usage : @cmds = $fac->available_commands('commands');
616             Function: Use to browse available commands, params, or switches
617             Returns : array of scalar strings
618             Args : 'commands' : all maq commands
619             'params' : parameters for this object's command
620             'switches' : boolean switches for this object's command
621             'filespec' : the filename spec for this object's command
622             4Geeks : Overrides Bio::ParameterBaseI via
623             Bio::Tools::Run::AssemblerBase
624              
625             =cut
626              
627             sub available_parameters {
628 3     3 1 9 my $self = shift;
629 3         7 my $subset = shift;
630 3         10 for ($subset) { # get commands
631 3 100       11 !defined && do { # delegate
632 1         13 return $self->SUPER::available_parameters($subset);
633             };
634 2 50       13 m/^c/i && do {
635 0         0 return grep !/^run$/, @program_commands;
636             };
637 2 50       9 m/^f/i && do { # get file spec
638 0         0 return @{$command_files{$self->command}};
  0         0  
639             };
640 2         5 do { #else delegate...
641 2         10 return $self->SUPER::available_parameters($subset);
642             };
643             }
644             }
645              
646 0     0 0   sub available_commands { shift->available_parameters('commands') };
647              
648 0     0 0   sub filespec { shift->available_parameters('filespec') };
649            
650             1;