[Jifty-commit] r7567 - in Template-Declare/trunk: . lib/Template t

Jifty commits jifty-commit at lists.jifty.org
Fri Oct 16 16:42:37 EDT 2009


Author: theory
Date: Fri Oct 16 16:42:36 2009
New Revision: 7567

Added:
   Template-Declare/trunk/t/composition.t
      - copied unchanged from r7566, /Template-Declare/branches/mixmaster/t/composition.t
   Template-Declare/trunk/t/deep_mixing.t
      - copied unchanged from r7566, /Template-Declare/branches/mixmaster/t/deep_mixing.t
   Template-Declare/trunk/t/mixing.t
      - copied unchanged from r7566, /Template-Declare/branches/mixmaster/t/mixing.t
   Template-Declare/trunk/t/pod-spelling.t
      - copied unchanged from r7566, /Template-Declare/branches/mixmaster/t/pod-spelling.t
   Template-Declare/trunk/t/relative-mixing.t
      - copied unchanged from r7566, /Template-Declare/branches/mixmaster/t/relative-mixing.t
Modified:
   Template-Declare/trunk/   (props changed)
   Template-Declare/trunk/Changes
   Template-Declare/trunk/MANIFEST.SKIP
   Template-Declare/trunk/lib/Template/Declare.pm
   Template-Declare/trunk/lib/Template/Declare/TagSet.pm
   Template-Declare/trunk/lib/Template/Declare/Tags.pm
   Template-Declare/trunk/t/aliasing.t
   Template-Declare/trunk/t/dispatch_order.t
   Template-Declare/trunk/t/importing.t
   Template-Declare/trunk/t/smart_tag_wrapper.t

Log:
Merged from mixmaster. That branch is now defunct.

Modified: Template-Declare/trunk/Changes
==============================================================================
--- Template-Declare/trunk/Changes	(original)
+++ Template-Declare/trunk/Changes	Fri Oct 16 16:42:36 2009
@@ -1,12 +1,20 @@
 0.41
-* Documented aliasing and template importing (mixins).
-* Reworked all the documentation, neatening things, fixing bugs in the
-  examples, and adding missing docs for various functions and methods.
+* Reworked all the documentation, neatening things, expanding the "USAGE"
+  section, fixing bugs in the examples, and adding missing docs for various
+  functions and methods.
 * Added "dispatch_to" to replace "roots", which is now deprecated. Note that
   "dispatch_to" resolves to template classes in the opposite order to "roots".
   This won't be an issue if you only use a single temlate class.
-* Deprecated "path_for()", since it only works for the last class into which a
-  template is imported.
+* Converted the implementation of "alias" to be the same as that used for
+  "import_templates", which is much more efficient.
+* Added the "into" parameter to "alias" and "import_templates".
+* Added the "setting" syntactical sugar keyword for use with "alias".
+* Renamed "import_templates" to "mix". The former is still around, but is
+  deprecated.
+* Added support for package variables with "mix".
+* Deprecated the undocumented "aliases()" and "alias_metadata()" methods, as
+  they are no longer needed. They're now no-ops that issue warnings. To be
+  removed altogether in a future version.
 
 0.40_01 2009-08-12
 * Support for inline tagset definitions. Thanks to Olivier 'dolmen' Mengué

Modified: Template-Declare/trunk/MANIFEST.SKIP
==============================================================================
--- Template-Declare/trunk/MANIFEST.SKIP	(original)
+++ Template-Declare/trunk/MANIFEST.SKIP	Fri Oct 16 16:42:36 2009
@@ -43,3 +43,4 @@
 \.svn
 \.git
 \.t_$
+pod-spelling.t$

Modified: Template-Declare/trunk/lib/Template/Declare.pm
==============================================================================
--- Template-Declare/trunk/lib/Template/Declare.pm	(original)
+++ Template-Declare/trunk/lib/Template/Declare.pm	Fri Oct 16 16:42:36 2009
@@ -1,7 +1,6 @@
 use 5.006;
 use warnings;
 use strict;
-use Carp;
 
 package Template::Declare;
 use Template::Declare::Buffer;
@@ -13,8 +12,6 @@
 use base 'Class::Data::Inheritable';
 __PACKAGE__->mk_classdata('dispatch_to');
 __PACKAGE__->mk_classdata('postprocessor');
-__PACKAGE__->mk_classdata('aliases');
-__PACKAGE__->mk_classdata('alias_metadata');
 __PACKAGE__->mk_classdata('templates');
 __PACKAGE__->mk_classdata('private_templates');
 __PACKAGE__->mk_classdata('buffer');
@@ -23,8 +20,6 @@
 
 __PACKAGE__->dispatch_to( [] );
 __PACKAGE__->postprocessor( sub { return wantarray ? @_ : $_[0] } );
-__PACKAGE__->aliases(           {} );
-__PACKAGE__->alias_metadata(    {} );
 __PACKAGE__->templates(         {} );
 __PACKAGE__->private_templates( {} );
 __PACKAGE__->buffer( String::BufferStack->new );
@@ -39,15 +34,7 @@
     return $ref->buffer;
 };
 
-use vars qw/$TEMPLATE_VARS/;
-
-# Backwards-compatibility support.
-sub roots {
-    # warn "roots() has been deprecated; use dispatch_to() instead\n";
-    my $class = shift;
-    $class->dispatch_to( [ reverse @{ +shift } ] ) if @_;
-    return [ reverse @{ $class->dispatch_to } ];
-}
+our $TEMPLATE_VARS;
 
 =head1 NAME
 
@@ -110,7 +97,7 @@
 
 =item *
 
-"Native" XML namespace and declarator support
+"Native" XML namespace and declaration support
 
 =item *
 
@@ -122,75 +109,119 @@
 
 =item *
 
+Delegation
+
+=item *
+
 Public and private templates
 
 =back
 
-=head1 USAGE
+=head1 GLOSSARY
 
-=head2 Basic usage
+=over
 
-A simple HTML example is in the L<SYNOPSIS/SYNOPSIS>. So let's do XUL!
+=item template class
 
-    package MyApp::Templates;
-    use base 'Template::Declare';
-    use Template::Declare::Tags 'XUL';
+A subclass of Template::Declare in which one or more templates are defined
+using the C<template> keyword, or that inherits templates from a super class.
 
-    template main => sub {
-        xml_decl { 'xml', version => '1.0' };
-        xml_decl { 'xml-stylesheet', href => "chrome://global/skin/", type => "text/css" };
-        groupbox {
-            caption { attr { label => 'Colors' } }
-            radiogroup {
-                for my $id ( qw< orange violet yellow > ) {
-                    radio {
-                        attr {
-                            id    => $id,
-                            label => ucfirst($id),
-                            $id eq 'violet' ? (selected => 'true') : ()
-                        }
-                    }
-                } # for
-            }
-        }
-    };
+=item template
 
-    package main;
-    Template::Declare->init( dispatch_to => ['MyApp::Templates'] );
-    print Template::Declare->show( 'main' );
+Created with the C<template> keyword, a template is a subroutine that uses
+C<tags> to generate output.
 
-The output:
+=item attribute
 
- <?xml version="1.0"?>
- <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+An XML element attribute. For example, in C<< <img src="foo.png" /> >>, C<src>
+is an attribute of the C<img> element.
 
- <groupbox>
-  <caption label="Colors" />
-  <radiogroup>
-   <radio id="orange" label="Orange" />
-   <radio id="violet" label="Violet" selected="true" />
-   <radio id="yellow" label="Yellow" />
-  </radiogroup>
- </groupbox>
+=item tag
+
+A subroutine that generates XML element-style output. Tag subroutines execute
+blocks that generate the output, and can call other tags to generate a
+properly hierarchical structure.
+
+=item tag set
+
+A collection of related tags defined in a subclass of
+L<Template::Declare::TagSet> for a particular purpose, and which can be
+imported into a template class. For example,
+L<Template::Declare::TagSet::HTML> defines tags for emitting HTML elements.
+
+=item wrapper
+
+A subroutine that wraps the output from a template. Useful for wrapping
+template output in common headers and footers, for example.
+
+=item dispatch class
+
+A template class that has been passed to L<C<init()>|/init> via the
+C<dispatch_to> parameter. When L<show|/"show TEMPLATE"> is called, only
+templates defined in or mixed into the dispatch classes will be executed.
+
+=item path
+
+The name specified for a template when it is created by the C<template>
+keyword, or when a template is mixed into a template class.
+
+=item mixin
+
+A template mixed into a template class via L</mix>. Mixed-in templates may be
+mixed in under prefix paths to distinguish them from the templates defined in
+the dispatch classes.
+
+=item alias
+
+A template aliased into a template class via L</alias>. Aliased templates may
+be added under prefix paths to distinguish them from the templates defined in
+the dispatch classes.
+
+=item package variable
+
+Variables defined when mixing templates into a template class. These variables
+are available only to the mixed-in templates; they are not even accessible
+from the template class in which the templates were defined.
+
+=item helper
+
+A subroutine used in templates to assist in the generation of output, or in
+template classes to assist in the mixing-in of templates. Output helpers
+include C<outs()> for rending text output and C<xml_decl()> for rendering XML
+declarations. Mixin helpers include C<into> for specifying a template class to
+mix into, and C<under> for specifying a path prefix under which to mix
+templates.
+
+=back
+
+=head1 Basics
+
+Like other Perl templating systems, there are two parts to Template::Declare:
+the templates and the code that loads and executes the templates. Unlike other
+template systems, the templates are written in Perl classes. A simple HTML
+example is in the L</SYNOPSIS>.
 
 =head2 A slightly more advanced example
 
 In this example, we'll show off how to set attributes on HTML tags, how to
-call other templates and how to declare a I<private> template that can't be
-called directly. We'll also show passing arguments to templates.
+call other templates, and how to declare a I<private> template that can't be
+called directly. We'll also show passing arguments to templates. First, the
+template class:
 
     package MyApp::Templates;
-    use Template::Declare::Tags;
     use base 'Template::Declare';
+    use Template::Declare::Tags;
 
