perlhashfunctional-programminggenerative-programming

Write an anonymous sub in Perl to a file for later use


I have a Perl program that generates parsing rules as subs from an input file. The subs are anonymously defined an put into a hash. Now, I want to export that hash, with all the subs and then load them again later to use with a different program.

How do I go about doing this? Is there some way to extract the code of each sub, or can I copy the block of memory that the hash exists in and then cast it as a hash when I load it again later?

Thanks in advance.


Solution

  • From the "Code References" section of the Storable documentation (with added emphasis):

    Since Storable version 2.05, CODE references may be serialized with the help of B::Deparse. To enable this feature, set $Storable::Deparse to a true value. To enable deserialization, $Storable::Eval should be set to a true value. Be aware that deserialization is done through eval, which is dangerous if the Storable file contains malicious data.

    In the demo below, a child process creates the hash of anonymous subs. Then the parent—in an entirely separate process and address space, so it can't see %dispatch—reads the output from freeze in the same way that you might from a file on disk.

    #! /usr/bin/perl
    
    use warnings;
    use strict;
    
    use Storable qw/ freeze thaw /;
    
    my $pid = open my $fh, "-|";
    die "$0: fork: $!" unless defined $pid;
    
    if ($pid == 0) {
      # child process
      my %dispatch = (
        foo => sub { print "Yo!\n" },
        bar => sub { print "Hi!\n" },
        baz => sub { print "Holla!\n" },
      );
    
      local $Storable::Deparse = 1 || $Storable::Deparse;
      binmode STDOUT, ":bytes";
      print freeze \%dispatch;
      exit 0;
    }
    else {
      # parent process
      local $/;
      binmode $fh, ":bytes";
      my $frozen = <$fh>;
    
      local $Storable::Eval = 1 || $Storable::Eval;
      my $d = thaw $frozen;
      $d->{$_}() for keys %$d;
    }
    

    Output:

    Hi!
    Holla!
    Yo!