[% META book = 'Release' page = 'TODO' %]

    #========================================================================
    #
    # TODO
    #
    # DESCRIPTION
    #   TODO list for the Template Toolkit version 2.01, containing
    #   known bugs, limitations, planned enhancements, long term visions
    #   and a few whacky ideas.
    #
    # AUTHOR
    #   Andy Wardley   <abw@kfs.org>
    #
    #------------------------------------------------------------------------
    # $Id: TODO.tt2,v 1.1 2001/03/29 22:10:51 abw Exp $
    #========================================================================

    #------------------------------------------------------------------------
    # Miscellaneous
    #------------------------------------------------------------------------

    * Fix stringification problem identified by SAM.  Objects that have
      auto-stringification sometimes don't get properly stringified at the
      right time.  Need to check with SAM exactly what the problem is.

    * The 'eval' filter leaks memory, as reported by Colin Johnson.  The
      filter subroutine created contains a reference to the context and then
      gets cached in the FILTER_CACHE item of the context.  Hey presto -
      circular references.  The reset() method should probably clear the
      FILTER_CACHE.  Also need to check the plugins cache for similar
      problems.

    * default DELIMITER should be defined as a package var somewhere.  It's
      currently hardcoded in Template::Parser and Template::Context.  This
      causes a problem on Win32 machine trying to use explicit paths.

    * If you use 'ttree' with a COMPILE_EXT or COMPILE_DIR option then
      templates in the 'lib' directories will be compiled, but those in
      the src directories will not.  This is because ttree does a chdir()
      to the src directory and processes files as './myfile'.  TT doesn't
      compile RELATIVE files by default.

    * No recursion checking is performed for BLOCKs, only
      Template::Document instances.  This is probably the way it will stay
      (unless anyone shouts loudly enough) but it should be documented
      anyway.  STOP PRESS: I had an idea that bare BLOCK subs should be
      blessed into Template::Document class to allow $template->process()
      to be called regardless.  Template::Document methods would need to
      test $self for CODE/HASH and Do The Right Thing.  This would then
      allow recursion testing for BLOCKs as well as Template::Document
      objects.

    * A ':preload' use option to Template.pm to preload all modules?  Or
      should it be ':noload' and have them preloaded by default?

    * It should be possible to access template BLOCK definitions via the
      'template' variable.  This would be particularly useful in conjunction
      with the PRE_PROCESS, PROCESS and/or POST_PROCESS options, e.g.

        <table>
        <tr>
          <td>[% tt_start_tag %] INCLUDE $template.blocks.sidebar [% tt_end_tag %]</td>
          <td>[% tt_start_tag %] INCLUDE $template [% tt_end_tag %]
        </tr>
        </table>

      Currently you *can* access these blocks, but the stash automatically
      calls these unblessed subs, generating an error due to the fact that
      no context reference is passed to the sub to allow it to act as a
      template.

    * It would be useful if template components had some notion of inheritance
      so that a 'derived' component could call on the 'super' component.
      This is something that is hacked in as part of the VIEW feature, but
      should be properly added as a facility.

    * The issue of CGI::Carp throwing non-reference error might need closer
      investigation.

    #------------------------------------------------------------------------
    # Documentation
    #------------------------------------------------------------------------

    * Add the XML tutorial, kindly donated by Dave Cross.

    * Extend the FAQ.

    * Document the Splash! library properly, once the interface is a little
      more settled.

    * Various bits of the documentation like Changes, TODO, FAQ, etc., should
      be built from XML files.

    * Examples for libraries (HTML, Splash & PostScript) should be integrated
      into the documentation.

    #------------------------------------------------------------------------
    # Directives
    #------------------------------------------------------------------------

    * A 'FOR', like 'FOREACH' but without using an iterator.  You wouldn't get
      the 'loop' reference to test 'first', 'last', etc., against, but it would
      be faster for those cases when you didn't need it.  This will likely
      be implemented as a facility feature (see later).

    * PRINT should be defined as a new directive, doing what the print()
      method of Template::View currently does (the Right Thing).

        [% tt_start_tag %] PRINT node [% tt_end_tag %]    ===    [% tt_start_tag %] tt.view.print(node) [% tt_end_tag %]

      NOTE TO SELF: this is a Very Good Idea [tm].  PRINT becomes the way to
      display a data structure (e.g. hash, list, XML element, MyThingy, database
      record, etc.) in an "intelligent" fashion.  Implemented underneath via
      the current default VIEW.

    * ARGS.  There may be a requirement for reusable template components
      to define what variables they plan to use.  This would allow some
      optimisation and also possibly help to avoid global variable clashes.
      Would also be a useful "comment" directive for human readers and maybe
      also help in debugging (WARNING: expected 'title' argument).

        [% tt_start_tag %] ARGS title		# no default
    	    bgcol='#ffffff'	# default value
        [% tt_end_tag %]

    #------------------------------------------------------------------------
    # Stash
    #------------------------------------------------------------------------

    * Stas Bekman raised the issue of the Stash not being able to correctly
      differentiate between scalar/list context and in particular, the
      cgi.param examples not working as expected.

    * Richard Tietjen's patch for stash replace.  Allows back references
      (e.g. $1) but it would be nice to find a rock-solid way to implement
      it without relying on unusual ^A delimiter character.

    * Have stash, etc., add current template name/line when reporting errors.
      (may be tricky under the current implementation)

    * I've written a version of Template::Stash in XS which should give a
      significant speedup to the runtime processing.  It's 95% complete
      (but hasn't been updated to keep up with more recent changes to the
      stash) and just needs some minor debugging and testing.  The new
      Template::Stash will automatically load the existing Perl version if
      you don't have a C compiler on your platform (shame on you!).

    #------------------------------------------------------------------------
    # Parser
    #------------------------------------------------------------------------

    * Lists don't accept arbitrary expressions as elements.  In other words
      you can't do this:   [% tt_start_tag %] foo(bar + 1) [% tt_end_tag %]

    * Stas reported a problem with spacing, something like : [% tt_start_tag %] a =b+10 [% tt_end_tag %] but
      I can't seem to reproduce it (or remember exactly what the problem
      was... I need to check the archives for his email).

    * The parser isn't as intelligent as it could be about blocks of template
      code commented out en masse.  The pre-scanner find the first terminating
      END_TAG after an opening tag, regardless of it being on a
      commented line or not.
      e.g.
        [% tt_start_tag %]#
          #
          #  [% tt_start_tag %] INCLUDE blah [% tt_end_tag %] <- directive ends here
          #  foo                <- this gets printed
        [% tt_end_tag %]

    * Allow { and } as block delimiters, replacing for the ugly ';' and
      big, chunky [% tt_start_tag %] END [% tt_end_tag %] approach.

      e.g. something like:

        [% tt_start_tag %] FOREACH a = [ 1 2 3 ] [% tt_end_tag %]
           [% tt_start_tag %] IF b == a [% tt_end_tag %]
    	  [% tt_start_tag %] INCLUDE foo [% tt_end_tag %]
           [% tt_start_tag %] ELSE [% tt_end_tag %]
    	  [% tt_start_tag %] INCLUDE bar [% tt_end_tag %]
           [% tt_start_tag %] END [% tt_end_tag %]
        [% tt_start_tag %] END [% tt_end_tag %]

       could be written as:

        [% tt_start_tag %]	FOREACH a = [ 1 2 3 ] {
    	    IF b == a {
    		INCLUDE foo
    	    }
    	    ELSE {
    		INCLUDE bar
    	    }
    	}
        [% tt_end_tag %]

    * Make IF, FOR, WHILE, etc., available in lower case by default (or by
      configuration option).  I think any constructs like these which map
      to regular programming language constructs (i.e. can be translated
      directly to Perl) shouldn't have to stick out like a sore thumb.
      UPPER CASE should be reserved for DIRECTIVES which actuate a
      facility feature.  Lower case is used for the very restricted set of
      reserved words that implement the language framework (if, while,
      for, else, try, catch, and, or, not, etc.).  FOREACH should probably
      be a directive as it invokes an iterator ("for" would be a fast
      implementation which has no 'loop' iterator).

        [% tt_start_tag %]	for a = [ 1 2 3 ] {
    	    if b == a {
    		INCLUDE foo
    	    }
    	    else {
    		INCLUDE bar
    	    }
    	}
        [% tt_end_tag %]

    * The above point implies a general rule of lower case words being
      runtime variables or one of a small number of reserved words,
      and UPPER CASE being compile time directives which perform some
      rewriting (e.g. code generation).

        [% tt_start_tag %] INCLUDE filename a='b', c='d' [% tt_end_tag %]

      is a compile time directive (UPPER CASE) which calls a sub to do the
      code generation of:

        $output .= $context->include('filename', { a => 'b', c => 'd' });

      the above directive is therefore also equivalent to:

        [% tt_start_tag %] tt2.include('filename', a='b', c='d') [% tt_end_tag %]

    * We might want to tie the above in with namespaces.  This
      would permit disambiguation of directives loaded from different
      facilities.

        [% tt_start_tag %] TT2.INCLUDE ... [% tt_end_tag %]   # UPPER == COMPILE TIME
        [% tt_start_tag %] SQL.QUERY ... [% tt_end_tag %]

       vs			    # rewritten to...

        [% tt_start_tag %] tt2.include(...) [% tt_end_tag %]  # lower == runtime
        [% tt_start_tag %] sql.query(...) [% tt_end_tag %]

       What about the DBI plugin (for example):

        [% tt_start_tag %] USE DBI(...) [% tt_end_tag %]
        [% tt_start_tag %] DBI.query [% tt_end_tag %]

       We can't assume that CAPITAL implies compile time in this case
       unless we look at the method (i.e. second element) not the first,
       and that's too  confusing. IMHO.  Maybe use ':' instead as the compile
       time directive delimiter?

        [% tt_start_tag %] TT2:INCLUDE ... [% tt_end_tag %]

      Or maybe 'TT2' is the universal prefix into which facilties are loaded?

        [% tt_start_tag %] TT2.VIEW.INCLUDE ... [% tt_end_tag %]
    	  => $view->include(...) === [% tt_start_tag %] tt2.view.include(...) [% tt_end_tag %]
        [% tt_start_tag %] TT2.SQL.INCLUDE [% tt_end_tag %]
    	  => $sql->include(...) === [% tt_start_tag %] tt2.sql.include(...) [% tt_end_tag %]

    * Ability to set different parser options for BLOCK definitions, etc.

        [% tt_start_tag %] BLOCK header
             eval_perl = 0
             pre_chomp = 1
        [% tt_end_tag %]
           ...
        [% tt_start_tag %] END [% tt_end_tag %]

      Anonymous BLOCK can then be used to set a parser scope

        [% tt_start_tag %] BLOCK trim=1 [% tt_end_tag %]
           ...
        [% tt_start_tag %] END [% tt_end_tag %]

        [% tt_start_tag %] BLOCK trim=0 [% tt_end_tag %]
           ...
        [% tt_start_tag %] END [% tt_end_tag %]

      And/or set different tag styles, etc.

        [% tt_start_tag %] BLOCK tags='star' [% tt_end_tag %]
           [* INCLUDE this_is_a_directive *]
           [% tt_start_tag %] INCLUDE this_is_not [% tt_end_tag %]
        [* END *]

        [% tt_start_tag %] INCLUDE back_to_normal [% tt_end_tag %]

      This will require some fairly serious work on the parser.
      Some experimentation underway, see P2.pm - got half a lexer working.

    * Note that this might also allow a default view to be set for a BLOCK:

        [% tt_start_tag %] BLOCK document view=my.view.pod [% tt_end_tag %]
           ...
        [% tt_start_tag %] END [% tt_end_tag %]

      Being able to set a default VIEW is another issue altogether.  In
      many ways it's orthogonal to the definition of VIEWs which is
      discussed below.  It should be fairly straightforward as there
      aren't that many issues to consider (syntax perhaps being the only
      major one) but I haven't really considered them yet so watch this
      space for details.

    #------------------------------------------------------------------------
    # Plugins
    #------------------------------------------------------------------------

    * We need a way to easily enable/disable certain plugins.  This should
      be addressed by facility provision.

    * The Text::Autoformat module has some problems with versions of Perl
      prior to 5.6.0 when using a locale which has a decimal separator
      other than '.' (e.g. Swedish, which uses ',').  Damian has been made
      aware of the problem (and I note he now has a new version out which
      I need to check).  For now, the Makefile.PL issues a warning but
      continues regardless.

    * The Template::Plugin DBI iterator first/last() methods don't behave
      the same as list first/last().  Randal also reports that get_all()
      doesn't work as it should - may be a conflict in code/docs?

    * PLUGINS could accept a reference to an object which is used as a
      singleton factory for a plugin.  (NOTE: 2.01 includes PLUGIN_FACTORY
      to implement this, but currently undocumented because it's likely to
      change).

    * Add Leo & Leon's Page plugin, or try to find some way of implementing
      it in terms of the Table plugin.  I think the jury is still out on the
      matter of whether it counts as duplicated functionality.

    * The childrenTotemplate() and allChildrenToTemplate() methods of the
      XML::DOM can send Perl into a deep recursive loop.  In fact, the the
      XML::DOM module itself seems to be a little unstable in general -
      I've had to disable one of the tests in t/dom.t which tests the
      parser creation failing, as it seems to be causing a segfault core
      dump during global cleanup a the end of the script.  The
      toTemplate() method and friends will be replaced by the VIEW
      facility (in some form).  Rather than build functionality into
      XML::DOM to present a data structure via the TT, it will be the
      print() method of a VIEW which walks the tree and processes the
      appropriate template.  It's difficult to explain simply in a few
      words, but suffice it to say that it's very clever, extremely powerful
      and deceptively easy to use.  Big wins all around.  See next item...

    * A related problem to the above is that the XML::XPath plugin doesn't
      have a toTemplate() method, or something similar, to allow easy
      conversion of mixed XML content via template elements.  And because
      of the way that Matt's implemented the XPath module (to cleverly
      avoid circular references) I'm not sure there's an easy/obvious way
      to add one.  The solution comes as part of the VIEW model.  A
      generic PerlSAX -> VIEW interface should be provided, making it
      possible to easily display XML content from XML::DOM, XML::XPath, or
      any other SAX compliant source.

      Something like this:

        # define a view
        [% tt_start_tag %] VIEW my_view
             prefix="my/xml/dom/path/" ;
           END
        [% tt_end_tag %]

        # get some XML
        [% tt_start_tag %] USE dom = XML.DOM [% tt_end_tag %]
        [% tt_start_tag %] doc = dom.parser(my.files.xmldata) [% tt_end_tag %]

        # ask the view to print the data
        [% tt_start_tag %] my_view.print(doc) [% tt_end_tag %]

      The view print() method will call the relevant 2SAX method on the
      XML node, passing a SAX2TTView handler to make the relevant calls
      back to the view to display parts of the XML data model as SAX events
      are received.

    #------------------------------------------------------------------------
    # Views
    #------------------------------------------------------------------------

    The current implementation is there to get me (and anybody else who's
    interested) using it and trying to identify the problems, requirements
    and general issues involved.  I've got a better idea now about what a
    VIEW should be in notional terms, but I'm still not quite sure about
    the syntax and API.

    General thoughts:

    * A view defines a set of templates.  Things like prefix, suffix,
      default, etc., can be specified to customise template selection.
      In this sense, it is like a custom provider of those templates.
      It implements the template() method to fetch a template according
      to those rules.

    * It is also a custom processor of those templates.  It implements the
      process() method.  In this sense, it is like a custom context.

    * It also implements dispatch logic to apply the right template to the
      right kind of data.  It does this via the print() method.  It may
      have all kinds of custom dispatch logic.

    * A view takes responsiblity for things template related as opposed
      to anything data related (stash) or application logic related
      (plugins, runtime code, etc).  It is the user interface facility
      within the engine.

    #------------------------------------------------------------------------
    # Splash!
    #------------------------------------------------------------------------

    The current implementation is a fairly ugly hack to get something up
    and running that's good enough to use.  It's mainly template driven
    and doesn't scale very well, particularly with global variables
    clashing all over the place.  My plan is that this will become a
    view-based system and will no doubt be a test-bed for the
    implementation of the view facility.

    To include:

    * Variable management for storing metadata relating to an
      interface/view, protected from the rest of template space.

    * Also, style management for defining different styles (e.g. plain,
      fancy,  icecold, whitehot) for different interface elements (e.g.
      bars, borders, menu text) in different modes (e.g. selected, unselected),
      or under different, possibly custom conditions (e.g. user preferences,
      guest or logged in, etc.).

    * Clearly define API for different elements, allowing people to write
      apps to the API which run across different conformant widget sets.

    * support wider range of colours and general theme elements

    * note that more colours, etc., means more images.  Even though each is
      tiny, being less than 1k each, they soon add up.  Thus may be wise to
      move Splash out to a separate distribution.

    #------------------------------------------------------------------------
    # Test Suite
    #------------------------------------------------------------------------

    * t/xpath.t makes some silly platform-dependant assumptions about what
      kind of error message gets returned when a file isn't found.  Reported
      by <umun@yahoo.com>.

    #------------------------------------------------------------------------
    # Facilities
    #------------------------------------------------------------------------

    Core facilities currently implemented by Template::Context should be
    moved out into separate facilities.  These currently fall into the
    categories of things like stash, view, plugins, filters, parser and
    maybe some others.  (NOTE: this might tie in very closely with Camelot
    and the resource/presenter/actor breakdown, aka model/view/controller).

    * 'view' would handle template fetching and processing.  It is the view
      that talks to a provider, possibly adding special prefixes, suffixes,
      doing default templates, special dispatch logic, etc.

    * 'stash' is responsible for storing variables, as it currently is.

    * 'plugins' is responsible for fetching plugins.

    * 'filters' is responsible for fetching filters.

    * maybe both the above would get bundled into something like 'logic'?

    * 'parser' would make parts of the parser accessible

    * 'output' could be used to generate output

    There would be some facility to install, customise and remove facilities
    to modify TT behaviour as required.  This would allow us to disable
    certain plugins, or remove the plugin facility altogether, for example.
    Or we could install a new stash facility which generated a different kind
    of code (e.g. less magic, more speed).  Or install a new custom facility
    to do some application or domain specific task.

    Facilities should be accessible via the context:

        my $stash = $context->stash();	# currently works
        my $view  = $context->view();	# not yet

    General form:

        my $xyz = $context->facility('xyz');

    Multiple form:

        my ($a, $b, $c) = $context->facility(qw[ a b c ]);

    This can then be written into generated code pretty much as the stash
    currently is.  The facilities would define the code generators that
    currently clutter up Template::Directives.  They would ensure that the
    facility is scheduled to be requested from the context at the start of
    the sub:

        sub {
    	my $context = shift;
    	my ($stash, $view) = $context->faciity(qw( stash view ));

    and then transform the various directives into appropriate callbacks
    into the facility:

    	$output .= $stash->get('x');
    	$output .= $view->process('header');

    The context becomes a switching centre for the Template Toolkit, with
    most, if not all of its existing functionality moved out to
    facilities.  The context should acquire all facilities at the start of
    a process lifecycle, run the template, and then release them all
    again.  This should all be done according to the process contract
    which specifies which facilities should be installed, which can be
    modified, what can and can't be be loaded, and so on.  The
    contract would also define things like PRE_PROCESS templates, error
    handling, etc.

    Thus the role of Template::Service is to undertake a contract with the
    client and attempt to fulfill it.  A Template::Contract defines the
    terms of the contract and the Template::Context becomes an embodiment
    (runtime instance) of a contract.

    The current context would be available as the 'tt2' template variable,
    with facilities available as object methods.  Thus, the following become
    possible:

        [% tt_start_tag %] tt2.stash.get('foo') [% tt_end_tag %]		# [% tt_start_tag %] foo [% tt_end_tag %]
        [% tt_start_tag %] tt2.view.process('header') [% tt_end_tag %]	# [% tt_start_tag %] PROCESS header [% tt_end_tag %]
        [% tt_start_tag %] tt2.parser.start_tag [% tt_end_tag %]		# can't do this currently

    Directives would be re-written into code like that above.  You can
    use the 'tt2.facility.whatever' form when directive syntax would
    otherwise get in the way:

        [% tt_start_tag %] mycode( header = tt2.view.process('my/fancy/header'),
    	       footer = tt2.view.process('your/dull/footer') ) [% tt_end_tag %]

    Or to explicitly disambiguate:

        [% tt_start_tag %] tt2.stash.get('foo.size') [% tt_end_tag %]	# object method
        [% tt_start_tag %] tt2.stash.list.size(foo) [% tt_end_tag %]	# virtual method
        [% tt_start_tag %] foo.size [% tt_end_tag %]			# lucky dip  :-)

    Facility management would itself be a facility.  Thus, to disable runtime
    facility loading, you would simply unload (or not load) the facility
    management facility.

        [% tt_start_tag %] tt2.facility.install(module='my_facility', name='foo') [% tt_end_tag %]
        [% tt_start_tag %] tt2.foo.bar(123) [% tt_end_tag %]

    Note that there are some issues relating to cross-cutting facilities,
    otherwise known as "aspects" (see Aspect Oriented Programming).  For
    example, variable localisation cross cuts views and data management
    (i.e. tt2.view.include('header', title='my title') must first localise
    the stash and delocalise it again afterwards).  It may be appropriate
    to install aspects as separate entities (e.g. 'localisation') which
    can be invoked to apply cross cutting concerns in a generic way.
    Perhaps aspects are implemented as their own facility?

        [% tt_start_tag %] tt2.aspect.localise [% tt_end_tag %] ... [% tt_start_tag %] tt2.aspect.delocalise [% tt_end_tag %]
    or
        [% tt_start_tag %] aspect = tt2.aspect.localise [% tt_end_tag %]   # cloned & specialised context
        [% tt_start_tag %] aspect.view.process('header', title='my title') [% tt_end_tag %]
    or
        ...

    Another example would be debugging:

        [% tt_start_tag %] tt2dbg = tt2.aspect.debug(...params...) [% tt_end_tag %]
        [% tt_start_tag %] tt2dbg.view.process('header') [% tt_end_tag %]
    or:
        [% tt_start_tag %] tt2 = tt2.aspect.debug(...) [% tt_end_tag %]
    	...
        [% tt_start_tag %] tt2 = tt2.release [% tt_end_tag %]

    #------------------------------------------------------------------------
    # Output
    #------------------------------------------------------------------------

    It should be possible to stack output buffers.  In other words, you
    stop writing to the current output buffer and open a new buffer and
    start writing to that.  The final output is simply the concatenation
    of all output buffers.

    The clever part of all this is that is should be possible to keep a
    handle on an earlier buffer and go back and append to it at some point
    in the future.  A typical use is for generating tables of contents at
    the start of a document when you don't know in advance what the document
    contains.  Simply push a new output buffer at the point of the TOC,
    generate the rest of the document (keeping track of all the section
    titles, etc) and at the end of the document, go back and generate the
    TOC onto the end of the first buffer.

    Haven't decided on any syntax yet, but it will almost certainly be
    implemented as a facility.  At the lowest level, something like
    this perhaps:

        [% tt_start_tag %] INCLUDE header [% tt_end_tag %]	  # write content to first buffer

        [% tt_start_tag %] toc = tt2.output.push [% tt_end_tag %]   # save current buffer as toc

        Blah blah blah		  # write content to second buffer

        [% tt_start_tag %] INCLUDE footer [% tt_end_tag %]

        [% tt_start_tag %] tt2.output.buffer = toc [% tt_end_tag %] # re-instate first buffer

        This is the TOC		  # append to first buffer

    The output stack would look something like this:

        +-----------------+
        | <header>        |
        | This is the TOC |
        +-----------------+
                 |
                 V
        +-----------------+
        | Blah blah blah  |
        | <footer>        |
        +-----------------+

    Which to the end user, would silently be concatenated into:

        <header>
        This is the TOC
        Blah blah blah
        <footer>

    Another use is to ensure dependencies on other templates get resolved.
    For example, many of the PostScript library templates rely on other
    templates.  At present, each template sets a global variable to
    say "I've been loaded" while also inspecting these variables for any
    templates that it relies on, loading them via INCLUDE/PROCESS if not
    set.  e.g. ps/cross:

        [% tt_start_tag %]  # this works, but it's a bit clunky
            DEFAULT radius = '5 mm';
            PROCESS ps/mm UNLESS global.ps.loaded.mm;
            global.ps.loaded.cross = 1;
        -[% tt_end_tag %]
        /cross {
    	...
        }

    Better would be to have each template simply activate the flags for
    those templates that it relies on.  The header file pushes a new output
    buffer and the footer file goes back to the header buffer and INCLUDEs
    the dependant templates.

        [% tt_start_tag %] PROCESS ps/header + ps/complex [% tt_end_tag %]

        10 mm 10 mm complex

        [% tt_start_tag %] PROCESS ps/footer [% tt_end_tag %]

    ps/complex:

        [% tt_start_tag %] global.ps.require.simple = 1 [% tt_end_tag %]
        /complex {
    	...
    	simple
    	...
        }

    ps/simple:

        [% tt_start_tag %] global.ps.require.mm = 1 [% tt_end_tag %]
        /simple {
    	...
            31 mm 41 mm moveto
            ...
        }

    ps/header:

        %%!PS-Adobe-3.0
        ...
        %%EndComments

        [% tt_start_tag %] global.ps.header = tt2.output.push [% tt_end_tag %]

    ps/footer:

        [% tt_start_tag %]  FOREACH file = ['mm','simple',...];
    	    INCLUDE $file IF global.ps.require.$file;
    	END;
        [% tt_end_tag %]

    Ultimately, the whole ps library would become a facility.  The
    acquire() method (called by the Template::Service to acquire the
    facility at the start of processing a template) would do the 'header'
    part (i.e. push the output buffer), and the release() method (called
    at the tail end to release the facility) would do the dependency
    checks.  The dependency registrations would be facility features,
    e.g.

    gs/complex:

        [% tt_start_tag %] tt2.ps.require.mm = 1 [% tt_end_tag %]		    # either
        [% tt_start_tag %] tt2.ps.require('mm', 'simple')  [% tt_end_tag %]   # or