tags:

views:

73

answers:

3

I was curious if using Storable's store_fd and fd_retrieve would allow me to store a data structure into a program's own DATA filehandle. I realize this isn't Best Practice, I'm just curious if it'd work, my quick attempts to try it don't seem to work.

+1  A: 

DATA is a handle to read data stored with the script. Conway's Inline::Files is the only module I know offhand that talks of writable virtual files. And since script files are usually ASCII I don't know what would happen if you got a binary 26 byte on MSDOS or a binary 4 on UNIX in the output of Storable.

However, if you are talking about you storing data by typing it in there, only to read it from a script, then the binary problem still confronts you.

So, it's better to go with YAML or JSON for persistence. I know that YAML will handle the blessing when retrieving the data from DATA.

Axeman
`binmode(__DATA__)` i imagine
Evan Carroll
+2  A: 

I'm not sure why you'd want to do that, but you can fake it. You should try to avoid that though.

Just for giggles, you could open a filehandle, read lines from $0 and print them until you get to __DATA__, then add your new __DATA__ section. The trick is then to rename your new file to become $0, perhaps by an exec if your system locks the file while the program is running:

#!perl

my $mode = (stat($0))[2] & 07777;

open my($fh), '<', $0 or die "I can't open me! $!\n";
open my($new), '>', "$0.new" or die "I can't open you! $!\n";
eval { chmod( $mode, $new ) } or warn "Couldn't set permissions: $@\n";

while( <$fh> )
    {
    last if /^__DATA__$/;
    print { $new } $_;
    }

print "I am $$\n";
print { $new } "__DATA__\n", join '|', $$, time, (stat($0))[1];

rename( "$0.new", $0 )

__DATA__
64574|1265415126|8843292
brian d foy
+1  A: 

It's not possible in ordinary conditions:

$ cat write-data
#! /usr/bin/perl

use warnings;
print DATA "bar!\n";

$ ./write-data
Name "main::DATA" used only once: possible typo at ./write-data line 6.
print() on unopened filehandle DATA at ./write-data line 6.

But you can create extraordinary conditions:

#! /usr/bin/perl

use warnings;
use strict;

use Data::Dumper;
use File::Temp qw/ tempfile /;
use Storable qw/ store_fd fd_retrieve /;

sub store_in_DATA {
  my($data) = @_;

  my($fh,$path) = tempfile;
  unlink $path           or warn "$0: unlink: $!";

  *DATA = $fh;
  store_fd $data, \*DATA or warn "$0: print: $!";

  seek DATA, 0, 0        or warn "$0: seek: $!";
}

store_in_DATA { foo => "There is no spoon.\n" };

undef $/;
my $ref = fd_retrieve \*DATA;
print Dumper $ref;

On Windows, you'll get a warning on the unlink because of its default file-sharing semantics. If that's your platform, you can clean up at END time or use Win32::SharedFileOpen.

Greg Bacon