-    private template 'header' => sub {
+    private template 'util/header' => sub {
         head {
             title { 'This is a webpage' };
-            meta  { attr { generator => "This is not your father's frontpage" } }
+            meta  {
+                attr { generator => "This is not your father's frontpage" }
+            }
         }
     };
 
-    private template 'footer' => sub {
+    private template 'util/footer' => sub {
         my $self = shift;
         my $time = shift || gmtime;
 
@@ -205,7 +236,7 @@
         my $user = shift || 'world wide web';
 
         html {
-            show('header');
+            show('util/header');
             body {
                 img { src is 'hello.jpg' }
                 p {
@@ -213,16 +244,79 @@
                     "Hello, $user!"
                 };
             };
-            show('footer');
+            show('util/footer', 'noon');
         }
     };
 
+A few notes on this example:
+
+=over
+
+=item *
+
+Since no parameter was passed to C<use Template::Declare::Tags>, the HTML tags
+are imported by default.
+
+=item *
+
+The C<private> keyword indicates that a template is private. That means that
+it can only be executed by other templates within the template class in which
+it's declared. By default, C<< Template::Declare->show >> will not dispatch to
+it.
+
+=item *
+
+The two private templates have longer paths than we've seen before:
+C<util/header> and C<util/footer>. They must of course be called by their full
+path names. You can put any characters you like into template names, but the
+use of Unix filesystem-style paths is the most common (following on the
+example of L<HTML::Mason|HTML::Mason>).
+
+=item *
+
+The first argument to a template is a class name. This can be useful for
+calling methods defined in the class.
+
+=item *
+
+The C<show> sub executes another template. In this example, the C<simple>
+template calls C<show('util/header')> and C<show('util/footer')> in order to
+execute those private templates in the appropriate places.
+
+=item *
+
+Additional arguments to C<show> are passed on to the template being executed.
+here, C<show('util/footer', 'noon')> is passing "noon" to the C<util/footer>
+template, with the result that the "last generated at" string will display
+"noon" instead of the default C<gmtime>.
+
+=item *
+
+In the same way, note that the C<simple> template expects an additional
+argument, a user name.
+
+=item *
+
+In addition to using C<attr> to declare attributes for an element, you can
+use C<is>, as in
+
+    img { src is 'hello.jpg' }
+
+=back
+
+Now for executing the template:
+
     package main;
     use Template::Declare;
     Template::Declare->init( dispatch_to => ['MyApp::Templates'] );
-    print Template::Declare->show( 'simple', 'TD user');
+    print Template::Declare->show( '/simple', 'TD user');
+
+We've told Template::Declare to dispatch to templates defined in our template
+class. And note how an additional argument is passed to C<show()>; that
+argument, "TD user", will be passed to the C<simple> template, where it will
+be used in the C<$user> variable.
 
-And the output:
+The output looks like this:
 
  <html>
   <head>
@@ -236,8 +330,108 @@
   <div id="footer">Page last generated at Thu Sep  3 20:56:14 2009.</div>
  </html>
 
-For more options, especially the "native" XML namespace support, C<is> syntax
-for attributes, and more samples, see L<Template::Declare::Tags>.
+Note that the single quote in C<father's> was quoted for you. We sanitize
+your output for you to help prevent cross-site scripting attacks.
+
+=head2 XUL
+
+Template::Declare isn't limited to just HTML. Let's do XUL!
+
+    package MyApp::Templates;
+    use base 'Template::Declare';
+    use Template::Declare::Tags 'XUL';
+
+    template main => sub {
+        xml_decl { 'xml', version => '1.0' };
+        xml_decl {
+            'xml-stylesheet',
+            href => "chrome://global/skin/",
+            type => "text/css"
+        };
+        groupbox {
+            caption { attr { label => 'Colors' } }
+            radiogroup {
+                for my $id ( qw< orange violet yellow > ) {
+                    radio {
+                        attr {
+                            id    => $id,
+                            label => ucfirst($id),
+                            $id eq 'violet' ? (selected => 'true') : ()
+                        }
+                    }
+                } # for
+            }
+        }
+    };
+
+The first thing to do in a template class is to subclass Template::Declare
+itself. This is required so that Template::Declare always knows that it's
+dealing with templates. The second thing is to C<use Template::Declare::Tags>
+to import the set of tag subroutines you need to generate the output you want.
+In this case, we've imported tags to support the creation of XUL. Other tag
+sets include HTML (the default), and RDF.
+
+Templates are created using the C<template> keyword:
+
+    template main => sub { ... };
+
+The first argument is the name of the template, also known as its I<path>. In
+this case, the template's path is C<main> (or C</main>, both are allowed (to
+keep both PHP and L<HTML::Mason> fans happy). The second argument is an
+anonymous subroutine that uses the tag subs (and any other necessary code) to
+generate the output for the template.
+
+The tag subs imported into your class take blocks as arguments, while a
+number of helper subs take other arguments. For example, the C<xml_decl>
+helper takes as its first argument the name of the XML declaration to be
+output, and then a hash of the attributes of that declaration:
+
+    xml_decl { 'xml', version => '1.0' };
+
+Tag subs are used by simply passing a block to them that generates the output.
+Said block may of course execute other tag subs in order to represent the
+hierarchy required in your output. Here, the C<radiogroup> tag calls the
+C<radio> tag for each of three different colors:
+
+    radiogroup {
+        for my $id ( qw< orange violet yellow > ) {
+            radio {
+                attr {
+                    id    => $id,
+                    label => ucfirst($id),
+                    $id eq 'violet' ? (selected => 'true') : ()
+                }
+            }
+        } # for
+    }
+
+Note the C<attr> sub. This helper function is used to add attributes to the
+element created by the tag in which they appear. In the previous example, the
+the C<id>, C<label>, and C<selected> attributes are added to each C<radio>
+output.
+
+Once you've written your templates, you'll want to execute them. You do so by
+telling Template::Declare what template classes to dispatch to and then asking
+it to show you the output from a template:
+
+    package main;
+    Template::Declare->init( dispatch_to => ['MyApp::Templates'] );
+    print Template::Declare->show( 'main' );
+
+The path passed to C<show> can be either C<main> or </main>, as you prefer. In
+either event, the output would look like this:
+
+ <?xml version="1.0"?>
+ <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+ <groupbox>
+  <caption label="Colors" />
+  <radiogroup>
+   <radio id="orange" label="Orange" />
+   <radio id="violet" label="Violet" selected="true" />
+   <radio id="yellow" label="Yellow" />
+  </radiogroup>
+ </groupbox>
 
 =head2 Postprocessing
 
@@ -259,10 +453,21 @@
     };
 
     template after => sub {
-        h1 { "Welcome to _my_ site. It's _great_!" };
-        h2 { outs_raw "This is _not_ emphasized." };
+        h1  { "Welcome to _my_ site. It's _great_!" };
+        h2  { outs_raw "This is _not_ emphasized." };
+        img { src is '/foo/_bar_baz.png' };
     };
 
+Here we've defined two templates in our template class, with the paths
+C<before> and C<after>. The one new thing to note is the use of the C<outs>
+and C<outs_raw> subs. C<outs> XML-encodes its argument and outputs it. You can
+also just specify a string to be output within a tag call, but if you need to
+mix tags and plain text within a tag call, as in the C<before> template here,
+you'll need to use C<outs> to get things to output as you would expect.
+C<outs_raw> is the same, except that it does no XML encoding.
+
+Now let's have a look at how we use these templates with a post-processor:
+
     package main;
     use Template::Declare;
     Template::Declare->init(
@@ -270,8 +475,8 @@
         postprocessor => \&emphasize,
     );
 
-    print Template::Declare->show( 'before');
-    print Template::Declare->show( 'after');
+    print Template::Declare->show( 'before' );
+    print Template::Declare->show( 'after'  );
 
     sub emphasize {
         my $text = shift;
@@ -279,18 +484,31 @@
         return $text;
     }
 
-And the output:
+As usual, we've told Template::Declare to dispatch to our template class. A
+new parameter to C<init()> is C<postprocessor>, which is a code reference that
+should expect the template output as an argument. It can then transform that
+text however it sees fit before returning it for final output. In this
+example, the C<emphasize> subroutine looks for text that's emphasized using
+_underscores_ and turns them into C<< <em>emphasis</em> >> HTML elements.
+
+We then execute both the C<before> and the C<after> templates with the output
+ending up as:
 
  <h1>Welcome to
   <em>my</em> site. It&#39;s
   <em>great</em>!</h1>
  <h1>Welcome to <em>my</em> site. It&#39;s <em>great</em>!</h1>
  <h2>This is _not_ emphasized.</h2>
+ <img src="/foo/_bar_baz.png" />
+
+The thing to note here is that text passed to C<outs_raw> is not passed
+through the postprocessor, and neither are attribute values (like the C<img>'s
+C<src>).
 
 =head2 Inheritance
 
 Templates are really just methods. You can subclass your template packages to
-override some of those methods. See also L<Jifty::View::Declare::CRUD>.
+override some of those methods:
 
     package MyApp::Templates::GenericItem;
     use Template::Declare::Tags;
@@ -311,38 +529,493 @@
     use Template::Declare::Tags;
     use base 'MyApp::Templates::GenericItem';
 
