Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Format and Join an Array in a Template

by mscharrer (Hermit)
on Jun 19, 2009 at 16:03 UTC ( [id://773071]=perlquestion: print w/replies, xml ) Need Help??

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

Hi, I'm trying to generate a file using the Template module. I have an array of names and need to produce a comma separated list where each name appears twice in the format ".$name($name)":
@myarray = qw(A B C D E);
should produce:
.A(A), .B(B), .C(C), .D(D), .E(E)
Please note that the last line does not end in a comma. If the problem with the last trailing comma would not exits I simple could use FOREACH:
[% FOREACH n in names %] .[% n %]([% n %]), [%- END %]
Also I know about the possibility to use .join():
[% names.join(",\n") %]
which does not allow me to use the names twice.

I tried some combinations and checked the manual but could not find a solution yet. Can someone with more experience with Template point me in the right direction?

Thanks

Replies are listed 'Best First'.
Re: Format and Join an Array in a Template
by Your Mother (Archbishop) on Jun 19, 2009 at 17:26 UTC

    TT has some nice meta information included in all loops (size, max, index, count, first, last, prev, next). I think this is much easier to read than the slice stuff-

    [% FOR item IN my_stuff %] .[% item %]([% item %])[% "," UNLESS loop.last %] [% END %]

    You can also bake this stuff into your templates if you want.

    use Template::Stash; $Template::Stash::LIST_OPS->{my_weird_join} = sub { join(",\n", map { "$_.($_)" } @{ +shift || [] }; }; # then... [% my_stuff.my_weird_join %]

    Not tested but looks right.

      Ah, thanks! Both look quite interesting. I will check them out. Template seems to be quite powerful.

        Great. I adore TT and this example goes to the root of why and why I break from the View purists who say TT is a disaster and you should use something like HTML::Template. These simple loop controls can solve many common display logic problems.

        TT can do just about anything. Beware of moving too much into it (it can write files, run macros, run plain Perl, do recursion, etc, etc, etc). If you want a ton of code in templates, Mason is probably the right choice. TT lets you separate and plugin really well though so you can do your own methods and filters, for example, without writing anything but glue code; The Right Way to Do It™. Just another example-

        use warnings; use strict; use Template; use Lingua::EN::Numbers::Ordinate "ordinate"; my %config = ( FILTERS => { ordinal => sub { ordinate($_[0]) }, ordinal_html => sub { my $ord = ordinate($_[0]); $ord =~ s,(\D\D)\z,<sup>$1</sup>,; return $ord; } } ); my $tt2 = Template->new(\%config); $tt2->process(\*DATA, { numbers => [ 0 .. 121 ] }) or die $tt2->error; __DATA__ [% FOR i IN numbers %] Plain: [% i | ordinal %] -- HTML: [% i | ordinal_html %] [%-END %]

        I'd also point you toward Template::Alloy. It's a well behaved implementation of the TT2(3) syntax with a few improvements and supports several other template types. I've used it on my last couple of projects and haven't hit any reasons to go back.

      I now implemented this as follows. I also added alignment of the listed names by calculating the maximum length.

      Is there any possibility to get the indention level of the template code, so that all produced lines are indented the same amount (by adding the number of spaces in join( ))?

      Thanks again.

      Update: I know fixed the indention problem by (re-)adding a join argument:

      use Template::Stash; use List::Util qw(max); $Template::Stash::LIST_OPS->{signal_list} = sub { my $aref = +shift || []; my $sep = shift || "\n "; my $l = max map { length $_ } @$aref; join(",$sep", map { sprintf ".%-${l}s (%-${l}s)", $_, $_ } @$aref) +; };
Re: Format and Join an Array in a Template
by pileofrogs (Priest) on Jun 19, 2009 at 16:49 UTC

    It looks like you want to do the same thing to each item in the list except the last item, right? I think:

    [% FOREACH n in names.slice(0,-2) %] .[% n %]([% n %]), [%- END %] .[% names.last %]([% names.last %])

    Would do what you want. See Template::Manual::VMethods for more. The above is untested, so play around until it actually works.

    Update: s/slice(0,-1)/slice(0,-2)/

      It fails if the list has zero elements. It's getting complicated fast, which is why I didn't post that solution.

      Thanks, this works (with .slice(0,-2)). I was simply thinking the wrong way. The fact that the format must be used twice is a little drawback, but I think it does not get much shorter.

      It is a pity that the Template module does not provide a 'map' virtual method, otherwise a 'list.map(...).join(...)' would be possible.

        The fact that the format must be used twice is a little drawback,

        You could use a [% BLOCK %] to remove the redundancy.

Re: Format and Join an Array in a Template
by si_lence (Deacon) on Jun 19, 2009 at 16:19 UTC
    One way of doing it:
    my @out = join (",\n", (map {".$_($_)"} (@myarray)));
    cheers

    si_lence

      Thanks, but I know the Perl code to do it. I was looking for the Template code which I can use inside a template file.

        oops, misread your question. sorry!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://773071]
Approved by FunkyMonk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (4)
As of 2024-04-19 03:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found