Discussion:
[jifty-devel] Template::Declare Updates
David E. Wheeler
2009-09-07 21:39:34 UTC
Permalink
Fellow Templaters,

Jesse was foolish enough to give me a commit bit a few days ago, and
I've been going to town on the Template::Declare documentation. See
the [archives][] for what I've been about. A partial overview:

* Various whitespace fixes.
* Documented `alias`. I also updated `t/alias.t` as I read it, trying to
understand how aliasing works.
* Reformatted the POD, moving things around, fixed some broken examples,
and separated example outputs from the scripts that generate them.
* Fixed the TODO utf8 tests. I am not a fan of HTML::Lint.
* Switched from 'Template::Declare' to __PACKAGE__ where possible.
* Documented `import_templates`, updating the tests as I read them to
understand how it worked.
* Fixed a regression in `import_templates` that I discovered while
fooling around with an idea (more below on that idea).
* Made example code and example output indentation consistent.
* Fixed some more bugs in the examples.
* Added a proper SYNOPSIS section to the Template::Declare POD.
* Cleaned up the POD in Template::Declare::Tags,
Template::Declare::TagSet,
and Template::Declare::TagSet::*.
* Re-instated the pod-coverage test, which now passes.

[archives](http://lists.jifty.org/pipermail/jifty-commit/2009-September/subject.html
)

Now, I was doing all this in order to better understand
Template::Declare, towards improving the Catalyst view for it. I have
a few questions, though, and would appreciate some feedback:

* Is my documentation for `alias` and `import_templates` correct?
* Why do we have both `alias` and `import_templates`? The latter
seems superfluous.
* 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.
* `package_variables()` had a bug that made it useless. It also was
not previously documented. Should I remove it?
* What is the `append_attr()` function for, and how does it work?
* Can `get_current_attr()` be removed, since it's deprecated?
* How does `show_page()` differ from `show()`?
* 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?
* What is the meaning of paths? Is there one by convention among
Jifty users, perhaps?

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';

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

Thanks for your thoughts. As I said, I'm doing this all towards
improving the Catalyst view for Template::Declare. Specifically, I'm
looking at using the `move` method to move all the templates defined
in a Catalyst template package under a path. for example, if I have
MyApp::View::TD, and all the templates were under it, there might be:

MyApp::View::TD::Root
MyApp::View::TD::Lookup
MyApp::View::TD::List

My thought is to make it s that the templates in the latter two
packages are moved to be under /lookup/ and /list/, which would make
them better parallel Catalyst controller and action names. Thoughts?

Best,

David
Ruslan Zakirov
2009-09-08 03:20:21 UTC
Permalink
Post by David E. Wheeler
Fellow Templaters,
Jesse was foolish enough to give me a commit bit a few days ago, and
I've been going to town on the Template::Declare documentation. See
* Various whitespace fixes.
* Documented `alias`. I also updated `t/alias.t` as I read it, trying to
  understand how aliasing works.
* Reformatted the POD, moving things around, fixed some broken examples,
  and separated example outputs from the scripts that generate them.
* Fixed the TODO utf8 tests. I am not a fan of HTML::Lint.
* Switched from 'Template::Declare' to __PACKAGE__ where possible.
* Documented `import_templates`, updating the tests as I read them to
  understand how it worked.
* Fixed a regression in `import_templates` that I discovered while
  fooling around with an idea (more below on that idea).
* Made example code and example output indentation consistent.
* Fixed some more bugs in the examples.
* Added a proper SYNOPSIS section to the Template::Declare POD.
* Cleaned up the POD in Template::Declare::Tags,
Template::Declare::TagSet,
  and Template::Declare::TagSet::*.
* Re-instated the pod-coverage test, which now passes.
[archives](http://lists.jifty.org/pipermail/jifty-commit/2009-September/subject.html
)
Now, I was doing all this in order to better understand
Template::Declare, towards improving the Catalyst view for it. I have
* Is my documentation for `alias` and `import_templates` correct?
* 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)
Post by David E. Wheeler
* 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.

As far as I can see Catalyst plugin can avoid using buffers.
Post by David E. Wheeler
* `package_variables()` had a bug that made it useless. It also was
  not previously documented. Should I remove it?
Don't know.
Post by David E. Wheeler
* 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.
Post by David E. Wheeler
* Can `get_current_attr()` be removed, since it's deprecated?
Not sure, it can be undocumented.
Post by David E. Wheeler
* 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.
Post by David E. Wheeler
* 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.
Post by David E. Wheeler
* 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.
Post by David E. Wheeler
And finally, I have a couple of ideas I'd like to run by the group,
* 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
    move MyApp::Templates under '/here';