-    template 'item' => sub {
-        my ($self, $post) = @_;
-        h1  { $post->title }
-        div { $post->body }
+    template 'item' => sub {
+        my ($self, $post) = @_;
+        h1  { $post->title }
+        div { $post->body }
+    };
+
+Here we have two template classes; the second, C<MyApp::Templates::BlogPost>,
+inherits from the first, C<MyApp::Templates::GeniricItem>. Note also that
+C<MyApp::Templates::BlogPost> overrides the C<item> template. So execute these
+templates:
+
+    package main;
+    use Template::Declare;
+
+    Template::Declare->init( dispatch_to => ['MyApp::Templates::GenericItem'] );
+    print Template::Declare->show( 'list', 'foo', 'bar', 'baz' );
+
+    Template::Declare->init( dispatch_to => ['MyApp::Templates::BlogPost'] );
+    my $post = My::Post->new(title => 'Hello', body => 'first post');
+    print Template::Declare->show( 'item', $post );
+
+First we execute the C<list> template in the base class, passing in some
+items, and then we re-C<init()> Template::Declare and execute I<its> C<list>
+template with an appropriate argument. Here's the output:
+
+ <div>
+  <span>foo</span>
+  <span>bar</span>
+  <span>baz</span>
+ </div>
+
+ <h1>Hello</h1>
+ <div>first post</div>
+
+So the override of the C<list> template in the subclass works as expected. For
+another example, see L<Jifty::View::Declare::CRUD>.
+
+=head2 Wrappers
+
+There are two levels of wrappers in Template::Declare: template wrappers and
+smart tag wrappers.
+
+=head3 Template Wrappers
+
+C<create_wrapper> declares a wrapper subroutine that can be called like a tag
+sub, but can optionally take arguments to be passed to the wrapper sub. For
+example, if you wanted to wrap all of the output of a template in the usual
+HTML headers and footers, you can do something like this:
+
+    package MyApp::Templates;
+    use Template::Declare::Tags;
+    use base 'Template::Declare';
+
+    BEGIN {
+        create_wrapper wrap => sub {
+            my $code = shift;
+            my %params = @_;
+            html {
+                head { title { outs "Hello, $params{user}!"} };
+                body {
+                    $code->();
+                    div { outs 'This is the end, my friend' };
+                };
+            }
+        };
+    }
+
+    template inner => sub {
+        wrap {
+            h1 { outs "Hello, Jesse, s'up?" };
+        } user => 'Jesse';
+    };
+
+Note how the C<wrap> wrapper function is available for calling after it has
+been declared in a C<BEGIN> block. Also note how you can pass arguments to the
+function after the closing brace (you don't need a comma there!).
+
+The output from the "inner" template will look something like this:
+
+ <html>
+  <head>
+   <title>Hello, Jesse!</title>
+  </head>
+  <body>
+   <h1>Hello, Jesse, s&#39;up?</h1>
+   <div>This is the end, my friend</div>
+  </body>
+ </html>
+
+=head3 Tag Wrappers
+
+Tag wrappers are similar to template wrappers, but mainly function as syntax
+sugar for creating subroutines that behave just like tags but are allowed to
+contain arbitrary Perl code and to dispatch to other tag. To create one,
+simply create a named subroutine with the prototype C<(&)> so that its
+interface is the same as tags. Within it, use
+L<C<smart_tag_wrapper>|Template::Declare::Tags/"smart_tag_wrapper"> to do the
+actual execution, like so:
+
+    package My::Template;
+    use Template::Declare::Tags;
+    use base 'Template::Declare';
+
+    sub myform (&) {
+        my $code = shift;
+
+        smart_tag_wrapper {
+            my %params = @_; # set using 'with'
+            form {
+                attr { %{ $params{attr} } };
+                $code->();
+                input { attr { type => 'submit', value => $params{value} } };
+            };
+        };
+    }
+
+    template edit_prefs => sub {
+        with(
+            attr  => { id => 'edit_prefs', action => 'edit.html' },
+            value => 'Save'
+        ), myform {
+            label { 'Time Zone' };
+            input { type is 'text'; name is 'tz' };
+        };
+    };
+
+Note in the C<edit_prefs> template that we've used
+L<C<with>|Template::Declare::Tags/"with"> to set up parameters to be passed to
+the smart wrapper. C<smart_tag_wrapper()> is the device that allows you to
+receive those parameters, and also handles the magic of making sure that the
+tags you execute within it are properly output. Here we've used C<myform>
+similarly to C<form>, only C<myform> does something different with the
+C<with()> arguments and outputs a submit element.
+
+Executing this template:
+
+    Template::Declare->init( dispatch_to => ['My::Template'] );
+    print Template::Declare->show('edit_prefs');
+
+Yields this output:
+
+ <form action="edit.html" id="edit_prefs">
+  <label>Time Zone</label>
+  <input type="text" name="tz" />
+  <input type="submit" value="Save" />
+ </form>
+
+=head2 Class Search Dispatching
+
+The classes passed via the C<dispatch_to> parameter to C<init()> specify all
+of the templates that can be executed by subsequent calls to C<show()>.
+Template searches through these classes in order to find those templates. Thus
+it can be useful, when you're creating your template classes and determining
+which to use for particular class to C<show()>, to have templates that
+override other templates. This is similar to how an operating system will
+search all the paths in the C<$PATH> environment variable for a program to
+run, and to L<HTML::Mason> component roots or L<Template::Toolkit>'s
+C<INCLUDE_PATH> parameter.
+
+For example, say you have this template class that defines a template that
+you'll use for displaying images on your Web site.
+
+    package MyApp::UI::Standard;
+    use Template::Declare::Tags;
+    use base 'Template::Declare';
+
+    template image => sub {
+        my ($self, $src, $title) = @_;
+        img {
+            src is $src;
+            title is $title;
+        };
+    };
+
+As usual, you can use it like so:
+
+    my @template_classes = 'MyApp::UI::Standard';
+    Template::Declare->init( dispatch_to => \@template_classes );
+    print Template::Declare->show('image', 'foo.png', 'Foo');
+
+We're explicitly using a reference to C<@template_classes> so that we can
+manage this list ourselves.
+
+The output of this will be:
+
+ <div class="std">
+  <img src="foo.png" title="Foo" />
+  <p class="caption"></p>
+ </div>
+
+But say that in some sections of your site you need to have a more formal
+treatment of your photos. Maybe you publish photos from a wire service and
+need to provide an appropriate credit. You might write the template class like
+so:
+
+    package MyApp::UI::Formal;
+    use Template::Declare::Tags;
+    use base 'Template::Declare';
+
+    template image => sub {
+        my ($self, $src, $title, $credit, $caption) = @_;
+        div {
+            class is 'formal';
+            img {
+                src is $src;
+                title is $title;
+            };
+            p {
+                class is 'credit';
+                outs "Photo by $credit";
+            };
+            p {
+                class is 'caption';
+                outs $caption;
+            };
+        };
+    };
+
+
+This, too, will work as expected, but the useful bit that comes in when you're
+mixing and matching template classes to pass to C<dispatch_to> before
+rendering a page. Maybe you always pass have MyApp::UI::Standard to
+C<dispatch_to> because it has all of your standard formatting templates.
+But when the code realizes that a particular page needs the more formal
+treatment, you can prepend the formal class to the list:
+
+    unshift @template_classes, 'MyApp::UI::Formal';
+    print Template::Declare->show(
+        'image',
+        'ap.png',
+        'AP Photo',
+        'Clark Kent',
+        'Big news'
+    );
+    shift @template_classes;
+
+In this way, made the formal C<image> template will be found first, yielding
+this output:
+
+ <div class="formal">
+  <img src="ap.png" title="AP Photo" />
+  <p class="credit">Photo by Clark Kent</p>
+  <p class="caption">Big news</p>
+ </div>
+
+At the end, we've shifted the formal template class off the C<dispatch_to>
+list in order to restore the template classes the default configuration, ready
+for the next request.
+
+=head2 Template Composition
+
+There are two methods of template composition: mixins and delegation. Their
+interfaces are very similar, the only difference being the template invocant.
+
+=head2 Mixins
+
+Let's start with a mixin.
+
+    package MyApp::UtilTemplates;
+    use Template::Declare::Tags;
+    use base 'Template::Declare';
+
+    template content => sub {
+        my $self  = shift;
+        my @paras = @_;
+        h1 { $self->get_title };
+        div {
+            id is 'content';
+            p { $_ } for @paras;
+        };
+    };
+
+    package MyApp::Templates;
+    use Template::Declare::Tags;
+    use base 'Template::Declare';
+    mix MyApp::UtilTemplates under '/util';
+
+    sub get_title { 'Kashmir' }
+
+    template story => sub {
+        my $self = shift;
+        html {
+          head {
+              title { "My Site: " . $self->get_title };
+          };
+          body {
+              show( 'util/content' => 'first paragraph', 'second paragraph' );
+          };
+        };
+    };
+
+The first template class, C<MyApp::UtilTemplates>, defines a utility template,
+called C<content>, for outputting the contents of page. Note its call to
+C<< $self->get_title >> even though it doesn't have a C<get_title> method. This
+is part of the mixin's "contract": it requires that the class it's mixed into
+have a C<get_title()> method.
+
+The second template class, C<MyApp::Templates>, mixes C<MyApp::UtilTemplates>
+into itself under the path C</util> and defines a C<get_title()> method as
+required by the mixin. Then, its C<story> template calls the mixed-in template
+as C<util/content>, because the C<content> template was mixed into the current
+template under C</util>. Get it?
+
+Now we can use the usual template invocation:
+
+    package main;
+    Template::Declare->init( dispatch_to => ['MyApp::Templates'] );
+    print Template::Declare->show('story');
+
+To appreciate our output:
+
+ <html>
+  <head>
+   <title>My Site: Kashmir</title>
+  </head>
+  <body>
+   <h1>Kashmir</h1>
+   <div id="content">
+    <p>fist paragraph</p>
+    <p>second paragraph</p>
+   </div>
+  </body>
+ </html>
+
+Mixins are a very useful tool for template authors to add reusable
+functionality to their template classes. But it's important to pay attention to
+the mixin contracts so that you're sure to implement the required API in your
+template class (here, the C<get_title()> method).
+
+=head3 Aliases
+
+Aliases are very similar to mixins, but implement delegation as a composition
+pattern, rather than mixins. The upshot is that there is no contract provided
+by an aliased class: it just works. This is because the invocant is the class
+from which the aliases are imported, and therefore it will dispatch to methods
+defined in the aliased class.
+
+For example, say that you wanted to output a sidebar on pages that need one
+(perhaps your CMS has sidebar things). We can define a template class that
+has a template for that:
+
+    package MyApp::UI::Stuff;
+    use Template::Declare::Tags;
+    use base 'Template::Declare';
+
+    sub img_path { '/ui/css' }
+
+    template sidebar => sub {
+        my ($self, $thing) = @_;
+        div {
+            class is 'sidebar';
+            img { src is $self->img_path . '/sidebar.png' };
+            p { $_->content } for $thing->get_things;
+        };
+    };
+
+Note the use of the C<img_path()> method defined in the template class and
+used by the C<sidebar> template. Now let's use it:
+
+    package MyApp::Render;
+    use Template::Declare::Tags;
+    use base 'Template::Declare';
+    alias MyApp::UI::Stuff under '/stuff';
+
+    template page => sub {
+        my ($self, $page) = @_;
+        h1 { $page->title };
+        for my $thing ($page->get_things) {
+            if ($thing->is('paragraph')) {
+                p { $thing->content };
+            } elsif ($thing->is('sidebar')) {
+                show( '/stuff/sidebar' => $thing );
+            }
+        }
+    };
+
+Here our rendering template class has aliased C<MyApp::UI::Stuff> under
+C</stuff>. So the C<page> template calls C<show('/stuff/sidebar')> to invoke
+the sidebar template. If we run this:
+
+    Template::Declare->init( dispatch_to => ['MyApp::Render'] );
+    print Template::Declare->show( page => $page );
+
+We get output as you might expect:
+
+ <h1>My page title</h1>
+ <p>Page paragraph</p>
+ <div class="sidebar">
+  <img src="/ui/css/sidebar.png" />
+  <p>Sidebar paragraph</p>
+  <p>Another paragraph</p>
+ </div>
+
+Now, let's say that you have political stuff that you want to use a different
+image for in the sidebar. If that's the only difference, we can subclass
+C<MyApp::UI::Stuff> and just override the C<img_path()> method:
+
+    package MyApp::UI::Stuff::Politics;
+    use Template::Declare::Tags;
+    use base 'MyApp::UI::Stuff';
+
+    sub img_path { '/politics/ui/css' }
+
+Now let's mix that into a politics template class:
+
+    package MyApp::Render::Politics;
+    use Template::Declare::Tags;
+    use base 'Template::Declare';
+    alias MyApp::UI::Stuff::Politics under '/politics';
+
+    template page => sub {
+        my ($self, $page) = @_;
+        h1 { $page->title };
+        for my $thing ($page->get_things) {
+            if ($thing->is('paragraph')) {
+                p { $thing->content };
+            } elsif ($thing->is('sidebar')) {
+                show( '/politics/sidebar' => $thing );
+            }
+        }
     };
 
-    package main;
-    use Template::Declare;
+The only difference between this template class and C<MyApp::Render> is that
+it aliases C<MyApp::UI::Stuff::Politics> under C</politics>, and then calls
+C<show('/politics/sidebar')> in the C<page> template. Running this template:
+
+    Template::Declare->init( dispatch_to => ['MyApp::Render::Politics'] );
+    print Template::Declare->show( page => $page );
+
+Yields output using the value of the subclass's C<img_path()> method -- that
+is, the sidebar image is now F</politics/ui/css/sidebar.png> instead of
+F</ui/css/sidebar.png>:
+
+ <h1>My page title</h1>
+ <p>Page paragraph</p>
+ <div class="sidebar">
+  <img src="/politics/ui/css/sidebar.png" />
+  <p>Sidebar paragraph</p>
+  <p>Another paragraph</p>
+ </div>
 
-    Template::Declare->init(
-        dispatch_to => ['MyApp::Templates::GenericItem']
-    );
-    print Template::Declare->show( 'list', 'foo', 'bar', 'baz' );
+=head3 Other Tricks
 
-    Template::Declare->init( dispatch_to => ['MyApp::Templates::BlogPost'] );
-    my $post = My::Post->new(title => 'Hello', body => 'first post');
-    print Template::Declare->show( 'item', $post );
+The delegation behavior of C<alias> actually makes it a decent choice for
+template authors to mix and match libraries of template classes as
+appropriate, without worrying about side effects. You can even alias templates
+in one template class into another template class if you're not the author of
+that class by using the C<into> keyword:
+
+    alias My::UI::Widgets into Your::UI::View under '/widgets';
+
+Now the templates defined in C<Your::UI::View> are available in
+C<My::UI::Widgets> under C</widgets>. The C<mix> method supports this syntax
+as well, though it's not necessarily recommended, given that you would not be
+able to fulfill any contracts unless you re-opened the class into which you
+mixed the templates. But in any case, authors of framework view classes might
+find this functionality useful for automatically aliasing template classes
+into a single dispatch template class.
+
+Another trick is to alias or mix your templates with package variables
+specific to the composition. Do so via the C<setting> keyword:
+
+    package My::Templates;
+    mix Some::Mixin under '/mymix', setting { name => 'Larry' };
+
+The templates mixed from C<Some::Mixin> into C<My::Templates> have package
+variables set for them that are accessible I<only> from their mixed-in paths.
+For example, if this template was defined in C<Some::Mixin>:
 
-And the output:
+    template howdy => sub {
+        my $self = shift;
+        outs "Howdy, " . $self->package_variable('name') || 'Jesse';
+    };
 
- <div>
-  <span>foo</span>
-  <span>bar</span>
-  <span>baz</span>
- </div>
+Then C<show('mymix/howdy')> called on C<My::Templates> will output "Howdy,
+Larry", while the output from C<show('howdy')> will output "Howdy, Jesse". In
+other words, package variables defined for the mixed-in templates are
+available only to the mixins and not to the original. The same functionality
+exists for C<alias> as well.
 
- <h1>Hello</h1>
- <div>first post</div>
+=begin comment
 
-=head2 Aliasing and Mixins
+=head2 Tag Sets
 
-=head2 Class Search Dispatching
+Wherein we will eventually provide a brief tutorial on creating custom tag sets.
+
+=end comment
 
 =head1 METHODS
 
@@ -407,71 +1080,6 @@
 
 }
 
-=head2 buffer
-
-Gets or sets the L<String::BufferStack> object; this is a class method. You
-can use it to manipulate the output from tags as they are output. It's used
-internally to make the tags nest correctly, and be output to the right place.
-We're not sure if there's ever a need for you 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>
-
-We'll leave it to you to judge whether or not that's actually useful.
-
-=head2 new_buffer_frame
-
-  $td->new_buffer_frame();
-
-Creates a new buffer frame, using L<String::BufferStack/push> with C<private>.
-This use is deprecated in favor of dealing with L</buffer> directly.
-
-=cut
-
-sub new_buffer_frame {
-    __PACKAGE__->buffer->push( private => 1 );
-}
-
-=head2 end_buffer_frame
-
-  my $buf = $td->end_buffer_frame();
-
-Deletes and returns the topmost buffer, using L<String::BufferStack/pop>. This
-use is deprecated in favor of dealing with L</buffer> directly..
-
-=cut
-
-sub end_buffer_frame {
-    __PACKAGE__->buffer->pop;
-}
-
 =head2 show TEMPLATE_NAME
 
     Template::Declare->show( 'howdy', name => 'Larry' );
@@ -494,24 +1102,130 @@
     return Template::Declare::Tags::show_page($template => @_);
 }
 
