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

Hey Wise ones,

I am pretty new to perl, and I've been through most of the perl man pages many many times, tried many things but am still stuck!

I want to include something from an external file as data I am passing to a subroutine. What I am trying to do is the following:

Read data from files, print the data to another file after formatting etc. And then dump that data that processed data into a subroutine.

I am reading in numbers from several files, and formatting that data into matrices so that I can pass it to the gnuplot subroutine that is part of the Chart::Graph::Gnuplot module.

So for example, My data file might look like the following:

[{ "title" => "line 1", "style" => "lines" , "type" => "matrix"}, [ 1 +, 6318 ], [ 2, 7903 ], [ 3, 25617 ], ] [{ "title" => "line 2", "style" => "lines" , "type" => "matrix"}, [ 1, + 6215 ], [ 2, 7831 ], [ 3, 25782 ],]

and I want to pass that data from the file to my perl script as if it was actually written within the script; like so:

gnuplot({ "title" => "My Trend", "output type" => "png", "output file" => "$TMPDIR/trend-$$.png"}, DATA_FROM_FILE );

Is there a way to do this so that perl thinks that DATA_FROM_FILE points to the contents of the file? Im thinking some sort of reference to a filehandle should work, but I have yet to make it work...

I know in bourne shell you can use back tics to "reference" the output of a command, so for example:

DATA=`cat /tmp/MY_DATA`
so that whenever I use $DATA it appears to the script that whatever cat /tmp/MY_DATA produces, actually looks like part of the script...
Any Ideas? I am beyond stuck!
TIA!
Dave

Replies are listed 'Best First'.
Re: file contents as a part of code?
by GrandFather (Saint) on Aug 17, 2005 at 01:42 UTC

    The simple, but presumably wrong, answer is that the file contents can just be slurped into a string and the string passed to the subroutine. Why is that the wrong answer?

    open infile, "< datafile"; my $str = join "", <infile>; close infile; gnuplot (..., $str);

    Perl is Huffman encoded by design.
      I think that OP want's the contents of the file eval'd .. so, to OP, i would say start with something live the above and simply perldoc -f eval it. Be aware, however, that this can be very dangerous--for example if someone puts malevalent perl code in the file it _will_ get executed.
      open FILEHANDLE, '<', '/tmp/MY_DATA' or die $!; my $str = do { local $/; <FILEHANDLE> }; close FILEHANDLE; gnuplot({ "title" => "My Trend", "output type" => "png", "output file" => "$TMPDIR/trend-$$.png"}, eval($str), );
      (Note: For slurp explaination, see Perl Idioms Explained - my $string = do { local $/; <FILEHANDLE> };)
        You teach one 'do' idiom, but then you skip the other power of 'do' and go the long way around.
        die if not -f '/tmp/MY_DATA'; gnuplot({ "title" => "My Trend", "output type" => "png", "output file" => "$TMPDIR/trend-$$.png"}, do '/tmp/MY_DATA' );
        (Not that this is an endorsement of either approach.)

        --
        [ e d @ h a l l e y . c c ]

Re: file contents as a part of code?
by xdg (Monsignor) on Aug 17, 2005 at 14:35 UTC

    Sounds like what you're trying to do is use one script to generate your data and another to plot it, and you want to be able to save your data to a file in-between. Is that it? If you're manually generating a "Perl-format" data structure and dumping that to a file, you're probably better off using various CPAN modules that help you serialize a Perl data structure and save it to a file. For example, Data::Dumper (and variants like Data::Dump) or YAML. Let's consider an example with YAML;

    use YAML qw( DumpFile ); my @data = ( [ { "title" => "line 1", "style" => "lines" , "type" => "matrix" }, [ 1, 6318 ], [ 2, 7903 ], [ 3, 25617 ], ], [ { "title" => "line 2", "style" => "lines" , "type" => "matrix" }, [ 1, 6215 ], [ 2, 7831 ], [ 3, 25782 ], ], ); DumpFile( "output.txt", @data )

    This produces an output file that looks like this:

    --- #YAML:1.0 - style: lines title: line 1 type: matrix - - 1 - 6318 - - 2 - 7903 - - 3 - 25617 --- #YAML:1.0 - style: lines title: line 2 type: matrix - - 1 - 6215 - - 2 - 7831 - - 3 - 25782

    Loading it back in from inside your other file is just the reverse, and then you can use it however you want:

    use YAML qw( LoadFile ); my @data = LoadFile( "output.txt" ); gnuplot({ "title" => "My Trend", "output type" => "png", "output file" => "$TMPDIR/trend-$$.png"}, @data );

    One advantage of YAML is that it's not Perl code, so you don't run the same "danger" in loading Perl code from a file and running "eval" or just running "do" on the file. (If it's just you using it, it's not much of a risk, but it's a bad habit to get into.)

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.