Can you describe it a little bit more?
Post by David E. Wheeler
* 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
    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?
Post by David E. Wheeler
Thanks for your thoughts. As I said, I'm doing this all towards
improving the Catalyst view for Template::Declare. Specifically, I'm
looking at using the `move` method to move all the templates defined
in a Catalyst template package under a path. for example, if I have
  MyApp::View::TD::Root
  MyApp::View::TD::Lookup
  MyApp::View::TD::List
My thought is to make it s that the templates in the latter two
packages are moved to be under /lookup/ and /list/, which would make
them better parallel Catalyst controller and action names. Thoughts?
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.
Post by David E. Wheeler
Best,
David
_______________________________________________
jifty-devel mailing list
http://lists.jifty.org/cgi-bin/mailman/listinfo/jifty-devel
--
Best regards, Ruslan.
David E. Wheeler
2009-09-08 16:16:10 UTC
Permalink
Post by Ruslan Zakirov
Post by David E. Wheeler
* Is my documentation for `alias` and `import_templates` correct?
Any comments on this?
Post by Ruslan Zakirov
Post by David E. Wheeler
* 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?
Post by Ruslan Zakirov
Post by David E. Wheeler
* 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()`?
Post by Ruslan Zakirov
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. ;-)
Post by Ruslan Zakirov
Post by David E. Wheeler
* `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?
Post by Ruslan Zakirov
Post by David E. Wheeler
* 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?
Post by Ruslan Zakirov
Post by David E. Wheeler
* Can `get_current_attr()` be removed, since it's deprecated?
Not sure, it can be undocumented.
Yeah, I've done so already.
Post by Ruslan Zakirov
Post by David E. Wheeler
* 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.
Post by Ruslan Zakirov
Post by David E. Wheeler
* 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?
Post by Ruslan Zakirov
Post by David E. Wheeler
* 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?
Post by Ruslan Zakirov
Post by David E. Wheeler
And finally, I have a couple of ideas I'd like to run by the group,
* 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
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").
Post by Ruslan Zakirov
Post by David E. Wheeler
* 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
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:

View::Root;
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";
$wrapper->($code);
}

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?
Post by Ruslan Zakirov
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.
Post by Ruslan Zakirov
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?

Best,

