Subject: | coderef iterator off-by-one |
HTML-Tabulate-0.31
This is perl, v5.8.8 built for i486-linux-gnu-thread-multi
Linux gibson2 2.6.18-6-486 #1 Mon Oct 13 15:35:23 UTC 2008 i686 GNU/Linux
Debian Etch
I believe there is an off-by-one bug when using generic coderef iterators with
HTML::Tabulate.
In the code to grab the column headers, HTML::Tabulate does this:
if (ref $set eq 'CODE') {
my $row = $set->();
$self->{prefetch} = $row;
$defn->{fields} = [ sort keys %$row ] if eval { keys %$row };
}
... saving the first row in $self->{prefetch}, while sub data_iterator does this:
if (ref $set eq 'CODE') {
return $set;
}
This throws away the prefetched row. For other set types, data_iterator checks for a
prefetched first row:
elsif (UNIVERSAL::isa($set,'UNIVERSAL') &&
$set->can('First') && $set->can('Next')) {
return sub {
$row = $row ? $set->Next : ($self->{prefetch} || $set->First);
};
}
... so I believe the code in data_iterator should be:
if (ref $set eq 'CODE') {
return sub {
$row = $row ? $set->() : ($self->{prefetch} || $set->());
};
}
That way it should return all the rows whether there is a prefetched first row or not.
With the code as it is, if I hand HTML::Tabulate v0.31 this iterator:
my $counter = 1;
$iter = sub {
if ( $counter > 5 ) {
return undef;
} else {
return { counter => $counter++ }
}
};
... it gives me HTML that looks like:
counter
2
3
4
5
I made the change above on my local copy and it gives me:
counter
1
2
3
4
5
... which is what I was expecting.
Perhaps I've missed the point of the coderef iterator option, but to me it looks like it's off by
one because it throws away the prefetched first row.
Cheers,
Dave Giller
dave@pdx.net