[Templates] listifying "scalars"

Jess Robinson castaway@desert-island.demon.co.uk
Mon, 20 Nov 2006 20:32:10 +0000 (GMT)


On Mon, 25 Sep 2006, Jess Robinson wrote:

>
> Hi folks,
>
> The 2.15 has an enhancement whereby using .list on a "scalar" should turn it 
> into a list. I quote the word "scalar", because it appears to really mean 
> "simple scalar", i.e. not references, or blessed refs. The docs should 
> probably reflect this.
>
> Anyway, that leaves me with a problem. My sub returns a list of blessed 
> objects, except that when there's only one, TT conveniently de-listifies the 
> result, however since I'd like to access it as a list anyway, I used .list on 
> it, which conveniently turns it into a list of hashrefs with values and 
> keys.. i.e. treats it as a hashref. Code that worked in 2.14, in the 
> SQL::Translator test suite i.e.:
>
> [% table.pkey_fields.join(", ") %]
>
> Now fails to work in 2.15, when the result of pkey_fields is a single 
> object.. Adding .list does not fix this.
>
> Any ideas how to fix this backwards compat problem, or how to make the test 
> suite work with lists of blessed scalars?
>
> Jess

Since nobody appears to want to play this game, I've delved in the fun 
Stash code myself.. after much debugging it appears that:

Calling a sub that returns a list of items is a list iff there is more 
than one item in it, in TT. (This behaviour is used internally and thus I 
guess can't be changed).

Calling "list" or "first" or any other list method on a single blessed 
hashref causes, in the first instance, the hash_list method to be called 
(that only appeared in v2.15, and is already marked as planned to 
disappear again by v3.. what is it for?), and in the second instance, 
.first fails to be called at all, as the old ploy of dropping 
through to try scalar and list ops when no matching method was found has 
been effectively turned off.. Was this on purpose?

The relevant change is this code in Stash.pm:

## under     elsif (ref($root) && UNIVERSAL::can($root, 'can')) {

2.14:

             if (UNIVERSAL::isa($root, 'HASH')
                 && defined($value = $root->{ $item })) {
                 return $value unless ref $value eq 'CODE';      ## RETURN
                 @result = &$value(@$args);
             }

Which drops through if it's hash-based and theres no such value

2.15:

             if (UNIVERSAL::isa($root, 'HASH') ) {
                 if( defined($value = $root->{ $item })) {
                     return $value unless ref $value eq 'CODE'; ## RETURN
                     @result = &$value(@$args);
                 }
                 elsif ($value = $HASH_OPS->{ $item }) {
                     @result = &$value($root, @$args);
                 }
             }
Which doesn't..


So, a) shall I make a test patch that fails, b) patch Stash.pm to fall 
through, or c) go patch the code that seems to rely on an undocumented 
2.14 feature?

Jess