> -----Original Message-----
> From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] On Behalf Of Jason Gottshall
> Sent: Tuesday, August 02, 2005 4:34 PM
> To: [email protected]
> Subject: RE: [Templates] Re: FOREACH loop help
> 
> I've run into this problem with other 3rd-party object methods that
> return lists instead of arrayrefs; when there's more than one item, TT
> collapses them into an arrayref, which is great. But if there's only one
> item, you just get that item by itself, not in a list. Obviously
> XML::Simple has a nice option for dealing with this issue, but many
> others don't. I solved this problem generically by adding a custom
> function to my variable hash before processing:
> 
>         my %vars = (foo => SomeObject->new());
>         $vars{'as_list'} = sub { return ref($_[0]) eq 'ARRAY' ? shift :
> [ shift ] };
>         $tt->process($file, \%vars);

Probably just an oversight, but I think you probably want something more
like:

    $vars{as_list} = sub {
        if (@_ == 1 && UNIVERSAL::isa($_[0],'ARRAY')) {
            return $_[0];
        }
        else {
            return [EMAIL PROTECTED];
        }
    };

The code you sent will always return an array, but will only return the
first list element instead of all of them.

On second thought, this probably isn't safe at all.  If the function you
wrap normally returns a list of arrayrefs, you'll be unable to tell from
as_list() whether the one arrayref you've been passed is TT2's collapsed
list or the original returned arrayref (if the return value is a list of
only one element).

Consider this example:

    sub dirent_stats {
        my ($dir) = @_;
        my @stats;
        opendir(my $DIR, $dir) || die $!;
        while (my $ent = readdir($DIR)) {
            next if $ent =~ /^\./;
            my @stat = stat("$dir/$ent");
            push(@stats, [$ent, @stat]);
        }
        return @stats;
    }

If you call as_list(dirent_stats("/etc")), as_list will receive an arrayref
as its first and only argument, so that's what it returns.

However, if you call as_list(dirent_stats("/dir_with_only_one_file")),
as_list will ALSO receive an arrayref as its first and only argument.  Since
there was only one return value from dirent_stats, TT2 didn't have to
"promote" it to an array.  But in this case, your template code really wants
it to be wrapped also.

The only reliable way I can see around this is to use a TT2 plugin module
for each Perl module where you need to force some context.  Maybe
Template::Stash::Context could help, too. http://tinyurl.com/8v2pw
(search.cpan.org)

Philip



_______________________________________________
templates mailing list
[email protected]
http://lists.template-toolkit.org/mailman/listinfo/templates

Reply via email to