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

Hi,

saveing hashes to files (and re-load them) is not too difficult,
even if they are nested,
but what if functions is part of this hash?

$h{'sub'} = sub { return "Hello World\n" };
Is there a way to save this (an more complicated) code to a file
and re-load it that it is executable?

Thanks,
Carl

Replies are listed 'Best First'.
(jeffa) Re: save to file: $h{'sub'}=sub{..};
by jeffa (Bishop) on Jul 12, 2003 at 19:15 UTC
    If you are using Perl 5.8 (because you have to use B::Deparse 0.61 or higher), you can also do this with Storable:
    # slightly modified from Storable docs use strict; use warnings; use Safe; use Storable qw(freeze thaw); my $safe = Safe->new(); $safe->permit(qw(:default require)); local $Storable::Deparse = 1; local $Storable::Eval = sub { $safe->reval($_[0]) }; my $serialized = freeze(sub { return 'hello world' }); my $code = thaw($serialized); print $code->(), "\n";

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Re: save to file: $h{'sub'}=sub{..};
by adrianh (Chancellor) on Jul 12, 2003 at 19:05 UTC

    You can use B::Deparse to create a string from a coderef that you can then eval back to the coderef again.

    The latest version of Data::Dumper can do this for you. Take a look at the $Data::Dumper::Deparse switch.

      Wow,

      that was fast,
      thanks,
      Carl

      Hm, well writing a sub to a file works, but how can I use it
      after I've re-read it?

      B::Deparse shows this: eval "sub func $ret". But this doesn't work.
      Either nothing happans or I get a failor, that the sub is not predeclared :-/

      #! /usr/bin/perl # write-read-execute code my %hash = (); # btw, all of a sudden there is a syntax error near: $hash{ # I have no idea why (can't test this, while simular code works?) $hash{'code'} = sub { print "Hi Guy - Hello Fellow!\n" }; &$hash{'code'}(); my $string = toStr($hash{'code'}; $hash{'code'} = toCode( split(/\n/, $string) ); # this should work (as before saved): &$hash{'code'}(); # the two subs sub toStr { use B::Deparse; my $ret .= $deparse->coderef2text( shift )."\n"; $ret .= B::Deparse->new("-p", "-sC")->coderef2text( shift )."\n"; return $ret; } sub toCode { my $ret; while ( @_ ) { $ret .= (shift)."\n"; # "\n" was eliminated by split } # NOW MAKE $ret been executed: # This is the examlpe of B:Deparse: eval "sub func $ret"; # but nothing happens # this causes this mistake: # Undefined subroutine &sub &{$ret}; # this should be given back: return $ret; }
      Am I doing s.th. wrong?
      Thanks,
      Carl
        OOPS, please be aware of two minor bugs in sub toStr,
        here is the corrected code (but all other mistaks are still there):
        #! /usr/bin/perl # write-read-execute code my %hash = (); # btw, all of a sudden there is a syntax error near: $hash{ # I have no idea why (can't test this, while simular code works?) $hash{'code'} = sub { print "Hi Guy - Hello Fellow!\n" }; &$hash{'code'}(); my $string = toStr($hash{'code'}; $hash{'code'} = toCode( split(/\n/, $string) ); # this should work (as before saved): &$hash{'code'}(); # the two subs sub toStr { use B::Deparse; return B::Deparse->new("-p", "-sC")->coderef2text( shift )."\n"; } sub toCode { my $ret; while ( @_ ) { $ret .= (shift)."\n"; # "\n" was eliminated by split } # NOW MAKE $ret been executed: # This is the examlpe of B:Deparse: eval "sub func $ret"; # but nothing happens # this causes this mistake: # Undefined subroutine &sub &{$ret}; # this should be given back: return $ret; }
Re: save to file: $h{'sub'}=sub{..};
by bsb (Priest) on Jul 13, 2003 at 04:39 UTC
    YAML also serializes functions but to a text format.
    Internally it's using B::Deparse as well.