in reply to Passing a Filehandle that Might be a Bareword

package My::Module; shift; # throw away my own package name our $fh = shift; {...} # check to see it's a good filehandle sub later { print $fh, 'Arbitrary text.'; }; 1;

I think you rather meant:

package My::Module; our $fh; sub import { shift; # throw away my own package name $fh = shift; #{...} # check to see it's a good filehandle } sub later { print $fh 'Arbitrary text.'; } 1;

As for what arguments to allow, I would not go to the trouble of allowing bareword filehandles (STDOUT) or filehandle names as strings ('STDOUT'), but a file name passed as a plain string (use My::Module '/var/foo.log';) might make sense, IMHO, in which case the module would open the corresponding handle.  (You could use ref \$fh in the module's import routine to tell apart...)

Replies are listed 'Best First'.
Re^2: Passing a Filehandle that Might be a Bareword (\*)
by tye (Sage) on May 30, 2010 at 17:23 UTC

    I would encourage passing in via \*STDOUT over *STDOUT. Globs are a type from Perl 4 and look too much like strings. Checking !ref($arg) is much more common than checking "GLOB" eq ref(\$arg) and !ref($arg) needs to be checked anyway in order to deal with lexical file handles and \*STDOUT and *STDOUT{IO}.

    Supporting passing in "STDOUT" gets rather tricky. Consider:

    package Whatever; use My::Logger qw< setLogLevel >; setLogLevel( STDOUT => 1 ); open LOG, '>>', 'some.log' or die; setLogLevel( LOG => 2 );

    My::Logger::setLogLevel() needs to treat 'STDOUT' as *STDOUT (or *main::STDOUT) but must treat 'LOG' as *Whatever::LOG.

    my( $arg )= @_; my $fh; if( ref( $arg ) ) { $fh= $arg; } elsif( "GLOB" eq $arg ) { $fh= \$arg; # or $fh= *{$arg}{IO}; } else { # It is a plain string. If you want to # treat it as the name of a glob, then # you'll need to check for /::|'/ and # prepend caller().'::', unless it is # special like 'STDOUT'. # You'll also need 'no strict;' here. ... }

    - tye        

Re^2: Passing a Filehandle that Might be a Bareword
by Xiong (Hermit) on May 30, 2010 at 16:19 UTC

    The truth is that {...} in my sample code stands in for a multitude of sins. In reality, I loop through @_ looking for one I like, splice it out into a lexical, test it for writability, then stash it in caller's namespace and source filter his code to call a routine in My::Module which grabs $fh from stash, prints to it, and so forth. Deliberately, I'm not showing any of this, including the import sub, which isn't one anyway. Sorry. our $fh was just a shorthand for the wacky stash-and-grab.

    I'll rewrite the example along your improved lines, since none of this has any bearing on the question of what kind of syntax caller is allowed.

    - the lyf so short, the craft so long to lerne -
Re^2: Passing a Filehandle that Might be a Bareword
by Xiong (Hermit) on May 30, 2010 at 16:38 UTC

    At the risk of beating a rotten equine carcass, our $fh doesn't really work nicely no matter what its scope. If the user's code contains two calling modules, each of which use My::Module $fh, there will be a conflict. I'm sure that's obvious. The standard way of dealing with this is like:

    use My::Module; our $tank = My::Module->new($fh);

    ... but since My::Module is actually a fire-and-forget source filter, caller never explicitly does anything with $tank, which should be a package variable anyway. I'm not willing to demand that caller declare $::tank himself according to some prescribed cargo cult code; therefore, I stash-and-grab.

    I promise that all this will make more sense when I get the thing out the door.

    - the lyf so short, the craft so long to lerne -