Sign In/My Account | View Cart  
advertisement
-->




   Print.Print
Email.Email article link
The Perl Cookbook, 2nd Edition (cover)

Perl Recipe of the Day

The following recipe is from Perl Cookbook, 2nd Edition, by Tom Christiansen and Nathan Torkington. All links in this recipe point to the online version of the book on the Safari Bookshelf.

Buy it now, or read it online on the Safari Bookshelf.


12.6. Determining the Caller's Package

12.6.3. Discussion

The _ _PACKAGE_ _ symbol returns the package that the code is currently being compiled into. This doesn't interpolate into double-quoted strings:

print "I am in package _ _PACKAGE_ _\n";              # WRONG!
I am in package _ _PACKAGE_ _

Needing to figure out the caller's package arose more often in older code that received as input a string of code to be evaluated, or a filehandle, format, or directory handle name. Consider a call to a hypothetical runit function:

package Alpha;
runit('$line = <TEMP>');

package Beta;
sub runit {
    my $codestr = shift;
    eval $codestr;
    die if $@;
}

Because runit was compiled in a different package than was currently executing, when the eval runs, it acts as though it were passed $Beta::line and Beta::TEMP. The old workaround was to include your caller's package first:

package Beta;
sub runit {
    my $codestr = shift;
    my $hispack = caller;
    eval "package $hispack; $codestr";
    die if $@;
}

That approach works only when $line is a global variable. If it's lexical, that won't help at all. Instead, arrange for runit to accept a reference to a subroutine:

package Alpha;
runit( sub { $line = <TEMP> } );

package Beta;
sub runit {
    my $coderef = shift;
    &$coderef( );
}

This not only works with lexicals, but has the added benefit of checking the code's syntax at compile time, which is a major win.

If all that's being passed in is a filehandle, it's more portable to use the Symbol::qualify function. This function takes a name and package to qualify the name into. If the name needs qualification, it fixes it; otherwise, it's left alone. But that's considerably less efficient than a * prototype.

Here's an example that reads and returns n lines from a filehandle. The function qualifies the handle before working with it.

open (FH, "<", "/etc/termcap")        or die "can't open /etc/termcap: $!";
($a, $b, $c) = nreadline(3, "FH");

use Symbol ( );
use Carp;
sub nreadline {
    my ($count, $handle) = @_;
    my(@retlist,$line);

    croak "count must be > 0" unless $count > 0;
    $handle = Symbol::qualify($handle, (caller( ))[0]);
    croak "need open filehandle" unless defined fileno($handle);

    push(@retlist, $line) while defined($line = <$handle>) && $count--;
    return @retlist;
}

If everyone who called your nreadline function passed the filehandle as a typeglob *FH, as a glob reference *FH, or using FileHandle or IO::Handle objects, you wouldn't need to do this. It's only the possibility of a bare "FH" string that requires qualification.


View the past week's recipes: Today | Yesterday | 3 days ago | 4 days ago | 5 days ago | 6 days ago | A week ago

Sponsored By: