[jifty-devel] Template::Declare Updates

Ruslan Zakirov ruslan.zakirov at gmail.com
Tue Sep 8 19:45:25 EDT 2009

On Tue, Sep 8, 2009 at 8:16 PM, David E. Wheeler<david at kineticode.com> wrote:
> 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?

svk annotate may help find responsible person.

>>> * 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
> `new_buffer_frame()`?

You have stream and can open a frame with a filter or frame with a
private buffer that is out of stream.

>> 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?

I think fixing it and making available for the world is fine too.

>>> * 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?

It can be moved to the end of the file and documented like, this is
helper and you should use different syntax to set attributes of the
tags. Undocummenting and comment probably will solve confusion as

>>> * 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.

May be for sake of consistency we should introduce new function
show_template and have the following

show - magic that dispatch to _page or _template
show_page - show exlcuding private
show_template - show including private

That will clear some confusion, I had that too at first.

>>> * 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
> resolved?


> 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?

It's unlikely.

It's useful for pluggable applications, for example App::View,
App::Plugin::X::View as roots (reverse order).

>>> * 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.

No inheritance. Layout your temlates as you like. In Jifty they may
follow URLs completly or you can change the way things dispatched in
dispatcher, for example you have '/user/show' template and in
dispatcher has '/user/*/show' rule that loads the user, set argument
and dispatches to '/user/show' template.

> 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?

True. I think it's better to leave dispatching out of T::D.

>>> 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('howdy');
> Or
>     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/
> howdy").

Either something is broken or you're missing something. You can not
run "howdy" from a template "/xxx" as "howdy" is relative path and
resolves against "/xxx" to "/howdy" that doesn't exist, but you can
run show("howdy") from "/stuff/xxx".

Oh, I've read to the end and now understand. This mess is a result of
using all classes as roots. That's it. See below.

>>> * 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:


I never used wrappers. Actually Jifty don't use wrappers for page
layouts, but instead adds 'page' function that does layouting. May be
it's good to look there.

> 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.

Using roots is wrong here again. In most cases an app has one root and
all other roots are empty and for extending the app.


> Does that help?

Doesn't help me, as I said I'm not a big user of those.

>> As far as I can see Catalyst::View::Template::Declare defines all
>> classes in MyApp::View::TD::* namespace as TD roots, dosn't it?
> Yes.
>> 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?

No, it's just wrong. Jonathan Rockway made mistake that should be fixed.

Once again so it's clear. Roots are as different directories in a file
system that mask each other. Consider CD-ROM that you can read and
change using /flash/drive/cd-rom/xxx/. Files on change placed on flash
drive, but only those that are different.

In application root class may look like this:

package View;

template index => sub {
template splash => sub {

alias View::Users under '/users';

package View::Users;

alias View::CRUD under '', model => 'App::Model::User';

template preferences => sub {...};

package View::CRUD;

template create => sub { my $model = $slef->pv('model') };
template show => sub { ... };
template list => {  ... };
template edit => { ... };

Something like that and only 'View' is root, but everything else
either imported or aliased into root and/or other classes to build
full layout.

Now I see that plenty of problems you try to solve are caused by one
incorrect implemtation decision. Once it's solved, you don't need move
function and things get better.

> Best,
> David

Best regards, Ruslan.

More information about the jifty-devel mailing list