[Templates] Accessing variables which contain period or dot in the name

Andy Wardley abw@wardley.org
Tue, 05 Jun 2007 16:32:36 +0100


Tosh Cooey wrote:
 > So of course you *might* expect it to work like this:
[...]
 > But it doesn't.

Hi Tosh,

Hmmm, yes.  That's strange.

Ah yes.  Now I see.  It *does* work if you do this.

VARIABLES = {
     badguys => {
      'C.I.A' => ['American', 'Dirty'],
      'MI6'   => ['British', '007'],
      'F.S.B' => ['Russian', 'K.G.B.'] }
     },
}

[% FOREACH secret IN badguys.keys %]
     [% FOREACH keyword IN badguys.$secret %]
         [% keyword %]
     [% END %]
[% END %]

The reason is that when you've got a variable that already has a dot
in it, like this:

    badguys.$secret

then the parser turns it into this:

    $stash->get([badguys, 0, $stash->get('secret'), 0]);

When passed a list ref like that, get() treats each pair of elements
as (name, args) (with 0 indicating no args) and all is well.

But when you don't have any dots in a variable, and no args,
like this:

     foo

the parser "optimises" it to this:

     $stash->get('foo');

Rather than

     $stash->get(['foo', 0]);

And if you have this:

     secret = 'C.I.A'
     $secret

Then it gets optimised to this:

     $stash->set(secret => 'C.I.A');
     $stash->get($stash->get('secret'))

Which is the same as:

     $stash->get('C.I.A')

Which the stash then parses into ['C', 0, 'I', 0, 'A', 0]
thinking you meant that dotop sequence all along because you
passed it a string and not a list ref.

So if you define C => { I => { A => [...] } } then you will
see the values coming back, just as if you typed:

     [% C.I.A %]

But that's not what you want :-(

And just to add to the weirdness of it, if you add an argument
to the single variable then it works because the parser no longer
optimises it down:

     $secret(1)

This becomes:

     $stash->get([$stash->get('secret'), [1]]);

And the value gets returned.  In this case, the (1) argument is ignored
so it makes no difference to the outcome.  Other than making it work,
of course.

So yes, I guess it is a bug.  But I'll probably hold off on fixing it until
TT3 given that it's something of an edge case.  And you've got a workaround
(just add an argument), however counter-intuitive it might be!

Incidentally, this works OK:

     badguys.${'C.I.A'}

And this will work in TT3:

     badguys.'C.I.A'

I guess that means this will/should work, too:

     $'C.I.A'

Cheers
A