[jifty-devel] Template::Declare Updates

David E. Wheeler david at kineticode.com
Tue Sep 8 12:16:10 EDT 2009

On Sep 7, 2009, at 8:20 PM, Ruslan Zakirov wrote:

>> * Is my documentation for `alias` and `import_templates` correct?

Any comments on this?

>> * Why do we have both `alias` and `import_templates`? The latter
>>   seems superfluous.
> At first I thought that imported templates dispatch relative paths
> differently, but a test showed that it's not true. I can not answer  
> this
> question. I see absence of package variables, some crazy path_for  
> function
> that is broken when a class imported many times and performance
> difference (imported templates are installed at compile-time)

Yes, from a user's point of view, AFAICT, aliases are are exactly like  
imported templates except that you can attach "package variables" do  
them. They look to be slower, too.

Am I missing something? Anyone else have knowledge of this?

>> * What are the `new_buffer_frame()` and `end_buffer_fram()` methods
>>   for? They were not documented, but I see that the catalyst view
>>   uses them.
> The way to catch any output. In some cases it's used to allow code
> inside templates influence output before the current text. For example
> in Jifty's plugin ViewDeclarePage I use it to allow people define
> title and add additional links into head of the page inside templates.

I'll have to have a look at that. I can see how `end_buffer_frame()`  
would be useful for that, but then what's the purpose of  

> As far as I can see Catalyst plugin can avoid using buffers.

At least for now, I'll have to see what you've done with  
ViewDeclarePage to see if there's something worth stealing. ;-)

>> * `package_variables()` had a bug that made it useless. It also was
>>   not previously documented. Should I remove it?
> Don't know.

Perhaps I'll un-document it (it wasn't documented before) and add a  
deprecation warning to it. Thoughts?

>> * What is the `append_attr()` function for, and how does it work?
> Real append_attr is set to a closure when you are inside a tag. So
> calls like attr { foo => 'x' } and foo is 'x' work as expected and
> don't work outside a tag.

Sounds like it shouldn't be documented then, yes?

>> * Can `get_current_attr()` be removed, since it's deprecated?
> Not sure, it can be undocumented.

Yeah, I've done so already.

>> * How does `show_page()` differ from `show()`?
> show_page don't dispatch to private templates. show dispatches via
> show_page if we're not in a template allready, otherwise dispatches to
> any templates including private.

Thanks, I'll add that to the docs.

>> * How are roots supposed to work? They don't seem to be searched
>>   for more packages to load. Why call them roots if it's really
>>   just a list of packages that define templates?
> roots overlay each other. Terminology probably is from mason. A
> template from first root wins.

That makes no sense to me, since roots are package names. What am I  
missing? Oh, wait, do you mean if I have two packages, View::Foo and  
View::Bar, and both are roots (in that order) and both define a  
template named "howdy', then View::Foo::howdy() will be the one  

If so, I'm not sure how that's really useful, since it means that  
View::Bar::howdy will *never* be executed -- unless it's not behind  
View::Foo in some other template configuration, I suppose. But the  
global nature of T::D templates make this seem somewhat unlikely, no?

>> * What is the meaning of paths? Is there one by convention among
>>   Jifty users, perhaps?
> I don't understand the question. Paths are paths, like everywhere.

So I can create template like this:

     template foo => sub { ... }

And like this:

     template "extras/foo" => sub { ... }

The template names are paths, I'm assuming (or at least "extras/" is).  
Semantically, what's the difference between these? Do they have any  
effect on dispatch? Or are they just arbitrary names with no inherent  
meaning to T::D.

I ask because Mason dhandlers and autohandlers definitely impose  
meaning on template paths as far as template resolution goes. But  
AFAIK, no such meaning is imposed by T::D. True?

>> And finally, I have a couple of ideas I'd like to run by the group,
>> for new featuers:
>> * I'd like to add a `move` method. It would work just like
>>   `import_templates`, except that the original template name
>>   would be removed. Basically, it would move all templates in
>>   the named subclass under the given path:
>>     move MyApp::Templates under '/here';
> Can you describe it a little bit more?

Sure. Say you've written this package:

     package View::Foo;
     template howdy => sub { ... };

When you import its template(s) into a path:

     import_templates View::Foo under '/stuff';

Then you can execute the template with either



     show( 'stuff/howdy' );

The only difference with my proposed `move()` method is that you would  
only be able to call the latter of these two names for the template.  
In short, the template would be moved (renamed) from "howdy" to "stuff/ 

>> * I'm thinking of adding a `wrap()` function like `show()` that
>>   would invoke the named wrapper. So if you'd created a wrapper
>>   function using `create_wrapper foo => sub { ... }`, you could
>>   then call it like so:
>>     wrap( foo => show('bar') )
>>   This will allow a (public) wrapper to easily be used in namespaces
>>   outside of which it was defined. Thoughts?
> Real life sexy usage?

Say that I've defined a wrapper in a package:

     use Template::Declare::Tags;

     BEGIN {
         create_wrapper basics => sub {
             my $code;
             html {
                 head { title { 'Welcome' } };
                 body { $code-> };

Currently I can use that wrapper from within View::Root:

     template list => sub {
         my ($self, @items) = @_;
         basics {
             ul {
                 li { $_ } for @items;

But if I define templates in another package, say View::Table, I can't  
use the `basics` wrapper directly, because as it's currently  
implemented, it's simply a subroutine in the View::Root package. I can  
export it using Exporter or Sub::Exporter or similar, but that's  
layering something on top of T::D, eliminating the special meaning of  
the wrapper.

So my thought is to add a new function, like show(), but that wraps,  
like so:

     package View::Table;
     use Template::Declare::Tags;

     template table {
         my ($self, @rows) = @_;
         wrap basics => sub {
             table { ... };

In this way, the View::Table package can use the wrapper even though  
it's defined in View::Root, just as long as both are template roots.  
The wrap function would look something like this:

     sub wrap {
         my ($wrapper_name, $code) = @_;
         my $wrapper = _find_wrapper( $wrapper_name )
             or die "Could not find wrapper $wrapper_name";

So Template::Declare would just have to do some bookkeeping to keep  
track of wrapper functions, just as it currently does for templates.

Does that help?

> As far as I can see Catalyst::View::Template::Declare defines all
> classes in MyApp::View::TD::* namespace as TD roots, dosn't it?


> It's just misuse of the feature and similar to saying "let's alias all
> those classes under /". What makes aliasing and importing useless and
> force you to type full names of your templates all the time.

Exactly. This is why I want to change things so that it looks at  
defines all
classes in MyApp::View::TD::* namespace as TD roots, but moves the  
templates in all but TD::Root to a path named for the package name.  
Does that make sense to you?



More information about the jifty-devel mailing list