I am debugging a test in MPEG::Audio::Frame. If I run this test, I get:
$ cpan -g MPEG::Audio::Frame
$ tar zxvf MPEG-Audio-Frame-0.09.tar.gz
$ cd MPEG-Audio-Frame-0.09
$ perl Makefile.PL
$ make
$ perl -I./blib/lib t/04-tie.t
1..5
ok 1 - use MPEG::Audio::Frame;
ok 2 - 'tie' isa 'MPEG::Audio::Frame'
Not a HASH reference at blib/lib/MPEG/Audio/Frame.pm line 273, <DATA> line 1.
# Looks like your test exited with 255 just after 2.
I narrowed down the problem to the following minimal example:
package My::Module;
use feature qw(say);
use strict;
use warnings;
use overload '""' => \&asbin;
sub asbin {
my $self = shift;
$self->{binhead} # $self is not yet a hash, so execution stops here.
}
sub TIEHANDLE {
bless \$_[1], $_[0]
}
sub READLINE {}
sub read {
say "reading..";
my $pkg = shift;
my $fh = shift || 0; # Why is the stringification operator called here?
}
package main;
use feature qw(say);
use strict;
use warnings;
tie *FH, 'My::Module', *DATA;
My::Module->read(\*DATA);
<FH>;
__DATA__
abc
Why is the stringification operator called for the statement My::Module->read(\*DATA) ?
shift || 0 will want to coerce the argument in shift to a scalar. There is no boolify or numify function overloads defined for My::Module, so Perl will use your stringify function.
To avoid evaluating the object in scalar context, you could rephrase it as
my $fh = #_ ? shift : 0;
$fh = shift;
$fh = 0 unless ref($fh) || $fh;
or define a bool function overload.
I have a main setup script which sets up the test env and stores data in some variables:
package main;
use Test::Harness;
our $foo, $xyz, $pqr;
($foo, $xyz, $pqr) = &subroutinesetup();
# ^ here
#test_files = glob "t/*";
print "Executing test #test\n";
runtests(#test_files);
In the test folder I have a testsuite (t/testsuite1.t, testsuite2.t etc.).
How can I access the value of $foo inside the testsuite1.t?
package main;
use Test::More;
$actual = getActual();
is($foo, $actual, passfoor);
# ^ here
done_testing();
Use Storable to store data in first script and retrieve it from other.
main.pl
($foo, $xyz, $pqr) = &subroutinesetup();
store ($foo, "/home/chankey/testsuite.$$") or die "could not store";
system("perl", "testsuite.pl", $$) == 0 or die "error";
testsuite.pl
my $parentpid = shift;
my $ref = retrieve("/home/chankey/testsuite.$parentpid") or die "couldn't retrieve";
print Dumper $ref;
You've received the $foo in $ref. Now use it the way you want.
You can't share a variable directly, because a new Perl process is started for each test file.
As noted in the documentation of Test::Harness, you should switch to TAP::Harness. It's more flexible: for example, it provides the test_args mechanism to pass arguments to test scripts.
$ cat 1.pl
#!/usr/bin/perl
use warnings;
use strict;
use TAP::Harness;
my $harness = 'TAP::Harness'->new({
test_args => [ qw( propagate secret ) ]
});
$harness->runtests('1.t');
__END__
$ cat 1.t
#!/usr/bin/perl
use warnings;
use strict;
use Test::More;
my %args = #ARGV;
is($args{propagate}, 'secret', 'propagated');
done_testing();
I found that the fastest way to dispatch many functions in perl is to use function references.
The remaining problem is, that I have to include the function names in an our ($func1, $func2, ...) list both in the dispatcher and in the function module. I could not fin d any way to include them, like C include would do. Here my code:
Main module:
use strict;
our ($base);
$base = '/home/en/dtest/perl/forditas/utf8/forditas/test1';
require("$base/disph1.pl");
require("$base/fut1h1.pl");
for (my $j = 0; $j < 5; $j++){
dispatch($j);
}
Dispatcher module:
use strict;
our ($base);
require("$base/fut1h1.pl");
our ($sref1, $sref2, $sref3, $sref4, $sref5); # This is what I'd like to include
my %shash = (
'0' => $sref1,
'1' => $sref2,
'2' => $sref3,
'3' => $sref4,
'4' => $sref5,
);
sub dispatch($){
my ($ix) = #_;
my ($a, $b, $c);
$a = 1; $b = 2; $c = 3;
my $ref = $shash{$ix};
&$ref($a,$b, $c);
}
1;
Function module:
use strict;
our ($sref1, $sref2, $sref3, $sref4, $sref5); # This is what I'd like to include
$sref1 = sub($$$) {
my ($a,$b,$c) = #_;
print "sub1 $a,$b,$c\n";
};
$sref2 = sub($$$) { my ($a,$b,$c) = #_; print "sub2 $a, $b, $c\n"; };
$sref3 = sub { print "sub3\n"; };
$sref4 = sub { print "sub4\n"; };
$sref5 = sub { print "sub5\n"; };
1;
This is the result of a run:
$ perl enhufh1.pl
sub1 1,2,3
sub2 1, 2, 3
sub3
sub4
sub5
Thanks in advance for tips.
You really should be using Perl modules - *.pm files - and including them where they are needed with use. Making these modules subclasses of Exporter allows them to export variable and aubroutine names into the calling package.
Take a look at this set of three sources, which also add several improvements on your original code.
Note that you can use the #EXPORT array instead of #EXPORT_OK, in which case the corresponding use statement doesn't have to list the symbols to be imported. However it is better to have the symbols listed at the point of use, otherwise the code for the module has to be inspected to discover exactly what is being imported.
main.pl
use strict;
use warnings;
use lib '/home/en/dtest/perl/forditas/utf8/forditas/test1';
use Dispatcher qw/ dispatch /;
dispatch($_) for 0 .. 4;
/home/en/dtest/perl/forditas/utf8/forditas/test1/Dispatcher.pm
package Dispatcher;
use strict;
use warnings;
require Exporter;
our #ISA = qw/ Exporter /;
our #EXPORT_OK = qw/ dispatch /;
use Utils qw/ sub1 sub2 sub3 sub4 sub5 /;
my #dtable = ( \&sub1, \&sub2, \&sub3, \&sub4, \&sub5 );
sub dispatch {
my ($i) = #_;
my ($a, $b, $c) = (1, 2, 3);
$dtable[$i]($a, $b, $c);
}
1;
/home/en/dtest/perl/forditas/utf8/forditas/test1/Utils.pm
package Utils;
use strict;
use warnings;
require Exporter;
our #ISA = qw/ Exporter /;
our #EXPORT_OK = qw/ sub1 sub2 sub3 sub4 sub5 /;
sub sub1 {
my ($a, $b, $c) = #_;
print "sub1 $a,$b,$c\n";
}
sub sub2 {
my ($a, $b, $c) = #_;
print "sub2 $a, $b, $c\n";
}
sub sub3 {
print "sub3\n";
}
sub sub4 {
print "sub4\n";
}
sub sub5 {
print "sub5\n";
}
1;
output
sub1 1,2,3
sub2 1, 2, 3
sub3
sub4
sub5
First of all mapping integers to elements is a misuse of hash. You might as well use arrays.
Then second, you seem to want to isolate algorithm from implementation, joining them in a main script. While this is admirable, it's clear that the functions module knows something of what it is being used for. Thus while deriving a sort of knowledge graph, the simplest case is that your function module knows the diapatch module.
You can just create a helper function for this purpose:
use strict;
use warnings;
our #EXPORT_OK = qw<setup_dispatch dispatch>;
use parent 'Exporter';
my #dispatch_subs;
sub setup_dispatch { #dispatch_subs = #_; }
sub dispatch {
my ($a, $b, $c) = ( 1, 2, 3 );
return $dispatch_subs[shift()]->( $a, $b, $c );
}
Now your function module can call the setup funciton:
use strict;
use warnings;
use Dispatch ();
Dispatch::setup_dispatch(
# I echo the caution about using prototypes
sub ($$$) {
my ($a,$b,$c) = #_;
print "sub1 $a,$b,$c\n";
}
, sub ($$$) { my ($a,$b,$c) = #_; print "sub2 $a, $b, $c\n"; }
, sub { print "sub3\n"; }
, sub { print "sub4\n"; }
, sub { print "sub5\n"; }
);
And you would just use both of them in the main module like this:
use strict;
use warnings;
require 'plugin_functions.pl';
use Dispatch qw<dispatch>;
...
You really don't need "names" if you just want to use "indexed" generic names. Just put them in a list.
What you need is Exporter.
Within your module:
require Exporter;
#EXPORT = qw($sref1 $sref2 $sref3);
However, it might be worth considering a different design:
Script:
set_dispatch(0,sub{ .... });
Dispatcher Module:
my #dispatch; #If just indexing to numbers, use an array instead of a hash.
sub set_dispatch {
$dispatch[$_[0]] = $_[1];
}
Main module:
for (0..4) #equivalent to before, but more Perlish.
{
dispatch($_);
}
Using a function call to set up the dispatch functions is better than exporting a bunch of variables, to my mind.
I would like to dynamically get a list of either function names (as strings) or function references from any arbitrary Perl module available on my system. This would include modules that may or may not have, e.g., a global #EXPORT_OK array in its namespace. Is such a feat possible? How does one pull it off if so?
Edit: From reading perlmod, I see that %Some::Module:: serves as a symbol table for Some::Module. Is this the correct place to be looking? If so, how can I whittle the table down to just the function names in Some::Module?
You're on the right track. To wittle down the full symbol table to just the subs, something like this can be done (Hat tip "Mastering Perl", ch 8, for main package version of this):
use strict; # need to turn off refs when needed
package X;
sub x {1;};
sub y {1;};
our $y = 1;
our $z = 2;
package main;
foreach my $entry ( keys %X:: ) {
no strict 'refs';
if (defined &{"X::$entry"}) {
print "sub $entry is defined\n" ;
}
}
# OUTPUT
sub y is defined
sub x is defined
You may find this simple script handy:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
# dump of object's symbol table:
foreach my $className (#ARGV)
{
print "symbols in $className:";
eval "require $className";
die "Can't load $className: $#" if $#;
no strict 'refs';
print Dumper(\%{"main::${className}::"});
}
But, if you're doing this in production code, I'd use Package::Stash instead:
my #subs_in_foo = Package::Stash->new('Foo')->list_all_symbols('CODE');
I'm using Perl 5.20. This works on my machine:
use strict;
package foo;
our $some_var;
sub func1 { return 'func1'}
sub func2 { return 'func2'}
package main;
sub callable {
my ($x) = #_;
return defined(&$x);
}
while (my ($k, $v) = each(%foo::)) {
if (callable($v)) {
print("$k\n");
}
}
# output:
# func1
# func2
I'd like to set a variable with a chosen name in another package. How can I do this easily?
Something like:
$variable_name = 'x';
$package::$variable_name = '0';
# now $package::x should be == '0'
You can do that, but you would have to disable strictures like so:
package Test;
package main;
use strict;
my $var_name = 'test';
my $package = 'Test';
no strict 'refs';
${"${package}::$var_name"} = 1;
print $Test::test;
So I'd not recommend that. Better to use a hash.
use 5.010;
use strict;
use warnings;
{
no warnings 'once';
$A::B::C::D = 5; # a test subject
}
my $pkg = 'A::B::C';
my $var = 'D';
# tearing down the walls (no warranty for you):
say eval '$'.$pkg."::$var"; # 5
# tearing down the walls but at least feeling bad about it:
say ${eval '\$'.$pkg."::$var" or die $#}; # 5
# entering your house with a key (but still carrying a bomb):
say ${eval "package $pkg; *$var" or die $#}; # 5
# using `Symbol`:
use Symbol 'qualify_to_ref';
say $${ qualify_to_ref $pkg.'::'.$var }; # 5
# letting us know you plan mild shenanigans
# of all of the methods here, this one is best
{
no strict 'refs';
say ${$pkg.'::'.$var}; # 5
}
and if the following make sense to you, party on:
# with a recursive function:
sub lookup {
#_ == 2 or unshift #_, \%::;
my ($head, $tail) = $_[1] =~ /^([^:]+:*)(.*)$/;
length $tail
? lookup($_[0]{$head}, $tail)
: $_[0]{$head}
}
say ${ lookup $pkg.'::'.$var }; # 5
# as a reduction of the symbol table:
use List::Util 'reduce';
our ($a, $b);
say ${+ reduce {$$a{$b}} \%::, split /(?<=::)/ => $pkg.'::'.$var }; # 5
And of course you can assign to any of these methods instead of saying them.
Given that $variable_name was validated, you could do:
eval "\$package::$variable_name = '0'";