views:

154

answers:

2

I know this type of thing I want to do used to work in 5.8. Am I doing something wrong? Is there a way to get back there in Perl 5.10?

Here's the module:

package TableMod;
use base qw<Exporter>;
our @EXPORT_OK = qw<mod_table>;

use Data::Dumper;
sub mod_table (\%@) { print Dumper( @_ ); }

1;

And here is the script:

use strict;
use warnings;
use Data::Dumper;
use Test::More tests => 4;

sub mod_table_here (\%@) { 
    print Dumper( @_ );
}

use_ok( 'TableMod', 'mod_table' );
can_ok( __PACKAGE__, 'mod_table' );
is( prototype( \&mod_table_here ), '\\%@'
  , q/prototype( \&mod_table_here ) = '\%@'/ 
  );
is( prototype( \&mod_table ), prototype( \&mod_table_here )
   , 'prototypes ARE the SAME!' 
   );
my %table = qw<One 1>;
mod_table_here %table => ( 1, 2, 3, 4 );
#mod_table %table => ( 1, 2, 3, 4 );
mod_table( %table, 1, 2, 3, 4 );

All I have to do is uncomment the next to last line and I get:

Useless use of modulus (%) in void context at - line 17.
Useless use of a constant in void context at - line 17.
Useless use of a constant in void context at - line 17.
Useless use of a constant in void context at - line 17.
Bareword "mod_table" not allowed while "strict subs" in use at - line 17.

It doesn't complain about the local sub, but it loses its mind over the imported one. On top of that despite the tests telling me that I've imported 'mod_table', strict is now confused that it is a bareword!

Not only that but despite the tests telling me that the prototypes are the same, I can't pass %table as a hashref to the imported sub. Not even if I use the conventional syntax, shown in the last line.

What I get is:

1..4
ok 1 - use TableMod;
ok 2 - main->can('mod_table')
ok 3 - prototype( \&mod_table_here ) = '\%@'
ok 4 - prototypes ARE the SAME!
$VAR1 = {
          'One' => '1'
        };
$VAR2 = 1;
$VAR3 = 2;
$VAR4 = 3;
$VAR5 = 4;
$VAR1 = 'One';
$VAR2 = '1';
$VAR3 = 1;
$VAR4 = 2;
$VAR5 = 3;
$VAR6 = 4;
+10  A: 

Its because use_ok is being called at run-time. If you add the following then it all works fine:

 use TableMod 'mod_table';

I normally only keep a single test file with use_ok in (normally 00-load.t or 00-use.t). I think Ovid may have written a blog post about this being a good practice?

Update: Found Ovid's blog post I was referring to.

/I3az/

draegtun
I can't believe I never tried `use` alone. Thanks.
Axeman
It's not the use_ok() that comes with 5.10.*, it's a problem with use_ok() in all versions. If you don't load the module before Perl has to parse the rest of the source, you don't get the benefit of prototypes or imports.
brian d foy
@brian - Absolutely correct. When I did a quick test with 5.8.8 the OP code did work, but I can't repeat that now so clearly I'd mucked something up while doing it ;-( I've amended answer accordingly.
draegtun
+7  A: 

This is the expected result. The use_ok call is at run-time, so the mod_table sub is only compiled and imported after the "call" to it is encountered during compilation, so the "call" to mod_table is interpreted as an illegal bareword.

This code produces the same warnings/error, both on 5.8 and 5.10.

perl -e'use strict; use warnings; my %table; mod_table %table => (1,2,3,4)'

Because the lack of compile-time import can affect the compiled test code in ways like this, it's a good idea to use use instead of use_ok in all tests except a test dedicated to just doing the use_ok (potentially with a BAIL_OUT). (Putting the use_ok in a BEGIN block alleviates these kind of problems but can cause other problems, so isn't a good idea.)

ysth