-=head2 path_for $template
+=head2 Template Composition
 
-    my $path = Template::Declare->path_for('index');
+Sometimes you want to mix templates from one class into another class, or
+delegate template execution to a class of templates. C<alias()> and C<mix()>
+are your keys to doing so.
+
+=head3 mix
+
+    mix Some::Clever::Mixin      under '/mixin';
+    mix Some::Other::Mixin       under '/otmix', setting { name => 'Larry' };
+    mix My::Mixin into My::View, under '/mymix';
+
+Mixes templates from one template class into another class. When the mixed-in
+template is called, its invocant will be the class into which it was mixed.
+This type of composition is known as a "mixin" in object-oriented parlance.
+See L<Template Composition|/"Template Composition"> for extended examples and
+a comparision to C<alias>.
+
+The first parameter is the name of the template class to be mixed in. The
+C<under> keyword tells C<mix> where to put the templates. For example,
+a C<foo> template in C<Some::Clever::Mixin> will be mixed in as C<mymixin/foo>.
+
+The C<setting> keyword specifies package variables available only to the
+mixed-in copies of templates. These are available to the templates as
+C<< $self->package_variable($varname) >>.
+
+The C<into> keyword tells C<mix> into what class to mix the templates. Without
+theis keyword, C<mix> will mix them into the calling class.
+
+For those who prefer a direct OO syntax for mixins, just call C<mix()> as a
+method on the class to be mixed in. To replicate the above three examples
+without the use of the sugar:
+
+    Some::Clever::Mixin->mix( '/mixin' );
+    Some::Other::Mixin->mix( '/otmix', { name => 'Larry' } );
+    My::Mixin->mix( 'My::View', '/mymix' );
 
-Returns the path for the template name to be used for show, adjusted with
-paths used in C<import_templates>. Note that this will only work for the last
-class into which you imported the template. This method is, therefore,
-deprecated.
+=cut
+
+sub mix {
+    my $mixin = shift;
+    my ($into, @args) = _into(@_);
+    $mixin->_import($into, $into, @args);
+}
+
+=head3 alias
+
+    alias Some::Clever:Templates   under '/delegate';
+    alias Some::Other::Templates   under '/send_to', { name => 'Larry' };
+    alias UI::Stuff into My::View, under '/mystuff';
+
+Aliases templates from one template class into another class. When an alias
+called, its invocant will be the class from which it was aliased. This type of
+composition is known as "delegation" in object-oriented parlance. See
+L<Template Composition|/"Template Composition"> for extended examples and a
+comparison to C<mix>.
+
+The first parameter is the name of the template class to alias. The C<under>
+keyword tells C<alias> where to put the templates. For example, a C<foo>
+template in C<Some::Clever::Templates> will be aliased as C<delegate/foo>.
+
+The C<setting> keyword specifies package variables available only to the
+aliases. These are available to the templates as
+C<< $self->package_variable($varname) >>.
+
+The C<into> keyword tells C<alias> into what class to aliase the templates.
+Without this keyword, C<alias> will alias them into the calling class.
+
+For those who prefer a direct OO syntax for mixins, just call C<alias()> as a
+method on the class to be mixed in. To replicate the above three examples
+without the use of the sugar:
+
+    Some::Clever:Templates->alias( '/delegate' );
+    Some::Other::Templates->alias( '/send_to', { name => 'Larry' } );
+    UI::Stuff->alias( 'My::View', '/mystuff' );
 
 =cut
 
-sub path_for {
-    my $class = shift;
-    my $template = shift;
-    return ($class->imported_into ||'') . '/' . $template;
+sub alias {
+    my $mixin = shift;
+    my ($into, @args) = _into(@_);
+    $mixin->_import($into, undef, @args);
+}
+
+=head3 package_variable( VARIABLE )
+
+  $td->package_variable( $varname => $value );
+  $value = $td->package_variable( $varname );
+
+Returns a value set for a mixed-in template's variable, if any were specified
+when the template was mixed-in. See L</mix> for details.
+
+=cut
+
+sub package_variable {
+    my $self = shift;
+    my $var  = shift;
+    if (@_) {
+        $TEMPLATE_VARS->{$self}->{$var} = shift;
+    }
+    return $TEMPLATE_VARS->{$self}->{$var};
+}
+
+=head3 package_variables( VARIABLE )
+
+    $td->package_variables( $variables );
+    $variables = $td->package_variables;
+
+Get or set a hash reference of variables for a mixed-in template. See
+L</mix> for details.
+
+=cut
+
+sub package_variables {
+    my $self = shift;
+    if (@_) {
+        %{ $TEMPLATE_VARS->{$self} } = shift;
+    }
+    return $TEMPLATE_VARS->{$self};
 }
 
-=head2 resolve_template TEMPLATE_PATH INCLUDE_PRIVATE_TEMPLATES
+=head2 Templates registration and lookup
+
+=head3 resolve_template TEMPLATE_PATH INCLUDE_PRIVATE_TEMPLATES
 
     my $code = Template::Declare->resolve_template($template);
     my $code = Template::Declare->has_template($template, 1);
@@ -522,13 +1236,7 @@
 
 First it looks through all the valid Template::Declare classes defined via
 C<dispatch_to>. For each class, it looks to see if it has a template called
-$template_name directly (or via an C<import_templates>. Then it looks to see
-if there are any L<C<alias>/"alias"> paths for the class with prefixes that
-match the template we're looking for.
-
-=head2 has_template TEMPLATE_PATH INCLUDE_PRIVATE_TEMPLATES
-
-An alias for C<resolve_template>.
+$template_name directly (or via a mixin).
 
 =cut
 
@@ -551,15 +1259,19 @@
         next unless ( $package and $package->isa(__PACKAGE__) );
         if ( my $coderef = $package->_has_template( $template_name, $show_private ) ) {
             return $coderef;
-        } elsif (  $coderef = $package->_has_aliased_template($template_name, $show_private) ) {
-            return $coderef;
         }
     }
 }
 
+=head3 has_template TEMPLATE_PATH INCLUDE_PRIVATE_TEMPLATES
+
+An alias for C<resolve_template>.
+
+=cut
+
 sub has_template { resolve_template(@_) }
 
-=head2 register_template( TEMPLATE_NAME, CODEREF )
+=head3 register_template( TEMPLATE_NAME, CODEREF )
 
     MyApp::Templates->register_template( howdy => sub { ... } );
 
@@ -578,7 +1290,7 @@
     _register_template( $class, _template_name_to_sub($template_name), $code )
 }
 
-=head2 register_private_template( TEMPLATE_NAME, CODEREF )
+=head3 register_private_template( TEMPLATE_NAME, CODEREF )
 
     MyApp::Templates->register_private_template( howdy => sub { ... } );
 
@@ -602,130 +1314,158 @@
 
 }
 
-=head2 alias TEMPLATE_CLASS under PATH
-
-    alias Some::Clever::Mixin under '/mixin';
-    alias Some::Other::Mixin  under '/mymix', { name => 'Larry' };
+=head3 buffer
 
-Sometimes you want to alias templates to a subpath, or mix them into an
-existing template path. Use C<alias> to do so. In the first example, if
-Some::Clever::Mixin creates templates named "foo" and "bar", they will be
-aliased to "mixin/foo" and "mixin/bar".
+Gets or sets the L<String::BufferStack> object; this is a class method.
 
-The second example mixes in the templates defined in Some::Other::Mixin into
-the "/mymix" path and defines a package variable for use only by the alias.
-If this template was defined in Some::Other::Mixin:
+You can use it to manipulate the output from tags as they are output. It's used
+internally to make the tags nest correctly, and be output to the right place.
+We're not sure if there's ever a need for you to frob it by hand, but it does
+enable things like the following:
 
-    template 'howdy' => sub {
-        my $self = shift;
-        outs "Howdy, " . $self->package_variable('name') || 'Jesse';
+    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;
+           }
+       }
     };
 
-Then use of the "mymixin/howdy" template will output "Howdy, Lary", while use
-of the original template, "howdy", will output "Howdy, Jesse". In other words,
-package variables defined for the alias are available only to the alias, and
-not to the original.
-
-In either case, ineritance continues to work. A template package that inherits
-from Some::Other::Mixin, for example, will be able to access both
-"mymixin/howdy" and "howdy".
+...which outputs, with equal regularity, either:
 
-=cut
+ <html>
+  <head></head>
+  <body>
+   <P>WHEE!</P>
+   <P>HELLO, WORLD WIDE WEB!</P>
+  </body>
+ </html>
 
-sub alias {
-    my $alias_into   = caller(0);
-    my $mixin        = shift;
-    my $prepend_path = shift;
-    my $package_vars = shift;
+...or:
+
+ <html>
+  <head></head>
+  <body></body>
+ </html>
+
+We'll leave it to you to judge whether or not that's actually useful.
 
-    $prepend_path =~ s|/+/|/|g;
-    $prepend_path =~ s|/$||;
+=head2 Helpers
 
-    my $alias_key = $mixin . " " . $prepend_path;
-    push @{ Template::Declare->aliases->{$alias_into} }, $alias_key;
-    $alias_into->alias_metadata()->{$alias_key} = {
-        class        => $mixin,
-        path         => $prepend_path,
-        package_vars => $package_vars
-    };
+You don't need to call any of this directly.
 
-}
+=head3 into
+
+    $class = into $class;
 
-=head2 import_templates
+C<into> is a helper method providing semantic sugar for the L</mix> method.
+All it does is return the name of the class on which it was called.
+
+=cut
+
+sub into { shift }
+
+=head2 Old, deprecated or just better to avoid
+
+=head3 import_templates
 
     import_templates MyApp::Templates under '/something';
 
