I have an application I am working on in TT2 that is attempting to perform
behavior similar to HTML::Mason (but not exactly) in locating templates.
 In order to do this, each template remembers where it was loaded from,
and sets its working directory to that directory.  Templates loaded without
any leading path qualifiers, which normally causes INCLUDE_PATH to be
searched in TT2 are searched for as if INCLUDE_PATH were the current
directory and every directory above it (up to an APP_ROOT config setting
that is.  Also, templates loaded with an absolute path are treated as
relative to APP_ROOT, making the whole tree relocatable.  This requires
a fairly grotesque hack, but it's reasonably trivial and not really a
problem yet).  So if a template /foo/bar/baz/blah.tmpl contains an [%INCLUDE
thing.tmpl%], it will search for thing.tmpl in /foo/bar/baz, then /foo/bar,
then /foo, then /, but won't actually change the working directory. 
This is fairly similar to HTML::Mason's autohandler or Zope's acquisition
behavior.

Anyway, to manage this, I had to override Provider::_load and have it
stick an extra member into Document object metadata (for which I had
to create a subclass of Document), namely _epath (stands for "effective
path").  When documents call Context::visit(), passing themselves in,
the overridden Context pushes it onto an internal _DOCSTACK member, and
the leave() method pops it.  Finally I had to change the interface between
Context and Provider to have the Context pass itself in as a parameter
to Provider::fetch so the provider could call a working_directory() method
on the context in order to implement the proper behavior in _fetch_path().

All this was reasonably hunky dory until the internal interface changed.
 Documents no longer pass themselves to the visit() method on their context,
they only pass their defblocks in.  No document stack now.  I could use
perl's 'caller' function, but that's a grotesque hack I have never liked,
and it fails in the face of inheritance.  Now since Document is a reasonably
private item (only Provider ever instantiates them) and I'm subclassing
Context, Provider, and Document anyway, I could simply revert the interface
back to the way it was, but I'm getting less comfortable with it -- it's
feeling more like an outright fork of TT2 than an enhancement, because
I'm breaking the interface contract all over the place.

In TT3, I could probably have the affected Provider subscribe to visit()
and leave() events to manage the document stack directly (assuming this
does cause an event notification?), but that's for a future design.

I see quite a bit of value in maintaining a Document stack along with
the block stack anyway.  It would allow for tracebacks in error handling
for one, as well as this mason-like behavior.  I would also like to see
Providers have some way of getting at their context (again without using
the ugly hack of 'my $context = caller;').  I'll submit a patch to this
effect if you're receptive to the idea.

__________________________________________________
FREE voicemail, email, and fax...all in one place.
Sign Up Now! http://www.onebox.com



Reply via email to