David
Ruslan Zakirov
2009-09-08 23:45:25 UTC
Permalink
Post by David E. Wheeler
Post by Ruslan Zakirov
Post by David E. Wheeler
* Is my documentation for `alias` and `import_templates` correct?
Any comments on this?
Post by Ruslan Zakirov
Post by David E. Wheeler
* 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.
Post by David E. Wheeler
Post by Ruslan Zakirov
Post by David E. Wheeler
* 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.
Post by David E. Wheeler
Post by Ruslan Zakirov
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. ;-)
Post by Ruslan Zakirov
Post by David E. Wheeler
* `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.
Post by David E. Wheeler
Post by Ruslan Zakirov
Post by David E. Wheeler
* 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
well.
Post by David E. Wheeler
Post by Ruslan Zakirov
Post by David E. Wheeler
* 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.
Post by David E. Wheeler
Post by Ruslan Zakirov
Post by David E. Wheeler
* 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?
Yes.
Post by David E. Wheeler
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).
Post by David E. Wheeler
Post by Ruslan Zakirov
Post by David E. Wheeler
* 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.
    template foo => sub { ... }
    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.
Post by David E. Wheeler
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.
Post by David E. Wheeler
Post by Ruslan Zakirov
Post by David E. Wheeler
And finally, I have a couple of ideas I'd like to run by the group,
* 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
    move MyApp::Templates under '/here';
Can you describe it a little bit more?
    package View::Foo;
    template howdy => sub { ... };
    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.
Post by David E. Wheeler
Post by Ruslan Zakirov
Post by David E. Wheeler
* 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
    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?
[snip]

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.
Post by David E. Wheeler
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.

[snip]
Post by David E. Wheeler
Does that help?
Doesn't help me, as I said I'm not a big user of those.
Post by David E. Wheeler
Post by Ruslan Zakirov
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.
Post by Ruslan Zakirov
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.
Post by David E. Wheeler
Best,
David
--
Best regards, Ruslan.
David E. Wheeler
2009-09-09 03:45:47 UTC
Permalink
Thanks for taking the time to respond to my missives, Ruslan, greatly
appreciated.
Post by Ruslan Zakirov
Post by David E. Wheeler
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.
Jesse, `svn blame` mostly shows your fingerprints all over both
`alias` and `import_templates`. Care to enlighten me as to why we have
both?
Post by Ruslan Zakirov
Post by David E. Wheeler
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.
Ah, I see. Neither is mentioned in tests, though. I'll have to look at
what you did for Jifty, add some tests, and then document them
properly. They definitely sound useful.
Post by Ruslan Zakirov
Post by David E. Wheeler
Post by Ruslan Zakirov
Post by David E. Wheeler
* `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.
That's what I've done so far, but I'm not sure there's a point to it.
Post by Ruslan Zakirov
Post by David E. Wheeler
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
well.
I can document `append_attr()`, but if it's not for users to users at
all, I think that the documentation should remain commented-out. It's
really private, no?
Post by Ruslan Zakirov
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.
The terminology is bad, frankly. Are these really intended to be used
in user-space? I know that show() dispatches to show_page() as
appropriate, but is show_page() ever used by template authors or tag
set authors?
Post by Ruslan Zakirov
It's unlikely.
It's useful for pluggable applications, for example App::View,
App::Plugin::X::View as roots (reverse order).
Ah, okay, I can see how it'd be useful to use them for plugins and
whatnot. Very good.
Post by Ruslan Zakirov
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.
Sorry, what dispatcher? Is that a Jifty term for a controller? I so,
then yes, I agree.
Post by Ruslan Zakirov
Post by David E. Wheeler
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.
Okay, so paths have no inherent meaning to T::D. I had thought that
was the case, but wanted to be sure, since import_templates() and
alias() specifically affect paths, so I wanted to understand whether
this was important for T::D or merely for users of T::D. And the
answer is the users: I can impose the meaning on paths that I deem
appropriate.
Post by Ruslan Zakirov
Post by David E. Wheeler
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! So paths *do* have inherent meaning! If I'm in /extras, I can't
dispatch to "howdy", but I can dispatch to "/howdy" or /stuff/howdy",
yes?
Post by Ruslan Zakirov
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.
Right, okay.
Post by Ruslan Zakirov
[snip]
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.
Sure. Wrappers were something I added last year, actually; I just want
to have a way to make it easier to execute them in packages other than
where they were defined. I think that's reasonable.
Post by Ruslan Zakirov
Post by David E. Wheeler
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.
How are templates located in other packages if you don't tell T::D
about those packages via the `roots` parameter?
Post by Ruslan Zakirov
Post by David E. Wheeler
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.
I want to fix it, but first I must understand. I'm glad I've asked.
Post by Ruslan Zakirov
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.
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.
Yes, but how does T::D resolve, say, users/preferences, unless you
pass View::Users to `roots`? Does it just automatically know about all
of its subclasses loaded into memory? Such would make it difficult to
have more than one view at once, no?
Post by Ruslan Zakirov
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.
Okay, I'm thinking something like this for Catalyst:

package View::TD::Root;

template index => sub { ... };
template splash => sub { ... };

package View::TD::Users;
template preferences => sub { ... };
import_templates View::TD::Users under '/users';

package View::TD::Widgets;
template preferences => sub { ... };
import_templates View::TD::Widgets under '/widgets';

package View::TD::CRUD;

template create => sub {
my ($self, $c) = @);
my $model = $c->model( $self->package_variable('model') );
};
template show => sub { ... };
template list => { ... };
template edit => { ... };
alias View::TD::CRUD under '/users', { model =>
'Model::CDBI::User' };
alias View::TD::CRUD under '/widgets', { model =>
'Model::CDBI::Widget' };

I think that this is similar to what you've done, only I've called
`alias` after the classes are defined, because otherwise the templates
don't exist yet in those classes. I also used `import_templates` when
I didn't need a package variable.

So does that correspond better with what you mean?

Thanks,

David
Ruslan Zakirov
2009-09-09 04:01:42 UTC
Permalink
Post by David E. Wheeler
Thanks for taking the time to respond to my missives, Ruslan, greatly
appreciated.
Probably it's easier to chat over IRC or jabber:
***@gmail.com, ping me using either.
--
Best regards, Ruslan.
David E. Wheeler
2009-10-06 00:56:38 UTC
Permalink
Post by David E. Wheeler
Post by Ruslan Zakirov
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.
The terminology is bad, frankly. Are these really intended to be used
in user-space? I know that show() dispatches to show_page() as
appropriate, but is show_page() ever used by template authors or tag
set authors?
I've added this:

=head2 show_page

show_page( main => { user => 'Bob' } );

Like C<show()>, but does not dispatch to private templates. It's used
internally by C<show()> when when that method is called from outside a
template class.

