I have a sub that reads a FASTA text file in chunks.
sub reader {
foreach my $line (<IN>) { # read line by line
chomp $line;
if ($line =~ m/^>/) { # if it's a title
&initiator($title, $seq) unless $firsttitle == 1;
$firsttitle = 0;
($title = $line) =~ s/^>//; # title without > at start
$seq = ''; # new seq
} else {
$seq = $seq . $line; # append seq lines
}
}
&initiator($title, $seq); # Do the thing for the last seq.
}
In the middle of several loops, &initiator is called. I'd like to have this in a module that I can "use" but substitute &initiator with other subs from other modules. These subs will need to have their own inputs as well. Would something like the following work or is there a more elegant solution?
use Reader qw(reader);
use Othersub qw(subroutine);
my @par = ('Mary', 'Lamb');
my %functions = (foo => \&Othersub::subroutine);
&reader($file_to_read, $functions{'foo'}($par[0], $par[1]));
Note: Final file structure is Othersub.pm, Reader.pm and the script that uses both modules.
Perl allows you to create references to things, and that includes both subroutines and arrays.
If you've got differing arguments to pass, then I would suggest you want to do so via array reference rather than what you're doing. A bit like this:
use strict;
use warnings;
sub variable_args {
my ( $code_ref, $array_ref ) = @_;
#dereference code ref;
#dereference array ref;
&$code_ref( @$array_ref, "optional", "extra", "arg" );
}
sub foo_func {
foreach (@_) {
print "Foo $_\n";
}
}
sub bar_func {
print "BAR: ", join( ":", @_ ), "\n";
}
#could inline the functions as anonymous subs. I would avoid doing that
#unless they're pretty short/clear.
my %functions = (
'foo' => \&foo_func,
'bar' => \&bar_func,
);
my %args_to_pass = (
'foo' => [ "Mary", "Lamb" ],
'bar' => [ "Some", "Fish", "Pie" ],
);
for my $thing ( "foo", "bar" ) {
variable_args( $functions{$thing}, $args_to_pass{$thing} );
}
Note - in the example above, you call &initiator
. You shouldn't do this. It's deprecated syntax from Perl 4, and is redundant (and may have some undesired consequences in certain scenarios).
But I would suggest doing it this way rather than the way you've got. You could get this to work:
&reader($file_to_read, $functions{'foo'}($par[0], $par[1]));
But what will happen when you try and do that is you'll (potentially) just run your function immediately, and pass it's result into reader
.
E.g.:
variable_args ( &{$functions{'foo'}}("Mary", "Lamb"), ["more stuff"] );
Won't work, because you're 'running' it immediately, and then sending the result - which'll make your $code_ref
whatever the result of the subroutine was.
However you could make an anonymous sub, and pass that:
variable_args( sub {
&{ $functions{'foo'} }( "Special", "Argument", @_ )
},
$args_to_pass{'foo'} );
I would suggest you're getting needlessly convoluted by that point though :)