tags:

views:

395

answers:

5

I have a Perl program that reads in a bunch of data, munges it, and then outputs several different file formats. I'd like to make Perl be one of those formats (in the form of a .pm package) and allow people to use the munged data within their own Perl scripts.

Printing out the data is easy using Data::Dump::pp.

I'd also like to print some helper functions to the resulting package.

What's an easy way to print a multi-line string without variable substitution?

I'd like to be able to do:

print <<EOL;
  sub xyz { 
    my $var = shift;
  }
EOL

But then I'd have to escape all of the $'s.

Is there a simple way to do this? Perhaps I can create an actual sub and have some magic pretty-printer print the contents? The printed code doesn't have to match the input or even be legible.

+31  A: 

Enclose the name of the delimiter in single quotes and interpolation will not occur.

print <<'EOL';
  sub xyz { 
    my $var = shift;
  }
EOL
1800 INFORMATION
No 'accepted' love for the right answer. :(
brian d foy
That's ok I guess I'll have to cry myself to sleep on top of a freakishly large pile of reputation points
1800 INFORMATION
+4  A: 

You could use a templating package like Template::Toolkit or Text::Template.

Or, you could roll your own primitive templating system that looks something like this:

my %vars = qw( foo 1 bar 2 );
Write_Code(\$vars);

sub Write_Code {
    my $vars = shift;

    my $code = <<'END';

    sub baz {
        my $foo = <%foo%>;
        my $bar = <%bar%>;

        return $foo + $bar;
    }

END

    while ( my ($key, $value) = each %$vars ) {
        $code =~ s/<%$key%>/$value/g;
    }

    return $code;
}

This looks nice and simple, but there are various traps and tricks waiting for you if you DIY. Did you notice that I failed to use quotemeta on my key names in the substituion?

I recommend that you use a time-tested templating library, like the ones I mentioned above.

daotoad
+1 for the recommendation to use a template module. Please don't roll your own :-)
Sinan Ünür
+2  A: 

Try writing your code as an actual perl subroutine, then using B::Deparse to get the source code at runtime.

JSBangs
B::Deparse will not properly capture closures, which are more common than one might think. Use Data::Dump::Streamer.
Schwern
@Schwern: B::Deparse does one thing with closures (assume the eval context is correct), Data::Dump::Streamer does another (assume any closed over variables aren't used by anything but the dumped code). Neither could be said to be "not proper".
ysth
If you're creating an actual Perl subroutine, don't stringify it at all. Make it a library. This isn't a game of Mousetrap :)
brian d foy
+2  A: 

Use a data section to store the Perl code:

#!/usr/bin/perl

use strict;
use warnings;

print <DATA>;
#print munged data

__DATA__
package MungedData;

use strict;
use warnings;

sub foo {
    print "foo\n";
}
Chas. Owens
+2  A: 

You can actually continue a string literal on the next line, like this:

my $mail = "Hello!

Blah blah.";

Personally, I find that more readable than heredocs (the <<<EOL thing mentioned elsewhere).

Double quote " interpolates variables, but you can use '. Note you'll need to escape any ' in your string for this to work.

Perl is actually quite rich in convenient things to make things more readable, e.g. other quote-operations. qq and q correspond to " and ' and you can use whatever delimiter makes sense:

my $greeting = qq/Hello there $name!
Nice to meet you/;  # Interpolation

my $url = q|http://perlmonks.org/|;     # No need to escape /

(note how the syntax coloring here didn't quite keep up)

Read perldoc perlop (find in page: "Quote and Quote-like Operators") for more information.

jplindstrom