I see that there is already a _show_template function, but it's
interface is a bit different. I could create a wrapper named
show_template() around it, so then we'd have the three functions you
mention, but I still think that the names are terrible: you're not
showing a page or a template, but wanting to show *from* a page or
template -- where "page" means outside of a template class, and
"template means inside of a template class. Correct?

If so, I find the terminology confusing. What is a "page"? If it's
anything that's not a template, then maybe it should just be a
non_template? how about

show_from_template() - includes private
show_not_from_template() - excludes private
show() - magic that dispatch to _page or _template

Terrible names, but maybe there's a better terminology we could use
here?

Thanks,

David

David E. Wheeler
2009-10-06 00:49:20 UTC
Permalink
Post by Ruslan Zakirov
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
well.
=head2 append_attr
C<append_attr> is a helper function providing an interface for setting
attributes from within tags. But it's better to use C<attr> or C<is>
to set
your attributes. Nohting to see here, really. Move along.
But again, I left it commented-out, since I it seems that `attr` and
`is` are the ways to set attributes.

Best,

David
Alex Vandiver
2009-09-22 17:45:48 UTC
Permalink
Post by David E. Wheeler
Jesse was foolish enough to give me a commit bit a few days ago, and
I've been going to town on the Template::Declare documentation. See
the archives for what I've been about.
[snip]
you++ for doing all of that.
Post by David E. Wheeler
* What are the `new_buffer_frame()` and `end_buffer_frame()` methods
for? They were not documented, but I see that the catalyst view
uses them.
The buffer stuff is my fault, for better integration with Mason. Buffer
frames are just an abstraction for a stack of stringrefs, the topmost of
which is being appended to. They're provided for backwards
compatability -- future code should interact with
Tedmplate::Declare->buffer, which is a String::BufferStack. I've
updated the documentation accordingly.
- Alex
David E. Wheeler
2009-09-22 21:49:05 UTC
Permalink
Post by Alex Vandiver
you++ for doing all of that.
Thanks. Still planning to get back to it to finish documenting stuff
that Ruslan and I discussed.
Post by Alex Vandiver
Post by David E. Wheeler
* What are the `new_buffer_frame()` and `end_buffer_frame()` methods
for? They were not documented, but I see that the catalyst view
uses them.
The buffer stuff is my fault, for better integration with Mason.
Buffer
frames are just an abstraction for a stack of stringrefs, the
topmost of
which is being appended to. They're provided for backwards
compatability -- future code should interact with
Tedmplate::Declare->buffer, which is a String::BufferStack. I've
updated the documentation accordingly.
Um, there is no buffer method that I can see…

Best,

David
Alex Vandiver
2009-09-23 01:36:11 UTC
Permalink
Post by David E. Wheeler
Um, there is no buffer method that I can see…
It's a class method, defined at the top with mk_classdata. I just
pushed a brief stub documenting it.
- Alex
David E. Wheeler
2009-09-23 16:20:50 UTC
Permalink
Post by Alex Vandiver
Post by David E. Wheeler
Um, there is no buffer method that I can see…
It's a class method, defined at the top with mk_classdata. I just
pushed a brief stub documenting it.
Ah, thanks. Can you show me a piece of code demonstrating what one
might want to use it for?

Thanks,

David
Alex Vandiver
2009-09-23 16:38:54 UTC
Permalink
Post by David E. Wheeler
Ah, thanks. Can you show me a piece of code demonstrating what one
might want to use it for?
You can use it to manipulate the output from TD tags as they are output.
It's used internally to make the tags nest correctly, and be output to
the right place. I can't think of many cases where you'd want or need
to frob it by hand, but it does enable things like the following:

template simple => sub {
html {
head {}
body {
Template::Declare->buffer->set_filter( sub {uc shift} );
p { 'Whee!' }
p { 'Hello, world wide web!' }
Template::Declare->buffer->clear_top if rand() < 0.5;
}
}
};

...which outputs, with equal regularity, either:

<html>
<head></head>
<body>
<P>WHEE!</P>
<P>HELLO, WORLD WIDE WEB!</P>
</body>
</html>

...or:

<html>
<head></head>
<body></body>
</html>

- Alex
David E. Wheeler
2009-09-23 22:28:27 UTC
Permalink
Post by Alex Vandiver
You can use it to manipulate the output from TD tags as they are output.
It's used internally to make the tags nest correctly, and be output to
the right place. I can't think of many cases where you'd want or need
Thanks. I added this paragraph and your example to the docs.

Best,

David
Loading...