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

With Ovid's tutorial, HTML::Template readme, and help from repson and ichimunki, I've got working code & markup. Yay!

Now I'd like to replace the push @urls sections with a subroutine, to avoid evil copy-and-paste, since the real scripts have several url hashes each.

So I read chapter 8 of The Llama and chapter seven of Elements of Programming with Perl.   Lotsa good info which I pretty much grasp.   But I'm suffering a severe case of flatulo-cephalism on applying this newfound knowledge to minimized code below.  

Two things that are particulary baffling:

  1. how to make vars within the sub unique for each %urlhash
  2. how to feed those values back out to the script and template with unique var names
Looks like it would involve the $_[0], $_[1], etc. elements of @_, and perhaps multiple return values.   Am I on the right track?   As always, any direction, suggestions or examples are appreciated.
    cheers,
    Don
    striving for Perl Adept
    (it's pronounced "why-bick")


(template.pl)
#!/usr/bin/perl -wT use strict; use HTML::Template; use CGI qw(:all); use CGI::Carp qw(fatalsToBrowser); # debugging only - for production +"use CGI::Carp;" use vars qw(@urlsA @urlsB); my $template = HTML::Template->new(filename => "template.tmpl"); $template-> param( servname => $ENV{'SERVER_NAME'}, ); my %urlhashA = ( 'Home' => '/', 'Icons' => '/icons/', 'Sitedocs' => '/doc/', ); my %urlhashB = ( 'Cisco' => 'http://www.cisco.com/', 'CPAN' => 'http://search.cpan.org/', 'Google' => 'http://www.google.com/', 'Perl Monks' => 'http://www.perlmonks.org/', ); while (my ($name,$url) = each %urlhashA) { push @urlsA, {nameA=>$name, urlA=>$url} } $template->param(urlloopA => \@urlsA); while (my ($name,$url) = each %urlhashB) { push @urlsB, {nameB=>$name, urlB=>$url} } $template->param(urlloopB => \@urlsB);
print header, $template->output;


(template.tmpl)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> <TITLE><!-- tmpl_var name=servname --></TITLE> </HEAD> <BODY> <!-- tmpl_loop name="urlloopA" --> <A HREF="<!-- tmpl_var name="urlA" -->"> <B><!-- tmpl_var name="nameA" --></B> </A> &nbsp;&nbsp;&nbsp; <!-- /tmpl_loop --> <P> <!-- tmpl_loop name="urlloopB" --> <A HREF="<!-- tmpl_var name="urlB" -->"> <!-- tmpl_var name="nameB" --> </A> <BR> <!-- /tmpl_loop --> </BODY> </HTML>

Replies are listed 'Best First'.
Re: Got those HTML::Template and subroutine blues
by chipmunk (Parson) on Dec 22, 2000 at 23:15 UTC
    How about something like this?
    my %tmpl_hash = ( urlloopA => { 'Home' => '/', 'Icons' => '/icons/', 'Sitedocs' => '/doc/', }, urlloopB => { 'Cisco' => 'http://www.cisco.com/', 'CPAN' => 'http://search.cpan.org/', 'Google' => 'http://www.google.com/', 'Perl Monks' => 'http://www.perlmonks.org/', }, ); for my $loop (keys %tmpl_hash) { my @vars; while (my($name, $url) = each %{$tmpl_hash{$loop}}) { push @vars, { name => $name, url => $url }; } $template->param($loop, [ @vars ]); }
    with a corresponding change to your template:
    <!-- tmpl_loop name="urlloopA" --> <A HREF="<!-- tmpl_var name="url" -->"> <B><!-- tmpl_var name="name" --></B> </A> &nbsp;&nbsp;&nbsp; <!-- /tmpl_loop --> <P> <!-- tmpl_loop name="urlloopB" --> <A HREF="<!-- tmpl_var name="url" -->"> <!-- tmpl_var name="name" --> </A> <BR> <!-- /tmpl_loop -->
    The separate hashes become a hash of hashes and the separate loops become a nested loop.

    According to the HTML::Template docs, a TMPL_LOOP has its own scope; reusing the same variable names in different loops should work just fine.

      That works like a charm.   chipmunk - you are wise beyond your size.   {grin}

      I oversimplified my script for the post, though.   Was using Tie::IxHash for insertion-order retrieval of hash elements.

      use Tie::IxHash; tie my %urlhashA, "Tie::IxHash"; %urlhashA = ( 'blah' => 'URL', 'bleh' => 'notherURL', 'bloo' => 'ananotherURL', );
      I didn't spot anything in perldoc IxHash.pm about using it with hash o' hashes.  
      tie my %tmpl_hash, "Tie::IxHash"; did nothing noticeable.  
      Attempts to tie urlloop failed as well.

      Is this do-able?

      Update: chipmunk's post below puts a glide in my stride.   8^)   chipmunk++.
          cheers,
          Don
          striving for Perl Adept
          (it's pronounced "why-bick")

        Ah, that makes sense, because you want the HTML output to be in the right order. The tricky thing is that the outer hash and each of the inner hashes must be tied to Tie::IxHash... I'm trying to imagine the code for that, and it's not coming out very pretty. :)

        So, I'll propose an array of arrays solution instead.

        my @tmpl_array = ( urlloopA => [ 'Home' => '/', 'Icons' => '/icons/', 'Sitedocs' => '/doc/', ], urlloopB => [ 'Cisco' => 'http://www.cisco.com/', 'CPAN' => 'http://search.cpan.org/', 'Google' => 'http://www.google.com/', 'Perl Monks' => 'http://www.perlmonks.org/', ], ); for (my $i = 0; $i < $#tmpl_array; $i+=2) { my($loop, $aref) = @tmpl_array[$i, $i+1]; my @vars; for (my $j = 0; $j < $#{$aref}; $j+=2) { my($name, $url) = @{$aref}[$j, $j+1]; push @vars, { name => $name, url => $url }; } $template->param($loop, [ @vars ]); }
        We're sort of simulating the ordered hashes, by having paired elements in each of the arrays. This works because we don't actually need any hash key lookups!

        Update: This code would be used with the same updated template as the hash of hashes suggestion in my earlier reply.

Re: Got those HTML::Template and subroutine blues (tutorial link)
by ybiC (Prior) on Dec 22, 2000 at 22:56 UTC
    Hrm... forgot this link - HTML::Template tutorial.

    Update: using Perl 5.00503, CGI.pm 2.56, and HTML::Template 2.1 in case it matters.
        cheers,
        Don
        striving for Perl Adept
        (it's pronounced "why-bick")