http://qs1969.pair.com?node_id=666473

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

Hello Monks!

After a long hiatus from the site, I'm back again :)

I've been toying with a side pet project for publishing HTML files. What I'm trying to achieve is similar to what ActionView, and other templating tools do.

In publish.pl, let's say I have a subroutine 'layout' that has local variables $headline, $body, $url. Within this sub, I'd like to call another script 'article.layout.pl', but with the local variables $headline, $body, and $url available to the script. 'article.layout.pl' would then use these variables to print out the final layout.

In publish.pl

sub layout { ... my ($headline, $body, $url); ... # call article.layout.pl ??? article.layout.pl {$headline, $body, $url}; }

In article.layout.pl

print <<HEADER ... HEADER print $title; print $body; print $url; print <<FOOTER ... FOOTER

I realize I could use TemplateTookit to achieve this, but I was hoping to learn how to call mess with perl scoping in general.

Thanks fellow monks! It's good to be back.

Replies are listed 'Best First'.
Re: Injecting local variables into a template
by hipowls (Curate) on Feb 06, 2008 at 05:45 UTC

    You could look to see how Template::Stash does it. Besides the POD there are comments in the code describing how each function works.

Re: Injecting local variables into a template
by ikegami (Patriarch) on Feb 06, 2008 at 06:53 UTC

    For starters, your my usage is wrong.
    my $headline, $body, $url;
    means
    (my $headline), $body, $url;
    but you want
    my ($headline, $body, $url);

    The solution requiring minial change is,

    # publish.pl sub layout { local our ($headline, $body, $url) = @_; do 'article.layout.pl'; } layout($headline, $body, $url);
    # article.layout.pl our ($headline, $body, $url); print("$headline, $body, $url\n");

    Update: Just to be clear, I recommend against using my solution (and wfsp's). I think you're going to spend way more time avoiding using a real template system than actually switching over. The sooner you switch, the easier and quicker it will be. My solution is a quick fix in case you already have your "templates" written that way and this needs to be done "yesterday". Otherwise, I think switching to a templating system would be faster, even in the short run.

Re: Injecting local variables into a template
by wfsp (Abbot) on Feb 06, 2008 at 06:13 UTC
    One way is to put your sub into a module and import the sub into your script. See Simple Module Tutorial for more information.
    #!/bin/perl5 use strict; use warnings; use lib qw{local/lib}; use Article qw{article_layout}; layout(); sub layout { #... my ($headline, $body, $url) = qw{one two three}; article_layout($headline, $body, $url); }
    package Article; use strict; use warnings; use Exporter; use vars qw($VERSION @ISA @EXPORT_OK); $VERSION = 1.00; @ISA = qw(Exporter); @EXPORT_OK = qw(article_layout); sub say { print qq{$_[0]\n}; } sub article_layout { my ($title, $body, $url) = @_; print <<HEADER; header stuff HEADER say $title; say $body; say $url; print <<FOOTER; footer stuff FOOTER } 1;
    output:
    header stuff one two three footer stuff