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

My example input file datainput.txt has the following text:
key1 "value1" key2 "value2" key3 "value3"
I have Perl code that would filter that file to look like:
$data_ref = { key1 => "value1", key2 => "value2", key3 => "value3", };
Would it be possible to create a subroutine such that I can call from another Perl script:
my $data_ref = MyModule::filter_and_return_ref('datainput.txt');
Considerations:
Is this possible?

Is this the only way: Write an intermediate filtered file. Then, do 'intermediate.txt'. Followed by returning the data reference. ??

Replies are listed 'Best First'.
Re: Obtain $data_ref from eval'ed input file that was filtered to look like Perl code
by kyle (Abbot) on Aug 05, 2008 at 20:25 UTC

    Have you looked at eval? Have you had a problem using it?

    Update with code:

    use strict; use warnings; use Data::Dumper; sub filter_and_return_ref { my $in = shift; my @lines = split /\n/, $in; for ( @lines ) { s{ \A (\S+) }{$1 =>}xms; $_ .= ','; } unshift @lines, '{'; push @lines, '}'; return eval join q{}, @lines; } my $unfiltered = <<'END_OF_UNFILTERED'; key1 "value1" key2 "value2" key3 "value3" END_OF_UNFILTERED ; my $data_ref = filter_and_return_ref( $unfiltered ); print Dumper $data_ref; __END__ $VAR1 = { 'key2' => 'value2', 'key1' => 'value1', 'key3' => 'value3' };

    If you've not used eval before, heed well this warning: it's compiling and executing whatever string you get it as Perl. As such, if it does not have the structure you think it does, it would be possible for it to do things you don't want (much as if you were using do, as you suggest).

Re: Obtain $data_ref from eval'ed input file that was filtered to look like Perl code
by massa (Hermit) on Aug 05, 2008 at 20:25 UTC
    Quite simple.
    sub filter_and_return_ref($) { my($fn) = @_; open my $f, '<', $fn or return; local $/; local $_ = <$f>; s/\A/{ /; s/\Z/ }/; s/(\S+)\n/ => "$1",\n/g; my $r = eval $_; return if $@; $r || {} }
    Update: missing => added. :-)
    []s, HTH, Massa (κς,πμ,πλ)
Re: Obtain $data_ref from eval'ed input file that was filtered to look like Perl code
by Tanktalus (Canon) on Aug 05, 2008 at 22:24 UTC

    Hmmm... I smell another XY Problem... why filter it? Why not just parse it? If you're worried about those quotes, Text::ParseWords can help. Sounds like you already have most of the parser done, you just need to populate your hash instead of trasnforming it.

    Or, perhaps Config::General would do?

    There really is no need to go to eval STR here. Really.

      Why filter? The proprietary format of the input file is hairy, and I do not have documentation on it. However, filtering it allows me to leverage some consistency of its syntax, without expanding more work than needed.

      Config::General won't cut it. I am aware of Text::ParseWords.

      No, I don't have a full-fledge parser. My filter makes more assumptions than a crafted parser would, but it's good enough for me.
Re: Obtain $data_ref from eval'ed input file that was filtered to look like Perl code
by repellent (Priest) on Aug 05, 2008 at 20:37 UTC
    Ah! It's a Doh! moment for me.

    Just slurp in the filtered file and eval. Thanks, kyle & massa.

    What if the filtered file is massive? { Slurp & eval $slurped } will be less efficient than { write file & do 'file' }, no?

      Probably, but then again if you're at that point then the inefficiency of having that much live data is probably going to be the bigger issue (and you'd want to look at moving instead to something like DB_File or a real database instead of kludging it with a hash in memory.

      (Might also look at having both sides produce something like yaml instead of playing games with filtering and eval (or even filter to YAML rather than Perl and load that instead).)

      The cake is a lie.
      The cake is a lie.
      The cake is a lie.

        Thanks, Fletch. Yes, if the data was that unwieldy, then a database would be the way to go. And then I would have to parse the input file anyway to populate the database.