-Import the templates defined in a template class into a subpath via the
-C<import_templates> function. In this example, the templates defined in
-MyApp::Templates will be imported into the "/something" path. Thus, a template
-deined in MyApp::Templates named "foo" will also be accessible via
-"something/foo". This is not unlike mixing in templates with C<alias>, but is
-lighter-weight and package variables cannot be assigned. This is because it is
-really like a hard link to the template, whereas an alias is a copy with the
-variable information attached to it.
+Like C<mix()>, but without support for the C<into> or C<setting> keywords.
+That is, it mixes templates into the calling template class and does not
+support package variables for those mixins.
+
+B<Deprecated> in favor of L</mix>. Will be supported for a long time, but
+new code should use C<mix()>.
 
 =cut
 
 sub import_templates {
-    return undef if $_[0] eq __PACKAGE__;
-    my $import_into      = caller(0);
-    my $import_from_base = shift;
-    my $prepend_path     = shift;
-
-    $prepend_path =~ s|/+/|/|g;
-    $prepend_path =~ s|/$||;
-    $import_from_base->imported_into($prepend_path);
+    my $caller = scalar caller(0);
+    shift->_import($caller, $caller, @_);
+}
 
-    my @packages = reverse grep { $_->isa(__PACKAGE__) }
-        Class::ISA::self_and_super_path( $import_from_base );
+=head3 new_buffer_frame
 
-    foreach my $import_from (@packages) {
-        foreach my $template_name (  __PACKAGE__->_templates_for($import_from) ) {
-            my $code = $import_from->_find_template_sub( _template_name_to_sub($template_name));
-            $import_into->register_template( $prepend_path . "/" . $template_name, $code );
-        }
-        foreach my $template_name (  __PACKAGE__->_private_templates_for($import_from) ) {
-            my $code = $import_from->_find_template_sub( _template_name_to_private_sub($template_name) );
-            $import_into->register_private_template( $prepend_path . "/" . $template_name, $code );
-        }
-    }
+    $td->new_buffer_frame;
+    # same as 
+    $td->buffer->push( private => 1 );
+
+Creates a new buffer frame, using L<String::BufferStack/push> with C<private>.
+
+B<Deprecated> in favor of dealing with L</buffer> directly.
+
+=cut
+
+sub new_buffer_frame {
+    __PACKAGE__->buffer->push( private => 1 );
 }
 
-=head2 package_variable( VARIABLE )
+=head3 end_buffer_frame
 
-  $td->package_variable( $varname => $value );
-  $value = $td->package_variable( $varname );
+    my $buf = $td->end_buffer_frame;
+    # same as
+    my $buf = $td->buffer->pop;
 
-Returns the value set for a template alias's variable. See L<alias/alias> for
-details.
+Deletes and returns the topmost buffer, using L<String::BufferStack/pop>.
+
+B<Deprecated> in favor of dealing with L</buffer> directly.
 
 =cut
 
-sub package_variable {
-    my $self = shift;
-    my $var  = shift;
-    if (@_) {
-        $TEMPLATE_VARS->{$self}->{$var} = shift;
-    }
-    return $TEMPLATE_VARS->{$self}->{$var};
+sub end_buffer_frame {
+    __PACKAGE__->buffer->pop;
 }
 
-=head2 package_variables( VARIABLE )
+=head3 path_for $template
 
-  $td->package_variables( $variables );
-  $variables = $td->package_variables( );
+    my $path = Template::Declare->path_for('index');
 
-Get or set a hash reference of variables for a template alias. See
-L<alias/alias> for details.
+Returns the path for the template name to be used for show, adjusted with
+paths used in C<mix>. Note that this will only work for the last class into
+which you imported the template. This method is, therefore, deprecated.
 
 =cut
 
-sub package_variables {
-    my $self = shift;
-    if (@_) {
-        %{ $TEMPLATE_VARS->{$self} } = shift;
-    }
-    return $TEMPLATE_VARS->{$self};
+# Deprecated in favor of dispatch_to().
+sub roots {
+    # warn "roots() has been deprecated; use dispatch_to() instead\n";
+    my $class = shift;
+    $class->dispatch_to( [ reverse @{ +shift } ] ) if @_;
+    return [ reverse @{ $class->dispatch_to } ];
+}
+
+# Removed methods that no longer work (and were never documented anyway).
+# Remove these no-ops after a few releases (added for 0.41).
+
+=begin comment
+
+=head3 aliases
+
+=head3 alias_metadata
+
+=end comment
+
+=cut
+
+sub aliases {
+    require Carp;
+    Carp::cluck( 'aliases() is a deprecated no-op' );
+}
+
+sub alias_metadata {
+    require Carp;
+    Carp::cluck( 'alias_metadata() is a deprecated no-op' );
+}
+
+sub path_for {
+    my $class = shift;
+    my $template = shift;
+    return ($class->imported_into ||'') . '/' . $template;
 }
 
 sub _templates_for {
@@ -753,42 +1493,6 @@
     return undef;
 }
 
-sub _has_aliased_template {
-    my $package       = shift;
-    my $template_name = shift;
-    my $show_private  = shift;
-
-    # XXX Should we consider normalizing the path in a more standard way?
-    $template_name = "/$template_name" unless $template_name =~ m{^/};
-
-    foreach my $alias_key ( @{ Template::Declare->aliases->{$package} } ) {
-        my $alias_info   = $package->alias_metadata->{$alias_key};
-
-        my $alias_prefix = $alias_info->{path};
-        $alias_prefix = "/$alias_prefix" unless $alias_prefix =~ m{^/};
-        # handle the case where we alias something under '/'. the regex appends
-        # a '/' so we need to prevent matching against m{^//};
-        $alias_prefix = '' if $alias_prefix eq '/';
-
-        # starts with fast check
-        next unless rindex($template_name, "$alias_prefix/", 0) == 0;
-
-        my $dispatch_to = substr $template_name, length($alias_prefix)+1;
-        my $alias_class = $alias_info->{class};
-        my $coderef = $alias_class->resolve_template(
-            $dispatch_to, $show_private,
-        );
-        next unless $coderef;
-
-        my $package_vars = $alias_info->{package_vars};
-        return sub {
-            shift @_;  # Get rid of the passed-in "$self" class.
-            local $TEMPLATE_VARS->{$alias_class} = $package_vars;
-            $coderef->($alias_class, at _);
-        };
-    }
-}
-
 sub _dispatch_template {
     my $class = shift;
     my $code  = shift;
@@ -828,6 +1532,61 @@
     *{ $class . '::' . $subname } = $coderef;
 }
 
+sub _into {
+    my ($into, $under);
+    if ( eval { $_[0]->isa(__PACKAGE__) } ) {
+        ($into, $under) = (shift, shift);
+    } elsif ( eval { $_[1]->isa(__PACKAGE__) } ) {
+        ($under, $into) = (shift, shift);
+    } else {
+        $into  = caller(1);
+        $under = shift;
+    }
+    return $into, $under, @_;
+}
+
+sub _import {
+    return undef if $_[0] eq __PACKAGE__;
+    my ($mixin, $into, $invocant, $prefix, $vars) = @_;
+
+
+    $prefix =~ s|/+/|/|g;
+    $prefix =~ s|/$||;
+    $mixin->imported_into($prefix);
+
+    my @packages = reverse grep { $_->isa(__PACKAGE__) }
+        Class::ISA::self_and_super_path( $mixin );
+
+    foreach my $from (@packages) {
+        for my $tname (  __PACKAGE__->_templates_for($from) ) {
+            my $sname = _template_name_to_sub($tname);
+            $into->register_template(
+                "$prefix/$tname",
+                _import_code( $sname, $from, $invocant || $mixin, $vars )
+            );
+        }
+        for my $tname (  __PACKAGE__->_private_templates_for($from) ) {
+            my $sname = _template_name_to_private_sub($tname);
+            $into->register_private_template(
+                "$prefix/$tname",
+                _import_code( $sname, $from, $invocant || $mixin, $vars )
+            );
+        }
+    }
+}
+
+sub _import_code {
+    my ($sname, $from, $mixin, $vars) = @_;
+    my $code = $from->_find_template_sub( $sname );
+    return $mixin eq $from ? $code : sub { shift; $code->($mixin, @_) }
+        unless $vars;
+    return sub {
+        shift @_;  # Get rid of the passed-in "$self" class.
+        local $TEMPLATE_VARS->{$mixin} = $vars;
+        $code->($mixin, @_);
+    };
+}
+
 =head1 PITFALLS
 
 We're reusing the perl interpreter for our templating langauge, but Perl was
@@ -860,7 +1619,7 @@
     };
 
 But C<xml_decl> is a notable exception. Please always put a trailing semicolon
-after C<xml_decl { ... }>, or you'll mess up the outputs.
+after C<xml_decl { ... }>, or you'll mess up the order of output.
 
 =item *
 
@@ -931,7 +1690,7 @@
 
  <p></p>
 
-This's because C<if ( 0 )> is the last expression, so it's returned as the
+This's because C<if ( 0 )> is the last expression, so C<0> is returned as the
 value of the whole block, which is used as the content of <p> tag.
 
 To get rid of this, just put an empty string at the end so it returns empty
@@ -945,7 +1704,7 @@
 
 Crawling all over, baby. Be very, very careful. This code is so cutting edge,
 it can only be fashioned from carbon nanotubes. But we're already using this
-thing in production :) Make sure you have read the L<PITFALLS/PITFALLS>
+thing in production :) Make sure you have read the L</PITFALLS>
 section above :)
 
 Some specific bugs and design flaws that we'd love to see fixed.

Modified: Template-Declare/trunk/lib/Template/Declare/TagSet.pm
==============================================================================
--- Template-Declare/trunk/lib/Template/Declare/TagSet.pm	(original)
+++ Template-Declare/trunk/lib/Template/Declare/TagSet.pm	Fri Oct 16 16:42:36 2009
@@ -59,7 +59,7 @@
 
 Template::Declare::TagSet is the base class for declaring packages of
 Template::Delcare tags. If you need to create new tags for use in your
-temlates, this is the base class for you! Review the source code of
+templates, this is the base class for you! Review the source code of
 L<Template::Declare::TagSet::HTML|Template::Declare::TagSet::HTML> for a
 useful example.
 

Modified: Template-Declare/trunk/lib/Template/Declare/Tags.pm
==============================================================================
--- Template-Declare/trunk/lib/Template/Declare/Tags.pm	(original)
+++ Template-Declare/trunk/lib/Template/Declare/Tags.pm	Fri Oct 16 16:42:36 2009
@@ -9,23 +9,31 @@
 our $VERSION = '0.40';
 
 use Template::Declare;
-use vars qw( @EXPORT_OK $PRIVATE $self @TagSubs );
 use base 'Exporter';
 use Carp qw(carp croak);
 use Symbol 'qualify_to_ref';
 
-our @EXPORT
-    = qw( with template private show show_page attr outs
-          outs_raw in_isolation $self under
-          get_current_attr xml_decl
-          smart_tag_wrapper current_template create_wrapper );
+our $self;
+
+our @EXPORT = qw(
+    template private current_template
+    show show_page
+    attr with get_current_attr 
+    outs outs_raw
+    xml_decl
+    under setting
+    smart_tag_wrapper create_wrapper
+    $self
+);
+
 our @TAG_SUB_LIST;
+our @TagSubs;
 *TagSubs = \@TAG_SUB_LIST;  # For backward compatibility only
 
 our %ATTRIBUTES       = ();
 our %ELEMENT_ID_CACHE = ();
 our $TAG_NEST_DEPTH   = 0;
-our @TEMPLATE_STACK;
+our @TEMPLATE_STACK   = ();
 
 our $SKIP_XML_ESCAPING = 0;
 
