eff_i_g has asked for the wisdom of the Perl Monks concerning the following question:

hi everyone; first post here :)

i'm trying to use a module to open files indirectly and export the handle. i'm using perl version ~5.

module:
package MyPackage; use Symbol qw( gensym ); ... sub import { MyPackage->export_to_level(1, @_); } sub open_file { my ($handle, $file) = @_; ${$handle} = gensym(); open *${$handle}, $file || die; import(*${$handle}); # this apparently isn't working? }
the file:
use MyPackage; use strict; ... open_file('LOG', 'log.txt'); while (<$LOG>) { print; } # yields the following: Global symbol "$LOG" requires explicit package name at ./moduletest.pl + line 21. Execution of ./moduletest.pl aborted due to compilation errors.


thanks for any guidance you can provide.

Replies are listed 'Best First'.
Re: modules, exporting, and indirect filehandles
by ikegami (Patriarch) on Aug 09, 2005 at 19:58 UTC

    Since you're using <$LOG> and not <LOG>, you could do the following:

    use strict; use warnings; package MyPackage; sub open_file { my $fh; my $ok; require 5.006; # Require Perl 5.6 # Support both 2 and 3 arg version of open. if (@_ == 1) { $ok = open($fh, $_[0]); } else { $ok = open($fh, $_[0], $_[1]); } die("$!\n") unless $ok; return $fh; } 1;
    use strict; use warnings; use MyPackage; our $LOG = open_file('log.txt'); # 'my' instead of 'our' also works while (<$LOG>) { print; }

    Well, the logic to import open_file is missing, but that's easy. Check Exporter for details. Change open_file to MyPackage::open_file in the .pl until this is resolved.

    Update: If you wanted to use <LOG>, how about:

    use strict; use warnings; package MyPackage; sub open_file { local *fh; my $ok; # Support both 2 and 3 arg version of open. if (@_ == 1) { $ok = open(*fh, $_[0]); } else { require 5.006; # Require Perl 5.6 $ok = open(*fh, $_[0], $_[1]); } die("$!\n") unless $ok; return *fh; } 1;
    use strict; use warnings; use MyPackage; *LOG = open_file('log.txt'); while (<LOG>) { print; }
      thanks. i came up with this based off the chatterbox:

      module:
      sub open_file { my ($mode, $file) = @_; my $fh = gensym(); open $fh, "$mode$file" or croak("could not open '$file': $!"); return \*$fh; }
      file:
      my $LOG = open_file('<','log.txt'); while(<$LOG>) { print; }
      why will this not work?

      open $fh, $mode, $file or croak("could not open '$file': $!");

      which gives:

      Too many arguments for open at MyPackage.pm line 55, near "$file or" BEGIN failed--compilation aborted at ./moduletest.pl line 4.

        It looks fine, and it works for me when I run that. Are you sure you're using the files you think you are using.

        By the way, \* in return \*$fh; is useless. return $fh; will return the same thing.

        Starting with Perl 5.6, open accepts the mode and file name as seperate arguments. It's safer to use the three argument form and concatenating the mode and file name:

        sub open_file { my ($mode, $file) = @_; my $fh = gensym(); open $fh, $mode, $file or croak("could not open '$file': $!"); return $fh; }
        ahhh... it's my version of perl.
Re: modules, exporting, and indirect filehandles
by Transient (Hermit) on Aug 09, 2005 at 19:42 UTC
    open *${$handle}, $file || die;
    will never die unless $file is false. Use or instead of ||. Hopefully that helps a little.