Skip Menu |

This queue is for tickets about the Template-Toolkit CPAN distribution.

Report information
The Basics
Id: 17503
Status: resolved
Priority: 0/
Queue: Template-Toolkit

People
Owner: Nobody in particular
Requestors: BADGERSRC [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 2.14
Fixed in: (no value)



Subject: Template toolkit FOREACH problem if UNIVERSAL::can is used
Template toolkit fails on processing FOREACH without setting an error if UNIVERSAL::can has been used. In effect, truncated output is returned. use strict; use warnings; use Template; use UNIVERSAL::can; print "\$UNIVERSAL::can::VERSION: $UNIVERSAL::can::VERSION\n"; print "\$Template::VERSION: $Template::VERSION\n"; my $templateText = qq( start size = [% numbers.size %] [% FOREACH number IN numbers %] [% number %] [% END %] end ); my $params = { numbers => [1,2,3] }; my $template = Template->new( {DEBUG => 1 }); $template->process( \$templateText, $params ) or die $template->error; output: $UNIVERSAL::can::VERSION: 1.03 $Template::VERSION: 2.14 start size = 3 comment out "use UNIVERSAL::can" and output is: $UNIVERSAL::can::VERSION: $Template::VERSION: 2.14 start size = 3 1 2 3 end perl is 5.8.7 on debian sarge. My windows box did not demonstrate this problem until UNIVERSAL::can was upgraded from 1.00 to 1.03. The attached patch (against Template::Iterator) seems to clear up the issue. regards, Mark
Subject: template_iterator.diff
--- /usr/lib/perl5/Template/Iterator.pm 2004-10-04 12:27:39.000000000 +0200 +++ /home/perl/lib/perl/5.8.7/Template/Iterator.pm 2006-02-06 13:16:37.000000000 +0100 @@ -54,6 +54,8 @@ use Template::Constants; use Template::Exception; +use Scalar::Util qw(blessed); + $VERSION = sprintf("%d.%02d", q$Revision: 2.65 $ =~ /(\d+)\.(\d+)/); $DEBUG = 0 unless defined $DEBUG; @@ -81,7 +83,7 @@ $data = [ map { { key => $_, value => $data->{ $_ } } } sort keys %$data ]; } - elsif (UNIVERSAL::can($data, 'as_list')) { + elsif (blessed $data && $data->can('as_list')) { $data = $data->as_list(); } elsif (ref $data ne 'ARRAY') {
On Mon Feb 06 07:27:14 2006, BADGERSRC wrote: Show quoted text
> Template toolkit fails on processing FOREACH without setting an error if > UNIVERSAL::can has been used. In effect, truncated output is returned. >
In fact, this seems to be a problem wherever Template toolkit calls UNIVERSAL::can. mark:~/work/migration$ cat template.t use strict; use warnings; use Template; use UNIVERSAL::can; use constant TEMPLATEFILE => q(template.tt); my $template = Template->new(); $template->process( TEMPLATEFILE , {} ) or die $template->error; mark:~/work/migration$ perl template.t mark:~/work/migration$ cat template.tt this is output mark:~/work/migration$ Comment out "use UNIVERSAL::can" and: mark:~/work/migration$ perl template.t this is output This time the fix is in Template::Provider (attached). It is unfortunate that this problem gives silent failure. Mark
--- /home/perl/lib/perl/5.8.7//Template/Provider.pm.dist 2006-02-07 09:34:36.000000000 +0100 +++ /home/perl/lib/perl/5.8.7//Template/Provider.pm 2006-02-07 09:44:59.000000000 +0100 @@ -43,6 +43,7 @@ use Template::Document; use File::Basename; use File::Spec; +use Scalar::Util qw(blessed); $VERSION = sprintf("%d.%02d", q$Revision: 2.81 $ =~ /(\d+)\.(\d+)/); @@ -281,7 +282,7 @@ unshift(@ipaths, @$dpaths); next; } - elsif (UNIVERSAL::can($dir, 'paths')) { + elsif (blessed $dir && $dir->can( 'paths')) { $dpaths = $dir->paths() || return $self->error($dir->error()); unshift(@ipaths, @$dpaths);
CC: undisclosed-recipients: ;
Subject: Re: [rt.cpan.org #17503] Template toolkit FOREACH problem if UNIVERSAL::can is used
Date: Tue, 7 Feb 2006 08:50:52 +0000
To: via RT <bug-Template-Toolkit [...] rt.cpan.org>
From: Andy Wardley <abw [...] wardley.org>
via RT wrote: Show quoted text
> perl is 5.8.7 on debian sarge. My windows box did not demonstrate this > problem until UNIVERSAL::can was upgraded from 1.00 to 1.03.
Perhaps then the problem is in UNIVERSAL::can? A
Subject: Re: [rt.cpan.org #17503] Template toolkit FOREACH problem if UNIVERSAL::can is used
Date: Tue, 7 Feb 2006 09:13:29 +0000 (GMT)
To: bug-Template-Toolkit [...] rt.cpan.org
From: Mark Clements <markdclements [...] yahoo.co.uk>
--- Andy Wardley via RT <bug-Template-Toolkit@rt.cpan.org> wrote: Show quoted text
> via RT wrote:
> > perl is 5.8.7 on debian sarge. My windows box did not demonstrate this > > problem until UNIVERSAL::can was upgraded from 1.00 to 1.03.
> > Perhaps then the problem is in UNIVERSAL::can?
Sure, but then perhaps it isn't. I started off by posting the bug against the UNIVERSAL-can queue, but then a bit of experimentation seemed to indicate that the problem lay with TT. I don't pretend to be an expert with either package so I've posted the bug in the hope that those who know better can take a look at it. UNIVERSAL::can is used by Test::MockObject, which is why I have encountered the problem, although I am not mocking objects being passed to TT or TT objects themselves. regards, Mark
CC: undisclosed-recipients: ;
Subject: Re: [rt.cpan.org #17503] Template toolkit FOREACH problem if UNIVERSAL::can is used
Date: Tue, 7 Feb 2006 10:17:37 +0000
To: "markdclements [...] yahoo.co.uk via RT" <bug-Template-Toolkit [...] rt.cpan.org>
From: Andy Wardley <abw [...] wardley.org>
markdclements@yahoo.co.uk via RT wrote: Show quoted text
> but then a bit of experimentation seemed to indicate that the problem > lay with TT.
Hi Mark, Looking at the docs for UNIVERSAL::can, it advertises itself as: "Hack around people calling UNIVERSAL::can() as a function" In other words, it deliberately breaks an advertised and totally standard usage of the core Perl UNIVERSAL::can subroutine. :-( While I agree with some of the reasoning behind it (as expressed in the UNIVERSAL::can docs) it doesn't change the fact that it breaks a core Perl function, and deliberately too. The UNIVERSAL::can() call is used in many places in TT and in some of those places it absolutely has to work as advertised in the Perl core and not in any other way. TT often has to work at the lower levels of Perl in order to grok things about your variables, etc., in order to "Do The Right Thing" for dotop magic. In these cases, having an external CPAN module second-guessing what it thinks we should have written is just plain wrong and breaks TT in ways that can't be fixed by simply using Scalar::Utils and the blessed method. For example, in Template::Stash we have to code explicitly for the CGI module which doesn't Do The Right Thing in terms of implementing can(). We could tell Lincoln to go fix his module (and get all the people using CGI to upgrade), or we could no longer support the CGI module in TT (and get all the people using it to find something else), but both of these are going to make us many enemies :-) So in summary, I'm fairly certain that TT absolutely depends upon the original and unmodified behaviour of UNIVERSAL::can in order to work with the modules that are really out there, and not some idealised OO vision about how modules should be written (which I generally agree with all the same). However, I am glad you brought it to my attention because there are places in TT where those function calls really should be method calls. I'm in the (ongoing) process of writing version 3 of TT and I'll consider these matters more carefully now that I'm aware of them. So thanks for taking the time to investigate the issue and file the bug report, but I'm afraid the only way I can resolve this one for TT2 is to say "Don't use UNIVERSAL::can". Cheers Andy
Subject: Re: [rt.cpan.org #17503] Template toolkit FOREACH problem if UNIVERSAL::can is used
Date: Tue, 7 Feb 2006 10:43:53 +0000 (GMT)
To: bug-Template-Toolkit [...] rt.cpan.org
From: Mark Clements <markdclements [...] yahoo.co.uk>
--- Andy Wardley via RT <bug-Template-Toolkit@rt.cpan.org> wrote: Show quoted text
> So thanks for taking the time to investigate the issue and file the bug > report, but I'm afraid the only way I can resolve this one for TT2 is to > say "Don't use UNIVERSAL::can".
OK - thanks for taking the time to explain this. I understand your reasoning. Unfortunately the net result for the time being is that Test::MockObject won't play nice with TT. There are other mockers, but TT and Test::MockObject are both mainstream modules and in an ideal world would work together. I may reopen the bug in UNIVERSAL-can or possibly create a new one in Test::MockObject. thanks again, Mark
On Tue Feb 07 05:18:55 2006, abw@wardley.org wrote: Show quoted text
> Looking at the docs for UNIVERSAL::can, it advertises itself as: > > "Hack around people calling UNIVERSAL::can() as a function" > > In other words, it deliberately breaks an advertised and totally > standard usage of the core Perl UNIVERSAL::can subroutine. :-(
This is incorrect. Please see the documentation for UNIVERSAL in Perl 5.8.8. Show quoted text
> For example, in Template::Stash we have to code explicitly for the CGI > module which doesn't Do The Right Thing in terms of implementing can(). > We could tell Lincoln to go fix his module (and get all the people using > CGI to upgrade), or we could no longer support the CGI module in TT (and > get all the people using it to find something else), but both of these > are going to make us many enemies :-)
Lincoln's code has a bug. Trying to work around that bug by using UNIVERSAL::can as a function *breaks* (Test::MockObject). Mark has provided me a test case and I'll do my best to make UNIVERSAL::can do the right thing, but I prefer to fix bugs, not patch over them.
On Wed Feb 08 14:42:48 2006, CHROMATIC wrote: Show quoted text
> > In other words, it deliberately breaks an advertised and totally > > standard usage of the core Perl UNIVERSAL::can subroutine. :-(
> > This is incorrect. Please see the documentation for UNIVERSAL in Perl > 5.8.8.
Not sure why RT has been opened this again... The documentation states: "can" can be called as a class (static) method, an object method, or a function. I'm calling it as a function. Unless I'm missing something, that's a documented and standard use of UNIVERSAL::can. I can understand why you might want to change UNIVERSAL::can, but then it becomes something different from what Perl normally does and I'm relying on that behaviour. So as I see it, using the UNIVERSAL::can module breaks TT (rather than the other way round) because U::C is changing the documentated behaviour of a core Perl module.