@@ -70,7 +78,7 @@
         Template::Declare::Tags::install_tag($_, $tagset)
             for @$tag_list;
     }
-   __PACKAGE__->export_to_level(1, $self);
+    __PACKAGE__->export_to_level(1, $self);
 }
 
 sub _install {
@@ -174,14 +182,14 @@
 C<Template::Declare::TagSet::Foo>, you can load it into a template module like
 so:
 
- use Template::Declare::Tags 'Foo';
+    use Template::Declare::Tags 'Foo';
 
 If your tag set module is not under the
 L<Template::Declare::TagSet|Template::Declare::TagSet> namespace, use the
 C<from> option to load it. Fore example, if you created a tag set named
 C<MyTag::Foo>, then you could load it like so:
 
- use Template::Declare::Tags Foo => { from => 'MyTag::Foo' };
+    use Template::Declare::Tags Foo => { from => 'MyTag::Foo' };
 
 XML namespaces are emulated by Perl packages. For example, to embed HTML tags
 within XUL using the C<html> namespace:
@@ -215,7 +223,7 @@
 C<MyApp::Templates> in the previous example.
 
 There may be cases when you want to specify a different Perl package for a
-perticular XML namespace. For instance, if the C<html> Perl package has
+particular XML namespace. For instance, if the C<html> Perl package has
 already been used for other purposes in your application and you don't want to
 install subs there and mess things up, use the C<package> option to install
 them elsewhere:
@@ -247,7 +255,9 @@
 
 =head1 METHODS AND SUBROUTINES
 
-=head2 template TEMPLATENAME => sub { 'Implementation' };
+=head2 Declaring templates
+
+=head3 template TEMPLATENAME => sub { 'Implementation' };
 
     template select_list => sub {
         my $self = shift;
@@ -256,7 +266,7 @@
         }
     };
 
-Declares a template in the current package. The first agument to the template
+Declares a template in the current package. The first argument to the template
 subroutine will always be a C<Template::Declare> object. Subsequent arguments
 will be all those passed to C<show()>. For example, to use the above example
 to output a select list of colors, you'd call it like so:
@@ -298,99 +308,94 @@
             $codesub,
         );
     }
-
 }
 
-=head2 create_wrapper WRAPPERNAME => sub { 'Implementation' };
+=head3 private template TEMPLATENAME => sub { 'Implementation' };
 
