Change of behavior when sorting single hash-based objects

Ivan Tubert-Brohman <[email protected]> Wed, 20 Jun 2012 12:24:34 -0400
Newsgroups gmane.comp.lang.perl.modules.template-toolkit
Message-ID <CA+eQHX1jSLYchbaZaF1g2oNrJrMq6q=8FSp8b-DPBDxcOsDajA@mail.gmail.com>
Hi,

Not sure if this is a bug or a feature, but I noticed that some code
of mine that used Class::DBI and Template broke after upgrading
Template from 2.14 to 2.20 (The same is true for version 2.24).

The problem begins because methods created by Class::DBI for
one-to-many relations between tables return a list of objects.
Sometimes, this is a "list" of a single object.

With 2.14, if I sorted such a list, I got the result I expected for
one-item lists: the same one-item list. With 2.20, I get instead a
sorted list of the keys in the hash underlying the Class::DBI object.

The example below reproduces the issue without having to involve Class::DBI.

What's happening is that, whereas 2.14 used to call the list nsort
method, 2.20 calls the hash nsort method when the "list" is a single
hash-based object.

This can be avoided in the example below if I change "get_list" to
always return an array reference. But doing the same with my old
Class::DBI-based codebase could be trickier. Is there a way within the
template to ensure than only the list nsort method will get called?
For now, my solution has been to revert back to version 2.14.

Cheers,
Ivan


package Foo;
use overload '""' => sub { $_[0]->{n} };

sub new {
    my ($class, $a, $n) = @_;
    bless { a => $a, n => $n}, $class;
}

sub a { $_[0]->{a} }

package main;

use Template;

my $tt = Template->new() or die;

my @list = (
    Foo->new(7, 'alice'),
    Foo->new(2, 'bob'),
    Foo->new(3, 'charlie'),
);

sub get_list { return @list[0 .. $_[0] - 1] }

my $t = "[% FOR i = get_list(len).nsort('a'); i; '\n';  END %]";

print "Test 1: sorting a list of three objects\n";
$tt->process(\$t, { get_list => \&get_list, len => 3 } );

print "\nTest 2: sorting a \"list\" of one object\n";
$tt->process(\$t, { get_list => \&get_list, len => 1 } );

__END__

Output using Template 2.14:

Test 1: sorting a list of three objects
bob
charlie
alice

Test 2: sorting a "list" of one object
alice


Output using Template 2.20:

Test 1: sorting a list of three objects
bob
charlie
alice

Test 2: sorting a "list" of one object
Argument "alice" isn't numeric in numeric comparison (<=>) at
...Template-Toolkit-2.20/blib/lib/Template/VMethods.pm line 355.
n
a