> As you can see it does this by having a re-delegation block for each of
> the objects that the view has which then looks up the tag's name and
> calls that block. However, it's all rather icky and has all the code in
> Template Toolkit code. Is there any way I can get this logic out of the
> presentation layer?
> 
> I was thinking for something like:
> 
>   [% VIEW(map_function => foo ) %]
> 
> Where foo has been loaded into the stash and is an anonymous subroutine or
> some such that does the calculation mapping the thing between it's being
> asked to present to a block name.  Alternatively (though admittedly I've
> only skimmed the code) the map function could call the stash entry so that
> we can load map with a hash, sub or whatever...
> 
> Though...if anyone has a better suggestion (or even something I've missed)

Mark,

I've been thinking about this too.  Views are a powerful feature,
and some clever improvements to the print mapping function would
make them even better.  Currently the only choices are to map
based on the basic type (LIST, HASH etc) or to do something more
clever via the perl object's present() method (which requires
perl code and blessed objects).

Often a hash contains a single variable (getName in the case of
your XML node) that you want to use as the name of the template
block for presentation of that hash. It would be great if there
were some mapping syntax that allowed you to specify this.

As one example, I added four lines of code to View.pm (see below)
that allows me to implement the recursive Directory view example (see
Template::Plugin::Directory) without using the present() method.
It's not that I have anything against the present method, I'm just
lazy and I would like the view complex structures without additional
perl code support and bless objects.

My map syntax here isn't pretty, but perhaps a mechanism like this could
be the basis of a more flexible map feature.  Here's my complete view
for Directory:

    [% VIEW dirView
        map = {
            'isdir=>1' => 'directory',
            'isdir=>'  => 'file',
        }
        method = 'isdir'
    %]
    [% BLOCK file -%]
         - [% item.name %]
    [% END -%]
    [% BLOCK directory -%]
         * [% item.name %]
    [% FILTER indent; view.print(f) FOREACH f = item.list; END; -%]
    [% END -%]
    [% END -%]

which is used as:

    [% USE dir = Directory("/home/craig", recurse=1) -%]
    [% dirView.print(dir) -%]

My view map says that you should use the directory block if "isdir" is 1,
and use the file block if isdir is empty.  I override the method to use
it as a variable name (for the purposes of this example I didn't want
the Directory's present() method being called).

I also added another four lines to View.pm to support a wild-card type
of map:

    [% VIEW xmlPathView
        map = {
            'getName=>*' => "*",
        }
        method = "getName"
    %]

The value of map{'getName=>*'} has the "*" replaced with the value of
getName in the hash, so you could put extra characters around the "*",
eg:

        map = {
            'getName=>*' => "getName_*",
        }

You can mix both forms: the explicit ones are checked first.  This type
of map should remove the need for your XML_XPath_Node_Element block.

Your perl function mapping example could be implemented by allowing code
references in the map, so:

        map = {
            'HASH' => myCode
        }

would call myCode with the hash, and expect the template name to be
returned.

Disclaimer: although the patch below and my Directory example work,
I dislike the new map syntax.  I would strongly endorse extensions
to the mapping syntax that are elegant and allow, as a test, the
Directory and XML.DOM present() examples to be done purely in TT2.

Craig

--- 2.03a/Template/View.pm     Thu Jun 14 04:40:32 2001
+++ View.pm     Sun Jun 24 21:22:49 2001
@@ -212,6 +212,7 @@
     my $method = $self->{ method };
     my $map = $self->{ map };
     my $output = '';
+    my $newType;
     
     # print each argument
     foreach $item (@_) {
@@ -232,6 +233,13 @@
                return unless defined $present;
                $output .= $present;
                next;                                   ## NEXT
+           }
+           elsif ( defined($newType = $item->{$method}) &&
+                    defined($template = $map->{"$method=>$newType"}) ) {
+           }
+           elsif ( defined($newType = $item->{$method}) &&
+                    defined($template = $map->{"$method=>*"}) ) {
+                $template =~ s/\*/$newType/;
            }
            elsif (! ($template = $map->{ default })) {
                # default not defined, so construct template name from type


Reply via email to