views:

289

answers:

3

Some time ago, I ask a question: How do I redefine built in Perl functions?

And the answers have served me well. I have a package that overrides Perl's 'open' function enabling me to log file access.

Now I've come to a case that breaks the functionality of the original code.

use strict;
use warnings;
use Data::Dumper;

sub myopen (*;@) {
  my $p;
  my $retval = CORE::open($p, $_[1]);
  {
    no strict;
    *{"main::$_[0]"} = $p;
  }
  return $retval;
}

BEGIN {
  *CORE::GLOBAL::open = *myopen;
};

my @a = (1, 2, 3);

open(CHECK, ">dump") or print "UNABLE TO OPEN DUMPER FILE: $!\n";
print CHECK "test\n";
print CHECK Data::Dumper->Dump(\@a);
close CHECK

Now I get this message: Can't locate object method "CHECK" via package "Data::Dumper"

How do I fix it?

+1  A: 

Compare:

> perl -MData::Dumper -e'local*_=*STDOUT;print _ Data::Dumper->Dump([2]);'
Can't locate object method "_" via package "Data::Dumper" at -e line 1.

to

> perl -MData::Dumper -e'local*_=*STDOUT;print _ ( Data::Dumper->Dump([2]) );'
$VAR1 = 2;

I used a different name from "STDOUT" because it seems to only gets the indirect object wrong when it's not a built-in handle.

Anonymous
+8  A: 

Try using a name other than "CHECK".

"CHECK" is a special function which is called during compile time, and you really shouldn't use it.

$ open CHECK , '<', 'foo.txt'; 
Took 0.00224494934082031 seconds.

Runtime error: Undefined subroutine &Devel::REPL::Plugin::Packages::DefaultScratchpad::CHECK called at (eval 329) line 5.

$ open CHECKS , '<', 'foo.txt'; 
Took 0.00155806541442871 seconds.

$

Why that specific error?

perl -MO=Deparse -e 'print CHECK Data::Dumper 1';
print 'Data::Dumper'->CHECK(1);

Also, you're using global file handles, which are problematic.

use this notation:

open my $fh, '<' , $foo ; 
print <$fh>;
close $fh;

These are extra beneficial is they self-close when they go out of scope.

Kent Fredric
+1, nice analysis of the problem and you proposed the right solution (open()'s saner 3-arg syntax, with the filehandle in a lexical variable). And, I HATE PERL FOR THINGS LIKE THIS.
j_random_hacker
@j_random_hacker: Using PerlCritic will bring some Perl love back ;-)
draegtun
@draegtun: Perl::Critic looks interesting (though I fear what it will say about my large codebase of old, old code... :) )
j_random_hacker
+1  A: 

This will work and without producing the error...

 print {*CHECK} Data::Dumper->Dump(\@a);

This stops it being confused has an "Indirect Object Syntax"

However I do recommend steering clear of using CHECK and other special named code blocks in Perl and using lexical variables for filehandles is the preferred method. PBP

/I3az/

draegtun