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

Anyone help me to replicate open() and close()?

I want to do something like:

my_open(FILEHANDLE,">$filename"); print FILEHANDLE "This is the file's content"; my_close(FILEHANDLE);
where my_open and my_close would do the exact same as open() and close(), but also do "other stuff" (like logging that the file was opened/closed).

When I run Data::Dumper on a function called in the above manner, it treats the unquoted string 'FILEHANDLE' as a string. I'd *prefer* not to have to use *FILEHANDLE or $FILEHANDLE outside the sub. What happens in the sub doesn't concern me ... I would make it an OBFU if it would work :)

Replies are listed 'Best First'.
Re: Replicate open() and close()
by Ovid (Cardinal) on Jan 29, 2003 at 22:51 UTC

    What you can do is read the source of Fatal.pm. This module replaces function such as open or close with versions that automatically die when they fail. This should give you some ideas.

    You can also use this module to do the following:

    use Fatal qw(:void open close);

    This is useful because any open or close called in void context (such as the examples you provide) will automatically fail.

    You can also check out Function::Override which allows you to add callback to existing functions, which would solve your problem perfectly.

    Cheers,
    Ovid

    New address of my CGI Course.
    Silence is Evil (feel free to copy and distribute widely - note copyright text)

Re: Replicate open() and close()
by chromatic (Archbishop) on Jan 29, 2003 at 22:54 UTC

    Why not write a subroutine?

    sub write_file { my $filename = shift; local *FH; open( FH, "> $filename" ) or die "Cannot open '$filename': $!\n"; log( "Opened '$filename' ); print FH @_; close FH; log( "Closed '$filename' ); }
Re: Replicate open() and close()
by clairudjinn (Beadle) on Jan 30, 2003 at 00:05 UTC
    If you are using perl 5.8.0, you could play around with the overload pragma as well.
    use overload "open" => \&subref; use overload "close" => \&subref;
Re: Replicate open() and close()
by Fletch (Bishop) on Jan 29, 2003 at 22:36 UTC

    See perldoc perlsub, specifically the section entitled Prototypes. If you prototype them with sub my_open (*$) I think it should work the way you want. An alternative might be to use an OO interface and inherit from IO::Handle, just overriding the relevant methods.

      If you prototype them with sub my_open (*$) I think it should work the way you want.

      Close...

      $ perl -le 'print prototype("CORE::open")' *;$@
      -sauoq
      "My two cents aren't worth a dime.";
      
      Thanks Fletch, I should have looked more in the docs .. they even call their example sub 'myopen'!:

      Declared as: sub myopen (*;$)
      Called as: myopen HANDLE, $name

        Declared as: sub myopen (*;$)

        Careful... The example in the docs won't do what you are asking for. It will complain about calling myopen() with 3 arguments. If you want it to act like perl's open(), use the same prototype that perl does. That's *;$@ as I pointed out in my reply to Fletch.

        perl -le 'sub myopen(*;$){print@_}myopen(FOO,"<","bar")' Too many arguments for main::myopen at -e line 1, at end of line Execution of -e aborted due to compilation errors.
        -sauoq
        "My two cents aren't worth a dime.";
        
Re: Replicate open() and close()
by robartes (Priest) on Jan 30, 2003 at 00:00 UTC
    Just to put some of what has been said into code, this uses a form of overriding open:
    #!/usr/local/bin/perl -w use strict; use subs 'open'; no strict 'refs'; sub open (*;$@) { my $file=shift; my $args=shift; print "My_open\n"; # Do whatever you want CORE::open (*{$file}, $args); } open OUTPUT, ">test2.txt"; print OUTPUT "Hi there.\n"; close OUTPUT; __END__ $ perl override.pl My_open $ cat test2.txt Hi there.

    Update: Caveat - the example open in this code is a very naive implementation (handles only two arguments). Beware of dragons.

    CU
    Robartes-

Thanks all! Re: Replicate open() and close()
by BigLug (Chaplain) on Jan 30, 2003 at 00:33 UTC
    Thanks everyone for your quick responses. Basically here's the deal:
    Thanks especially sauoq for the perl -le 'print prototype("CORE::open")' prototype
    Thanks to others for other ideas for overloading the existing open, however that's not the aim. However, it was good to see how to overload such things as open. I might put an optional override in the module.
    Thanks Chromatic for your suggestion of a separate routine, however I'd like to be able to just replace existing open() commands with my_open() commands and have any 'print FILEHANDLE' commands work.

    Once again, thanks everyone for your very quick responses. This really is the most useful community I've ever been a part of.