-    create_wrapper basics => sub {
-        my $code = shift;
-        html {
-            head { title { 'Welcome' } };
-            body { $code->() }
+    private template select_list => sub {
+        my $self = shift;
+        select {
+            option { $_ } for @_;
         }
     };
 
-C<create_wrapper> declares a wrapper subroutine that can be called like a tag
-sub, but can optionally take arguments to be passed to the wrapper sub. For
-example, if you wanted to wrap all of the output of a template in the usual
-HTML headers and footers, you can do something like this:
+Declares that a template isn't available to be called directly from client
+code. The resulting template can instead only be called from the package in
+which it's created.
 
-    package MyApp::Templates;
-    use Template::Declare::Tags;
-    use base 'Template::Declare';
+=cut
 
-    BEGIN {
-        create_wrapper wrap => sub {
-            my $code = shift;
-            my %params = @_;
-            html {
-                head { title { outs "Hello, $params{user}!"} };
-                body {
-                    $code->();
-                    div { outs 'This is the end, my friend' };
-                };
-            }
-        };
-    }
+sub private (@) {
+    my $class   = shift;
+    my $subname = shift;
+    my $code    = shift;
+    Template::Declare::register_private_template( $class, $subname, $code );
+}
 
-    template inner => sub {
-        wrap {
-            h1 { outs "Hello, Jesse, s'up?" };
-        } user => 'Jesse';
-    };
+=head2 Showing templates
 
-Note how the C<wrap> wrapper function is available for calling after it has
-been declared in a C<BEGIN> block. Also note how you can pass arguments to the
-function after the closing brace (you don't need a comma there!).
+=head3 show [$template_name or $template_coderef], args
 
-The output from the "inner" template will look something like this:
+    show( main => { user => 'Bob' } );
 
- <html>
-  <head>
-   <title>Hello, Jesse!</title>
-  </head>
-  <body>
-   <h1>Hello, Jesse, s&#39;up?</h1>
-   <div>This is the end, my friend</div>
-  </body>
- </html>
+Displays templates. The first argument is the name of the template to be
+displayed. Any additional arguments will be passed directly to the template.
+
+C<show> can either be called with a template name or a package/object and a
+template. (It's both functional and OO.)
+
+If called from within a Template::Declare subclass, then private templates are
+accessible and visible. If called from something that isn't a
+Template::Declare, only public templates will be visible.
+
+From the outside world, users can either call C<< Template::Declare->show() >>,
+C<< show() >> exported from Template::Declare::Tags or
+C<Template::Declare::Tags::show()> directly to render a publicly visible template.
+
+Private templates may only be called from within the C<Template::Declare>
+package.
 
 =cut
 
-sub create_wrapper ($$) {
-    my $wrapper_name   = shift;
-    my $coderef        = shift;
-    my $template_class = caller;
+sub show {
+    my $template = shift;
+
+    # if we're inside a template, we should show private templates
+    if ( caller->isa('Template::Declare') ) {
+        _show_template( $template, 1, \@_ );
+        return Template::Declare->buffer->data;
+    } else {
+        show_page( $template, @_);
+    }
 
-    # Shove the code ref into the calling class.
-    no strict 'refs';
-    *{"$template_class\::$wrapper_name"} = sub (&;@) { goto $coderef };
 }
 
-=head2 private template TEMPLATENAME => sub { 'Implementation' };
+=head3 show_page
 
-    private template select_list => sub {
-        my $self = shift;
-        select {
-            option { $_ } for @_;
-        }
-    };
+    show_page( main => { user => 'Bob' } );
 
-Declares that a template isn't available to be called directly from client
-code. The resulting template can instead only be called from the package in
-which it's created.
+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.
 
 =cut
 
-sub private (@) {
-    my $class   = shift;
-    my $subname = shift;
-    my $code    = shift;
-    Template::Declare::register_private_template( $class, $subname, $code );
+sub show_page {
+    my $template = shift;
+    my $args = \@_;
+
+    Template::Declare->buffer->push(
+        private => defined wantarray,
+        from => "T::D path $template",
+    );
+    _show_template( $template, 0, $args );
+    %ELEMENT_ID_CACHE = ();
+    return Template::Declare->buffer->pop;
 }
 
-=head2 attr HASH
+=head2 Attributes
+
+=head3 attr HASH
 
     attr { src => 'logo.png' };
 
@@ -405,14 +410,6 @@
        'This is a welcoming paragraph';
     }
 
-Attributes can also be specified by using C<is>, as in
-
-    p {
-       class is 'greeting text';
-       id    is 'welcome';
-       'This is a welcoming paragraph';
-    }
-
 =cut
 
 sub attr (&;@) {
@@ -426,46 +423,70 @@
     return @_;
 }
 
-=head2 xml_decl HASH
+=head3 ATTR is VALUE
 
-    xml_decl { 'xml', version => '1.0' };
+Attributes can also be specified by using C<is>, as in
 
-Emits an XML declaration. For example:
+    p {
+       class is 'greeting text';
+       id    is 'welcome';
+       'This is a welcoming paragraph';
+    }
 
-    xml_decl { 'xml', version => '1.0' };
-    xml_decl { 'xml-stylesheet',  href => "chrome://global/skin/", type => "text/css" };
+A few tricks work for 'is':
 
-Produces:
+    http_equiv is 'foo'; # => http-equiv="foo"
+    xml__lang is 'foo';  # => xml:lang="foo"
 
- <?xml version="1.0"?>
- <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+So double underscore replaced with colon and single underscore with dash.
 
 =cut
 
-sub xml_decl (&;$) {
-    my $code = shift;
-    my @rv   = $code->();
-    my $name = shift @rv;
-    outs_raw("<?$name");
-    while ( my ( $field, $val ) = splice( @rv, 0, 2 ) ) {
-        # only defined whle in a tag context
-        outs_raw(qq/ $field="$val"/);
+# 'is' is declared later, when needed, using 'local *is::AUTOLOAD = sub {};'
+
+=head3 with
+
+    with ( id => 'greeting', class => 'foo' ),
+        p { 'Hello, World wide web' };
+
+An alternative way to specify attributes for a tag, just for variation. The
+standard way to do the same as this example using C<attr> is:
+
+    p { attr { id => 'greeting', class => 'foo' }
+        'Hello, World wide web' };
+
+=cut
+
+sub with (@) {
+    %ATTRIBUTES = ();
+    while ( my ( $key, $val ) = splice( @_, 0, 2 ) ) {
+        no warnings 'uninitialized';
+        $ATTRIBUTES{$key} = $val;
+
+        if ( lc($key) eq 'id' ) {
+            if ( $ELEMENT_ID_CACHE{$val}++ ) {
+                warn
+                    "HTML appears to contain illegal duplicate element id: $val";
+            }
+        }
+
     }
-    outs_raw("?>\n");
-    return @_;
+    wantarray ? () : '';
 }
 
-=head2 outs STUFF
+=head2 Displaying text and raw data
+
+=head3 outs STUFF
 
     p { outs 'Grettings & welcome pyoonie hyoomon.' }
 
 HTML-encodes its arguments and appends them to C<Template::Declare>'s output
 buffer. This is similar to simply returning a string from a tag function call,
-but is occaisionally useful when you need to output a mix of things, as in:
+but is occasionally useful when you need to output a mix of things, as in:
 
     p { outs 'hello'; em { 'world' } }
 
-=head2 outs_raw STUFF
+=head3 outs_raw STUFF
 
    p { outs_raw "That's what <em>I'm</em> talking about!' }
 
@@ -477,40 +498,9 @@
 sub outs     { _outs( 0, @_ ); }
 sub outs_raw { _outs( 1, @_ ); }
 
-sub _outs {
-    my $raw     = shift;
-    my @phrases = (@_);
-
-    Template::Declare->buffer->push(
-        private => (defined wantarray and not wantarray), from => "T::D outs"
-    );
-
-    foreach my $item ( grep {defined} @phrases ) {
-        my $returned = ref($item) eq 'CODE'
-            ? $item->()
-            : $raw
-                ? $item
-                : _postprocess($item);
-        Template::Declare->buffer->append( $returned );
-    }
-    return Template::Declare->buffer->pop;
-}
-
-=begin comment
-
-=head2 get_current_attr
-
-Deprecated.
-
-=end comment
-
-=cut
+=head2 Installing tags and wrapping stuff
 
-sub get_current_attr ($) {
-    $ATTRIBUTES{ $_[0] };
-}
-
-=head2 install_tag TAGNAME, TAGSET
+=head3 install_tag TAGNAME, TAGSET
 
     install_tag video => 'Template::Declare::TagSet::HTML';
 
@@ -575,39 +565,9 @@
     );
 }
 
-=head2 with
-
-    with ( id => 'greeting', class => 'foo' ),
-        p { 'Hello, World wide web' };
-
-An alternative way to specify attributes for a tag, just for variation. The
-standard way to do the same as this example using C<attr> is:
-
-    p { attr { id => 'greeting', class => 'foo' }
-        'Hello, World wide web' };
-
-=cut
-
-sub with (@) {
-    %ATTRIBUTES = ();
-    while ( my ( $key, $val ) = splice( @_, 0, 2 ) ) {
-        no warnings 'uninitialized';
-        $ATTRIBUTES{$key} = $val;
-
-        if ( lc($key) eq 'id' ) {
-            if ( $ELEMENT_ID_CACHE{$val}++ ) {
-                warn
-                    "HTML appears to contain illegal duplicate element id: $val";
-            }
-        }
-
-    }
-    wantarray ? () : '';
-}
-
-=head2 smart_tag_wrapper
+=head3 smart_tag_wrapper
 
-    # create a tag that has access to the arguments set with with.
+    # create a tag that has access to the arguments set with L</with>.
     sub sample_smart_tag (&) {
         my $code = shift;
 
@@ -625,14 +585,14 @@
 
 The output would be
 
- keys: baz, foo
- Hello, World!
+    keys: baz, foo
+    Hello, World!
 
 The smart tag wrapper allows you to create code that has access to the
 attribute arguments specified via C<with>. It passes those arguments in to the
 wrapped code in C<@_>. It also takes care of putting the output in the right
 place and tidying up after itself. This might be useful to change the behavior
-of a template based on attributs passed to C<with>.
+of a template based on attributes passed to C<with>.
 
 =cut
 
@@ -645,27 +605,169 @@
     my %attr = %ATTRIBUTES;
     %ATTRIBUTES = ();                              # prevent leakage
 
-    my $last = join '',    #
-        map { ref($_) ? $_ : _postprocess($_) }    #
+    my $last = join '',
+        map { ref($_) ? $_ : _postprocess($_) }
         $coderef->(%attr);
 
     my $content = Template::Declare->buffer->pop;
     $content .= "$last" if not length $content and length $last;
-    Template::Declare->buffer->append( $content ) ;
+    Template::Declare->buffer->append( $content );
 
     return '';
 }
 
+=head3 create_wrapper WRAPPERNAME => sub { 'Implementation' };
+
+    create_wrapper basics => sub {
+        my $code = shift;
+        html {
+            head { title { 'Welcome' } };
+            body { $code->() }
+        }
+    };
+
+C<create_wrapper> declares a wrapper subroutine that can be called like a tag
+sub, but can optionally take arguments to be passed to the wrapper sub. For
+example, if you wanted to wrap all of the output of a template in the usual
+HTML headers and footers, you can do something like this:
+
+    package MyApp::Templates;
+    use Template::Declare::Tags;
+    use base 'Template::Declare';
+
+    BEGIN {
+        create_wrapper wrap => sub {
+            my $code = shift;
+            my %params = @_;
+            html {
+                head { title { outs "Hello, $params{user}!"} };
+                body {
+                    $code->();
+                    div { outs 'This is the end, my friend' };
+                };
+            }
+        };
+    }
+
+    template inner => sub {
+        wrap {
+            h1 { outs "Hello, Jesse, s'up?" };
+        } user => 'Jesse';
+    };
+
+Note how the C<wrap> wrapper function is available for calling after it has
+been declared in a C<BEGIN> block. Also note how you can pass arguments to the
+function after the closing brace (you don't need a comma there!).
+
+The output from the "inner" template will look something like this:
+
+ <html>
+  <head>
+   <title>Hello, Jesse!</title>
+  </head>
+  <body>
+   <h1>Hello, Jesse, s&#39;up?</h1>
+   <div>This is the end, my friend</div>
+  </body>
+ </html>
+
+=cut
+
+sub create_wrapper ($$) {
+    my $wrapper_name   = shift;
+    my $coderef        = shift;
+    my $template_class = caller;
+
+    # Shove the code ref into the calling class.
+    no strict 'refs';
+    *{"$template_class\::$wrapper_name"} = sub (&;@) { goto $coderef };
+}
+
+=head2 Helpers
+
+=head3 xml_decl HASH
+
+    xml_decl { 'xml', version => '1.0' };
+
+Emits an XML declaration. For example:
+
+    xml_decl { 'xml', version => '1.0' };
+    xml_decl { 'xml-stylesheet',  href => "chrome://global/skin/", type => "text/css" };
+
+Produces:
+
+ <?xml version="1.0"?>
+ <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+=cut
+
+sub xml_decl (&;$) {
+    my $code = shift;
+    my @rv   = $code->();
+    my $name = shift @rv;
+    outs_raw("<?$name");
+    while ( my ( $field, $val ) = splice( @rv, 0, 2 ) ) {
+        outs_raw(qq/ $field="$val"/);
+    }
+    outs_raw("?>\n");
+    return @_;
+}
+
+=head3 current_template
+
+    my $path = current_template();
+
+Returns the absolute path of the current template
+
+=cut
+
+sub current_template {
+    return $TEMPLATE_STACK[-1] || '';
+}
+
+=head3 under
+
+C<under> is a helper function providing semantic sugar for the C<mix> method
+of L<Template::Declare|Template::Declare/"mix">.
+
+=cut
+
+sub under ($) { return shift }
+
+=head3 setting
+
+C<setting> is a helper function providing semantic sugar for the C<mix> method
+of L<Template::Declare|Template::Declare/"mix">.
+
+=cut
+
+sub setting ($) { return shift }
+
+=begin comment
+
+=head2 get_current_attr
+
+Deprecated.
+
+=end comment
+
+=cut
+
+sub get_current_attr ($) {
+    $ATTRIBUTES{ $_[0] };
+}
+
 sub _tag {
     my $tagset    = shift;
-    my $tag = shift;
+    my $tag       = shift;
     my $code      = shift;
     my $more_code = shift;
     $tag = $tagset->namespace . ":$tag" if defined $tagset->namespace;
 
     Template::Declare->buffer->append(
               "\n" 
-            . ( " " x $TAG_NEST_DEPTH ) . "<$tag"
+            . ( " " x $TAG_NEST_DEPTH )
+            . "<$tag"
             . join( '',
             map { qq{ $_="} . ( $ATTRIBUTES{$_} || '' ) . qq{"} }
                 sort keys %ATTRIBUTES )
@@ -686,7 +788,7 @@
             $field =~ s/_/-/g;    # http_equiv is 'bar' ====> http-equiv="bar"
 
             # Squash empty values, but not '0' values
-            my $val = join( ' ', grep { defined $_ && $_ ne '' } @_ );
+            my $val = join ' ', grep { defined $_ && $_ ne '' } @_;
 
             append_attr( $field, $val );
         };
@@ -706,7 +808,7 @@
     }
     my $content = Template::Declare->buffer->pop;
     $content .= "$last" if not length $content and length $last;
-    Template::Declare->buffer->append($attrs);
+    Template::Declare->buffer->append($attrs) if length $attrs;
 
     if (length $content) {
         Template::Declare->buffer->append(">$content");
@@ -724,69 +826,6 @@
         : '';
 }
 
-=head2 show [$template_name or $template_coderef], args
-
-    show( main => { user => 'Bob' } );
-
-Displays templates. The first agument is the name of the emplate to be
-displayed. Any additional arguments will be passed directly to the template.
-
-C<show> can either be called with a template name or a package/object and a
-template. (It's both functional and OO.)
-
-If called from within a Template::Declare subclass, then private templates are
-accessible and visible. If called from something that isn't a
-Template::Declare, only public templates wil be visible.
-
-From the outside world, users can either call C<< Template::Declare->show() >>
-or C<Template::Declare::Tags::show()> to render a publicly visible template.
-
-Private templates may only be called from within the C<Template::Declare>
-package.
-
-=cut
-
-sub show {
-    my $template = shift;
-
-    # if we're inside a template, we should show private templates
-    if ( caller->isa('Template::Declare') ) {
-        _show_template( $template, 1, \@_ );
-        return Template::Declare->buffer->data;
-    } else {
-        show_page( $template, @_);
-    }
-
-}
-
-=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.
-
-=cut
-
-sub show_page {
-    my $template = shift;
-    my $args = \@_;
-
-    if (defined wantarray) {
-        Template::Declare->buffer->push( private => 1, from => "T::D path $template" );
-        _show_template( $template, 0, $args );
-        %ELEMENT_ID_CACHE = ();
-        return Template::Declare->buffer->pop;
-    } else {
-        Template::Declare->buffer->push( from => "T::D path $template" );
-        _show_template( $template, 0, $args );
-        %ELEMENT_ID_CACHE = ();
-        Template::Declare->buffer->pop;
-        return undef;
-    }
-}
-
 sub _resolve_template_path {
     my $template = shift;
 
@@ -811,19 +850,6 @@
     return join '/', @parts;
 }
 
-=head2 current_template
-
-  my $path = current_template();
-
-Returns the absolute path of the current template
-
-=cut
-
-sub current_template {
-    return $TEMPLATE_STACK[-1] || '';
-}
-
-
 sub _show_template {
     my $template        = shift;
     my $inside_template = shift;
@@ -859,6 +885,25 @@
     return;
 }
 
+sub _outs {
+    my $raw     = shift;
+    my @phrases = (@_);
+
+    Template::Declare->buffer->push(
+        private => (defined wantarray and not wantarray), from => "T::D outs"
+    );
+
+    foreach my $item ( grep {defined} @phrases ) {
+        my $returned = ref($item) eq 'CODE'
+            ? $item->()
+            : $raw
+                ? $item
+                : _postprocess($item);
+        Template::Declare->buffer->append( $returned );
+    }
+    return Template::Declare->buffer->pop;
+}
+
 sub _postprocess {
     my $val = shift;
     my $skip_postprocess = shift;
@@ -883,16 +928,6 @@
     return $val;
 }
 
-=head2 under
-
-C<under> is a helper function providing semantic sugar for the
-C<import_templates> and C<alias> methods of
-L<Template::Declare|Template::Declare>.
-
-=cut
-
-sub under ($) { return shift }
-
 =begin comment
 
 =head2 append_attr
@@ -912,7 +947,7 @@
 
 =head1 VARIABLES
 
-=over
+=over 4
 
 =item C<@Template::Declare::Tags::EXPORT>
 
@@ -972,7 +1007,7 @@
 
 =head1 COPYRIGHT
 
-Copyright 2006-2009 Best Practical Solutions, LLC
+Copyright 2006-2009 Best Practical Solutions, LLC.
 
 =cut
 

Modified: Template-Declare/trunk/t/aliasing.t
==============================================================================
--- Template-Declare/trunk/t/aliasing.t	(original)
+++ Template-Declare/trunk/t/aliasing.t	Fri Oct 16 16:42:36 2009
@@ -8,10 +8,12 @@
 
 template 'aliased' => sub {
     my $self = shift;
-    div { outs( 'This is aliased from ' . $self ) };
+    div { outs_raw "Invocant:  '$self'" };
     div { 'Variable ', $self->package_variable('VARIABLE') };
 };
 
+private template shhhh => sub { };
+
 ##############################################################################
 package Wifty::UI::aliased_subclass_pkg;
 use base qw/Wifty::UI::aliased_pkg/;
@@ -27,7 +29,7 @@
     html {
         head {};
         body { show 'private-content'; };
-        }
+    }
 
 };
 
@@ -38,17 +40,23 @@
     };
 };
 
-
-alias Wifty::UI::aliased_pkg under '/aliased_pkg', { VARIABLE => 'SET' } ;
+alias Wifty::UI::aliased_pkg under '/aliased_pkg', setting { VARIABLE => 'SET' } ;
 alias Wifty::UI::aliased_pkg under '/aliased_pkg2';
 alias Wifty::UI::aliased_subclass_pkg under '/aliased_subclass_pkg';
 
 ##############################################################################
 package main;
 use Template::Declare::Tags;
+
+# Alias from outside the class.
+alias Wifty::UI::aliased_pkg into Wifty::UI, under '/aliased_pkg3';
+# And reverse.
+alias Wifty::UI::aliased_pkg under '/aliased_pkg4', into Wifty::UI
+
+# Fire it up.
 Template::Declare->init( dispatch_to => ['Wifty::UI'] );
 
-use Test::More tests => 19;
+use Test::More tests => 30;
 require "t/utils.pl";
 
 ok( Wifty::UI::aliased_pkg->has_template('aliased'), 'Aliased package should have template' );
@@ -56,7 +64,7 @@
 ok( Wifty::UI::aliased_subclass_pkg->has_template('aliased'), 'Subclass should' );
 
 ok( Template::Declare->has_template('aliased_pkg/aliased'), 'TD should find alias' );
-
+ok( Template::Declare->has_template('aliased_pkg2/shhhh', 1), 'TD should find private mix' );
 
 ok( Template::Declare->has_template('aliased_subclass_pkg/aliased'),
     'Alias should be visible in a subclass, too' );
@@ -64,9 +72,9 @@
 {
     # Try the first alias with a variable set.
     ok my $simple = ( show('aliased_pkg/aliased') ), 'Should get output from alias template';
-    like( $simple, qr'This is aliased', 'Its output should be right' );
+    like( $simple, qr'Invocant:', 'Its output should be right' );
     like( $simple, qr'Variable SET' , "The variable was set");
-    like( $simple, qr'Wifty::UI::aliased_pkg',
+    like( $simple, qr{'Wifty::UI::aliased_pkg'},
         '$self is correct in template block' );
     ok_lint($simple);
 }
@@ -74,9 +82,29 @@
 {
     # Try the second alias with no variable.
     ok my $simple = ( show('aliased_pkg2/aliased') ), 'Should get output from second alias';
-    like( $simple, qr'This is aliased', 'Its output should be right' );
+    like( $simple, qr'Invocant:', 'Its output should be right' );
+    unlike( $simple, qr'Varialble SET' , 'But the variable should not be set');
+    like( $simple, qr{'Wifty::UI::aliased_pkg'},
+        '$self is correct in template block' );
+    ok_lint($simple);
+}
+
+{
+    # Try the third alias using `into`.
+    ok my $simple = ( show('aliased_pkg3/aliased') ), 'Should get output from third alias';
+    like( $simple, qr'Invocant:', 'Its output should be right' );
+    unlike( $simple, qr'Varialble SET' , 'But the variable should not be set');
+    like( $simple, qr{'Wifty::UI::aliased_pkg'},
+        '$self is correct in template block' );
+    ok_lint($simple);
+}
+
+{
+    # Try the fourth with `into` and `under` reversed.
+    ok my $simple = ( show('aliased_pkg4/aliased') ), 'Should get output from fourth alias';
+    like( $simple, qr'Invocant:', 'Its output should be right' );
     unlike( $simple, qr'Varialble SET' , 'But the variable should not be set');
-    like( $simple, qr'Wifty::UI::aliased_pkg',
+    like( $simple, qr{'Wifty::UI::aliased_pkg'},
         '$self is correct in template block' );
     ok_lint($simple);
 }
@@ -86,12 +114,12 @@
         'Should get output from superclass template';
     like(
         $simple,
-        qr'This is aliased',
+        qr'Invocant:',
         "We should get the aliased version in the subclass"
     );
     like(
         $simple,
-        qr'Wifty::UI::aliased_subclass_pkg',
+        qr{'Wifty::UI::aliased_subclass_pkg'},
         '$self is correct in template block'
     );
     ok_lint($simple);

Modified: Template-Declare/trunk/t/dispatch_order.t
==============================================================================
--- Template-Declare/trunk/t/dispatch_order.t	(original)
+++ Template-Declare/trunk/t/dispatch_order.t	Fri Oct 16 16:42:36 2009
@@ -27,7 +27,8 @@
 
 ##############################################################################
 package main;
-use Test::More tests => 16;
+use Test::More tests => 24;
+#use Test::More 'no_plan';
 
 # Check template resolution with the deprecated `roots` parameterx.
 ok !Template::Declare->init( roots => ['Wifty::Foo', 'Wifty::Bar'] ),
@@ -77,7 +78,7 @@
     'Bip should now have precedence';
 
 ##############################################################################
-# Now try the dame stuff with aliases.
+# Now try the same stuff with aliases.
 ##############################################################################
 package Mifty::Foo;
 use base qw/Template::Declare/;
@@ -134,3 +135,137 @@
 
 is +Template::Declare->show('hello'), 'hello from Bip',
     'Mifty::Bip should now have precedence';
+
+##############################################################################
+# Now try the same stuff with mixes.
+##############################################################################
+package Sifty::Foo;
+use base qw/Template::Declare/;
+use Template::Declare::Tags;
+template hello => sub { outs 'hello from Foo' };
+
+##############################################################################
+package Sifty::Bar;
+use base qw/Template::Declare/;
+use Template::Declare::Tags;
+template hello => sub { outs 'hello from Bar' };
+
+##############################################################################
+package Sifty::Baz;
+use base qw/Template::Declare/;
+use Template::Declare::Tags;
+template hello => sub { outs 'hello from Baz' };
+
+##############################################################################
+package Sifty::Bip;
+use base qw/Template::Declare/;
+use Template::Declare::Tags;
+template hello => sub { outs 'hello from Bip' };
+
+##############################################################################
+# Import the Baz templates into Bar.
+package Sifty::Bar;
+mix Sifty::Baz under '/';
+
+##############################################################################
+package main;
+ok !Template::Declare->init( dispatch_to => ['Sifty::Foo', 'Sifty::Bar'] ),
+    'init to dispatch to Sifty::Foo and Sifty::Bar';
+
+is +Template::Declare->show('hello'), 'hello from Foo',
+    'Sifty::Foo should have precedence';
+
+##############################################################################
+# Import the Baz templates into Foo.
+package Sifty::Foo;
+import_templates Sifty::Baz under '/';
+
+##############################################################################
+package main;
+ok !Template::Declare->init( dispatch_to => ['Sifty::Foo', 'Sifty::Bar'] ),
+    'init to dispatch to Sifty::Foo and Sifty::Bar again';
+
+is +Template::Declare->show('hello'), 'hello from Baz',
+    'Sifty::Baz::hello should have replaced Sifty::Foo::hello';
+
+# Now dispatch only to Bip and Foo.
+ok !Template::Declare->init( dispatch_to => ['Sifty::Bip', 'Sifty::Foo'] ),
+    'init to dispatch to Sifty::Bip and Sifty::Foo';
+
+is +Template::Declare->show('hello'), 'hello from Bip',
+    'Sifty::Bip should now have precedence';
+
+##############################################################################
+# Doc example.
+    package MyApp::UI::Standard;
+    use Template::Declare::Tags;
+    use base 'Template::Declare';
+
+    template image => sub {
+        my ($self, $src, $title) = @_;
+        img {
+            src is $src;
+            title is $title;
+        };
+    };
+
+    package MyApp::UI::Standard;
+    use Template::Declare::Tags;
+    use base 'Template::Declare';
+
+    template image => sub {
+        my ($self, $src, $title, $caption) = @_;
+        div {
+            class is 'std';
+            img {
+                src is $src;
+                title is $title;
+            };
+            p {
+                class is 'caption';
+                outs $caption;
+            };
+        };
+    };
+
+##############################################################################
+    package MyApp::UI::Formal;
+    use Template::Declare::Tags;
+    use base 'Template::Declare';
+
+    template image => sub {
+        my ($self, $src, $title, $credit, $caption) = @_;
+        div {
+            class is 'formal';
+            img {
+                src is $src;
+                title is $title;
+            };
+            p {
+                class is 'credit';
+                outs "Photo by $credit";
+            };
+            p {
+                class is 'caption';
+                outs $caption;
+            };
+        };
+    };
+
+##############################################################################
+package main;
+    my @template_classes = 'MyApp::UI::Standard';
+    Template::Declare->init( dispatch_to => \@template_classes );
+    is +Template::Declare->show('image', 'foo.png', 'Foo'), q{
+<div class="std">
+ <img src="foo.png" title="Foo" />
+ <p class="caption"></p>
+</div>}, 'Should get standard image output';
+
+    unshift @template_classes, 'MyApp::UI::Formal';
+    is +Template::Declare->show('image', 'ap.png', 'AP Photo', 'Clark Kent', 'Big news'), q{
+<div class="formal">
+ <img src="ap.png" title="AP Photo" />
+ <p class="credit">Photo by Clark Kent</p>
+ <p class="caption">Big news</p>
+</div>}, 'Should get formal image output';

Modified: Template-Declare/trunk/t/importing.t
==============================================================================
--- Template-Declare/trunk/t/importing.t	(original)
+++ Template-Declare/trunk/t/importing.t	Fri Oct 16 16:42:36 2009
@@ -8,7 +8,7 @@
 
 template 'imported' => sub {
     my $self = shift;
-    div { outs( 'This is imported from ' . $self ) };
+    div { outs_raw "Invocant: '$self'" };
 };
 
 ##############################################################################
@@ -22,7 +22,7 @@
 use Template::Declare::Tags;
 
 template simple => sub {
-
+    print '# ', ref +shift, $/;
     html {
         head {};
         body { show 'private-content'; };
@@ -92,22 +92,21 @@
 
 {
     ok my $simple = ( show('imported_pkg/imported') ), 'Should get output for imported template';
-    like( $simple, qr'This is imported', 'Its output should be correct' );
-    like( $simple, qr'Wifty::UI', '$self is correct in template block' );
+    like( $simple, qr'Invocant:', 'Its output should be correct' );
+    like( $simple, qr{'Wifty::UI'}, '$self is correct in template block' );
     ok_lint($simple);
 }
-
 {
     ok my $simple = ( show('imported_subclass_pkg/imported') ),
         'Should get output from imported template from subclass';
     like(
         $simple,
-        qr'This is imported',
+        qr'Invocant:',
         "We got the imported version in the subclass"
     );
     like(
         $simple,
-        qr'Wifty::UI',
+        qr{'Wifty::UI'},
         '$self is correct in template block'
     );
     ok_lint($simple);

Modified: Template-Declare/trunk/t/smart_tag_wrapper.t
==============================================================================
--- Template-Declare/trunk/t/smart_tag_wrapper.t	(original)
+++ Template-Declare/trunk/t/smart_tag_wrapper.t	Fri Oct 16 16:42:36 2009
@@ -33,7 +33,7 @@
 use Template::Declare::Tags;
 Template::Declare->init( dispatch_to => ['Wifty::UI'] );
 
-use Test::More tests => 2;
+use Test::More tests => 4;
 require "t/utils.pl";
 
 my $simple = show('simple');
@@ -50,3 +50,47 @@
       . "\nSTART \nsecond\nEND\n",      #
     "got correct output for simple"
 );
+
+##############################################################################
+# Documentation example.
+    package My::Template;
+    use Template::Declare::Tags;
+    use base 'Template::Declare';
+
+    sub myform (&) {
+        my $code = shift;
+
+        smart_tag_wrapper {
+            my %params = @_; # set using 'with'
+            form {
+                attr { %{ $params{attr} } };
+                $code->();
+                input { attr { type => 'submit', value => $params{value} } };
+            };
+        };
+    }
+
+    template edit_prefs => sub {
+        with(
+            attr  => { id => 'edit_prefs', action => 'edit.html' },
+            value => 'Save'
+        ), myform {
+            label { 'Time Zone' };
+            input { type is 'text'; name is 'tz' };
+        };
+    };
+
+    package main;
+    Template::Declare->init( dispatch_to => ['My::Template'] );
+
+ok my $output = Template::Declare->show('edit_prefs'), 'Get edit_prefs output';
+is(
+    $output,
+    qq{
+
+<form action="edit.html" id="edit_prefs">
+ <label>Time Zone</label>
+ <input type="text" name="tz" />
+ <input type="submit" value="Save" />
+</form>}, "got correct output for simple"
+);


More information about the Jifty-commit mailing list