Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 725 lines (542 sloc) 26.342 kB
c8d76d4 @abw *** empty log message ***
authored
1 #========================================================================
2 #
3 # TODO
4 #
5 # DESCRIPTION
dfe8b14 @abw version 2.10
authored
6 # TODO list for the Template Toolkit version 2.10, containing
c8d76d4 @abw *** empty log message ***
authored
7 # known bugs, limitations, planned enhancements, long term visions
8 # and a few whacky ideas.
9 #
10 # AUTHOR
d914545 @abw version 2.09
authored
11 # Andy Wardley <abw@wardley.org>
c8d76d4 @abw *** empty log message ***
authored
12 #
13 #------------------------------------------------------------------------
14 # $Id$
15 #========================================================================
89bdc37 @abw *** empty log message ***
authored
16
82cbea8 @abw version 2.00
authored
17 #------------------------------------------------------------------------
ca4050f @abw prep for 2.02
authored
18 # Miscellaneous
19 #------------------------------------------------------------------------
25a8d8e @abw *** empty log message ***
authored
20
dfe8b14 @abw version 2.10
authored
21 * The 'eval' filter leaks memory, as reported by Colin Johnson. The
22 filter subroutine created contains a reference to the context and then
23 gets cached in the FILTER_CACHE item of the context. Hey presto -
24 circular references. The reset() method should probably clear the
25 FILTER_CACHE. Also need to check the plugins cache for similar
26 problems.
27
ca4050f @abw prep for 2.02
authored
28 * The handling of the DELIMITER parameter could be improved. At the
29 moments it's hardcoded and hacked to Do The Right Thing for Win32
30 but I'd prefer it to Do The Good Thing.
3e45060 @abw *** empty log message ***
authored
31
dfe8b14 @abw version 2.10
authored
32 * If you use 'ttree' with a COMPILE_EXT or COMPILE_DIR option then
33 templates in the 'lib' directories will be compiled, but those in
34 the src directories will not. This is because ttree does a chdir()
35 to the src directory and processes files as './myfile'. TT doesn't
36 compile RELATIVE files by default.
37
82cbea8 @abw version 2.00
authored
38 * No recursion checking is performed for BLOCKs, only
3e45060 @abw *** empty log message ***
authored
39 Template::Document instances. This is probably the way it will stay
40 (unless anyone shouts loudly enough) but it should be documented
82cbea8 @abw version 2.00
authored
41 anyway. STOP PRESS: I had an idea that bare BLOCK subs should be
42 blessed into Template::Document class to allow $template->process()
43 to be called regardless. Template::Document methods would need to
44 test $self for CODE/HASH and Do The Right Thing. This would then
45 allow recursion testing for BLOCKs as well as Template::Document
46 objects.
ab37ff9 @abw *** empty log message ***
authored
47
f4df3b6 @abw approach v2.03
authored
48 * It would be nice if there was an option so that the files generated
49 under the COMPILE_DIR are relative to the INCLUDE_PATH and not absolute.
50 This could cause potential conflicts (e.g. if INCLUDE_PATH changes
51 between sessions and the same files in different INCLUDE_PATH dirs
52 maps to the samed compiled version) but is convenient for those times
53 when you know that's not going to be a problem.
c8d76d4 @abw *** empty log message ***
authored
54
6c54b0a @abw 2.03b
authored
55 * Richard Tietjen's patch for stash replace. Allows back references
56 (e.g. $1) but it would be nice to find a rock-solid way to implement
92ccaa1 @abw developer release 2.05b
authored
57 it without relying on unusual ^A delimiter character.
6c54b0a @abw 2.03b
authored
58
59 * Further to the above, Craig Barratt has this solution which will be
92ccaa1 @abw developer release 2.05b
authored
60 going into the next verion (2.05b) unless anyone has any further
6c54b0a @abw 2.03b
authored
61 suggestions to make before then.
62
63 It would be great if replace handled backreferences. I don't like
64 the ^A solution since the string could contain ^A, plus it is a
65 security hole. The attempt I posted only works for up to 9
66 backreferences and doesn't handle an escaped '\$' and uses nested
67 evals:
68
69 $str =~ s{$search}{
70 my $r = $replace;
71 my @d = (0, $1, $2, $3, $4, $5, $6, $7, $8, $9);
72 $r =~ s/\$(\d+)/$d[$1]/eg;
73 $r;
74 }eg;
75
76 I wish there was a perl predefined variable array containing all
77 the backreferences (is there one?). You can avoid the hard-coded
78 limit of 9 with extra evals, and a bit of work on the re could
79 handle the escaped '\$' case, so maybe that would be good enough.
80
81 * Craig also notes, in fixing the problem with NEXT not working
82 inside SWITCH (see Changes v2.04):
83
84 By the way, I came across another arcane bug:
85
86 NEXT FOREACH k = [1];
87
88 is legal syntax but is an infinite loop, since $_[0]->{ INFOR } in
89 Parser.yp is not set when the NEXT is parsed, so it generates a
90 plain "next;" rather than calling $factor->next(). I don't see an
91 easy, clean fix.
92
93
c8d76d4 @abw *** empty log message ***
authored
94 #------------------------------------------------------------------------
95 # Documentation
96 #------------------------------------------------------------------------
97
98 * Extend the FAQ.
99
100 * Document the Splash! library properly, once the interface is a little
101 more settled.
102
103 * Examples for libraries (HTML, Splash & PostScript) should be integrated
104 into the documentation.
105
106
107 #------------------------------------------------------------------------
108 # Directives
109 #------------------------------------------------------------------------
110
111 * A 'FOR', like 'FOREACH' but without using an iterator. You wouldn't get
112 the 'loop' reference to test 'first', 'last', etc., against, but it would
113 be faster for those cases when you didn't need it. This will likely
114 be implemented as a facility feature (see later).
115
116 * PRINT should be defined as a new directive, doing what the print()
117 method of Template::View currently does (the Right Thing).
118
119 [% PRINT node %] === [% tt.view.print(node) %]
120
121 NOTE TO SELF: this is a Very Good Idea [tm]. PRINT becomes the way to
122 display a data structure (e.g. hash, list, XML element, MyThingy, database
123 record, etc.) in an "intelligent" fashion. Implemented underneath via
124 the current default VIEW.
125
126 * ARGS. There may be a requirement for reusable template components
127 to define what variables they plan to use. This would allow some
128 optimisation and also possibly help to avoid global variable clashes.
129 Would also be a useful "comment" directive for human readers and maybe
130 also help in debugging (WARNING: expected 'title' argument).
131
132 [% ARGS title # no default
133 bgcol='#ffffff' # default value
134 %]
135
136
137 #------------------------------------------------------------------------
138 # Stash
139 #------------------------------------------------------------------------
140
401f9f2 @abw applied Christian's Makefile.PL patch
authored
141 * The XS Stash does not work with tied hashes (e.g. DBI.tie). Also note
2de5c38 @abw misc doc updates for 2.05
authored
142 that enabling the XS Stash cause all the Template::* modules to be
143 installed in an architecture-dependant directory. For info, see
144 http://www.tt2.org/pipermail/templates/2001-September/001568.html
145
92ccaa1 @abw developer release 2.05b
authored
146 * Jonas Liljegren reports a segfault when using the XS Stash under
147 Apache/mod_perl with certain undefined variables. At the time of
148 writing detail is scarce. Check the mailing list for further
149 details.
150
c8d76d4 @abw *** empty log message ***
authored
151 * Stas Bekman raised the issue of the Stash not being able to correctly
152 differentiate between scalar/list context and in particular, the
d941238 @abw prep 2.4d
authored
153 cgi.param examples not working as expected. This is fixed in v3 and
154 in Craig's Stash/Context.pm which does the right lookahead to allow
155 'scalar' and 'list' postfix operators. e.g. cgi.param.list
c8d76d4 @abw *** empty log message ***
authored
156
157 * Have stash, etc., add current template name/line when reporting errors.
158 (may be tricky under the current implementation)
159
160
161 #------------------------------------------------------------------------
162 # Parser
163 #------------------------------------------------------------------------
164
165 * Lists don't accept arbitrary expressions as elements. In other words
6c54b0a @abw 2.03b
authored
166 you can't do this: [% foo(bar + 1) %]. This has been fixed in the v3
167 parser. See http://www.tt2.org/v3/
c8d76d4 @abw *** empty log message ***
authored
168
a314819 @abw v2.00
authored
169 * The parser isn't as intelligent as it could be about blocks of template
170 code commented out en masse. The pre-scanner find the first terminating
c8d76d4 @abw *** empty log message ***
authored
171 END_TAG after an opening tag, regardless of it being on a
a314819 @abw v2.00
authored
172 commented line or not.
173 e.g.
174 [%#
175 #
176 # [% INCLUDE blah %] <- directive ends here
177 # foo <- this gets printed
178 %]
052df3e @abw *** empty log message ***
authored
179
c8d76d4 @abw *** empty log message ***
authored
180 * Allow { and } as block delimiters, replacing for the ugly ';' and
181 big, chunky [% END %] approach.
36ff03e @abw *** empty log message ***
authored
182
c8d76d4 @abw *** empty log message ***
authored
183 e.g. something like:
184
185 [% FOREACH a = [ 1 2 3 ] %]
186 [% IF b == a %]
187 [% INCLUDE foo %]
188 [% ELSE %]
189 [% INCLUDE bar %]
190 [% END %]
191 [% END %]
192
193 could be written as:
36ff03e @abw *** empty log message ***
authored
194
c8d76d4 @abw *** empty log message ***
authored
195 [% FOREACH a = [ 1 2 3 ] {
196 IF b == a {
197 INCLUDE foo
198 }
199 ELSE {
200 INCLUDE bar
201 }
202 }
203 %]
204
36ff03e @abw *** empty log message ***
authored
205 * Ability to set different parser options for BLOCK definitions, etc.
206
207 [% BLOCK header
208 eval_perl = 0
209 pre_chomp = 1
210 %]
211 ...
212 [% END %]
213
214 Anonymous BLOCK can then be used to set a parser scope
215
216 [% BLOCK trim=1 %]
c8d76d4 @abw *** empty log message ***
authored
217 ...
36ff03e @abw *** empty log message ***
authored
218 [% END %]
219
220 [% BLOCK trim=0 %]
c8d76d4 @abw *** empty log message ***
authored
221 ...
36ff03e @abw *** empty log message ***
authored
222 [% END %]
223
224 And/or set different tag styles, etc.
225
226 [% BLOCK tags='star' %]
227 [* INCLUDE this_is_a_directive *]
228 [% INCLUDE this_is_not %]
229 [* END *]
230
231 [% INCLUDE back_to_normal %]
232
f4df3b6 @abw approach v2.03
authored
233 This is likely to be a TT3 feature and I've already got the basic
234 parser for this up and running. It might get back-pactched into
235 version 2, otherwise you might have to wait for the first alpha
236 release of verion 3.
c8d76d4 @abw *** empty log message ***
authored
237
6c54b0a @abw 2.03b
authored
238 * Craig Barratt reports the following:
239
240 I looked at Parse.yp to see how hard it would be to push FILTER
241 evaluation down into the expr rule, so that you could put filters
242 inside expressions (eg: using repeat() just like &quot;x&quot; in
243 perl). More about that later.
244
245 In browsing through Parser.yp I noticed several issues:
246
247 - The operator precedence is very different to perl, C etc.
248 For example, these expressions evaluate differently in
249 TT2 versus perl, C etc:
250
251 + "1 || 0 && 0" evaluates to 0 in TT2 and 1 in perl or C.
252 TT2 parses it as (1||0) && 0; in perl and C && is higher
253 precedence than ||.
254
255 + "1 + !0 + 1" evaluates to 1 in TT2 and 3 in perl or C.
256 TT2 parses it as 1 + !(0 + 1); in perl and C ! is higher
257 precedence than +.
258
259 + Many other expressions parse incorrectly, but the effect
260 is benign since most rules return flat text that perl
261 correctly re-parses. Eg, 2 * 3 + 4 is incorrectly parsed
262 as (2 * (3 + 4)), but happily just the string "2 * 3 + 4"
263 is compiled by perl, which correctly evaluates it as
264 (2 * 3) + 4.
265
266 - There is no unary minus and the NUMBER token is signed. So you can
267 write "x = -2;" but not "x = -y;". Moreover, "x = 1 -1;" is a syntax
268 error (since "1 -1" returns just two tokens NUMBER, NUMBER). (As a
269 workaround you can rewrite these as "x = 0-y;" and "x = 1 - 1".)
270
271 - You cannot have expressions in lists ([..]) and function arguments.
272
273 I have modified the Parser.pm (to make NUMBER unsigned) and modified
274 Grammar.pm.skel and Parser.yp to fix most of these issues (improved
275 operator precedence, unary minus and plus), and also to allow
276 expressions in a few more places (eg: range). But the last item
277 has me stuck.
278
279 The parse rules for lists and function arguments make COMMA optional,
280 so you can equivalently write [1 2 3 4] or [1,,,,,2 3 4] or [1,2,3,4].
281 This makes it very difficult to make each term an expression, because
282 the resulting grammar has many ambiguities. For example, is [1 -1]
283 two elements [1, -1] or a single element [0]? One partial solution is
284 to move the bracketed expression rule '(' expr ')' to the term rule,
285 allowing expressions to be included via parens. But there are also
286 ambiguities, eg: does [foo (1+1)] have 2 elements or is it a function
287 call to foo?
288
289 Without allowing expressions in lists or function arguments, the unary
290 minus change I've made means that the NUMBER token is unsigned, so with
291 my changes you cannot write [-1, 2, 3]. Not a good thing.
292
293 One solution is to change the grammar so that COMMAs are required in
294 lists and arguments, but that would break several test cases and
295 probably break lots of old templates. But this might be the only
296 way to produce a grammar that is a lot more similar to perl.
297
298 Another solution is to ignore these issues altogether and use temporary
299 variables to precompute expressions that you need in lists or function
300 arguments, or use explicit lvalue assignments, eg:
301
302 foo(x + 2); becomes temp = x + 2;
303 foo(temp);
304
305 or
306
307 List = [x+1,x+2,x+4]; becomes List = [];
308 List.0 = x+1;
309 List.1 = x+2;
310 List.2 = x+4;
311
312 Both of these look ugly to me.
313
314 Back to the FILTER issues. Ultimately I'd like to be able to embed filters
315 as low precedence operators in expressions, and write:
316
317 List = [
318 "foo" | repeat(10),
319 "bar" | repeat(10)
320 ];
321
322 but I doubt there is a non-ambiguous upward compatible grammar that
323 supports this.
324
325 Comments?
326
36ff03e @abw *** empty log message ***
authored
327
328 #------------------------------------------------------------------------
c8d76d4 @abw *** empty log message ***
authored
329 # Plugins
3e45060 @abw *** empty log message ***
authored
330 #------------------------------------------------------------------------
331
c8d76d4 @abw *** empty log message ***
authored
332 * We need a way to easily enable/disable certain plugins. This should
f4df3b6 @abw approach v2.03
authored
333 be addressed by facility provision. Probably something for v3.
c8d76d4 @abw *** empty log message ***
authored
334
335 * The Text::Autoformat module has some problems with versions of Perl
336 prior to 5.6.0 when using a locale which has a decimal separator
337 other than '.' (e.g. Swedish, which uses ','). Damian has been made
338 aware of the problem (and I note he now has a new version out which
339 I need to check). For now, the Makefile.PL issues a warning but
340 continues regardless.
341
342 * The Template::Plugin DBI iterator first/last() methods don't behave
343 the same as list first/last(). Randal also reports that get_all()
344 doesn't work as it should - may be a conflict in code/docs?
345
82cbea8 @abw version 2.00
authored
346 * PLUGINS could accept a reference to an object which is used as a
c8d76d4 @abw *** empty log message ***
authored
347 singleton factory for a plugin. (NOTE: 2.01 includes PLUGIN_FACTORY
348 to implement this, but currently undocumented because it's likely to
349 change).
350
351 * Add Leo & Leon's Page plugin, or try to find some way of implementing
352 it in terms of the Table plugin. I think the jury is still out on the
353 matter of whether it counts as duplicated functionality.
354
f4df3b6 @abw approach v2.03
authored
355 * A more general solution for XML (e.g. DOM, XPath, etc) would be for
356 TT to support a PerlSAX handler which generates the appropriate
357 callbacks to the view. This should make it possible to easily
358 display XML content from XML::DOM, XML::XPath, or any other SAX
359 compliant source.
c8d76d4 @abw *** empty log message ***
authored
360
361 Something like this:
362
363 # define a view
364 [% VIEW my_view
365 prefix="my/xml/dom/path/" ;
366 END
367 %]
82cbea8 @abw version 2.00
authored
368
c8d76d4 @abw *** empty log message ***
authored
369 # get some XML
370 [% USE dom = XML.DOM %]
371 [% doc = dom.parser(my.files.xmldata) %]
372
373 # ask the view to print the data
374 [% my_view.print(doc) %]
82cbea8 @abw version 2.00
authored
375
c8d76d4 @abw *** empty log message ***
authored
376 The view print() method will call the relevant 2SAX method on the
377 XML node, passing a SAX2TTView handler to make the relevant calls
378 back to the view to display parts of the XML data model as SAX events
379 are received.
82cbea8 @abw version 2.00
authored
380
867f44f @abw rc2
authored
381
c8d76d4 @abw *** empty log message ***
authored
382 #------------------------------------------------------------------------
383 # Views
384 #------------------------------------------------------------------------
867f44f @abw rc2
authored
385
c8d76d4 @abw *** empty log message ***
authored
386 The current implementation is there to get me (and anybody else who's
387 interested) using it and trying to identify the problems, requirements
388 and general issues involved. I've got a better idea now about what a
389 VIEW should be in notional terms, but I'm still not quite sure about
390 the syntax and API.
391
392 General thoughts:
393
394 * A view defines a set of templates. Things like prefix, suffix,
395 default, etc., can be specified to customise template selection.
396 In this sense, it is like a custom provider of those templates.
397 It implements the template() method to fetch a template according
398 to those rules.
399
400 * It is also a custom processor of those templates. It implements the
401 process() method. In this sense, it is like a custom context.
402
403 * It also implements dispatch logic to apply the right template to the
404 right kind of data. It does this via the print() method. It may
405 have all kinds of custom dispatch logic.
406
407 * A view takes responsiblity for things template related as opposed
408 to anything data related (stash) or application logic related
409 (plugins, runtime code, etc). It is the user interface facility
410 within the engine.
867f44f @abw rc2
authored
411
ea725fe @abw *** empty log message ***
authored
412
36ff03e @abw *** empty log message ***
authored
413 #------------------------------------------------------------------------
c8d76d4 @abw *** empty log message ***
authored
414 # Splash!
36ff03e @abw *** empty log message ***
authored
415 #------------------------------------------------------------------------
416
c8d76d4 @abw *** empty log message ***
authored
417 The current implementation is a fairly ugly hack to get something up
418 and running that's good enough to use. It's mainly template driven
419 and doesn't scale very well, particularly with global variables
420 clashing all over the place. My plan is that this will become a
421 view-based system and will no doubt be a test-bed for the
422 implementation of the view facility.
423
424 To include:
425
426 * Variable management for storing metadata relating to an
427 interface/view, protected from the rest of template space.
428
429 * Also, style management for defining different styles (e.g. plain,
430 fancy, icecold, whitehot) for different interface elements (e.g.
431 bars, borders, menu text) in different modes (e.g. selected, unselected),
432 or under different, possibly custom conditions (e.g. user preferences,
433 guest or logged in, etc.).
434
435 * Clearly define API for different elements, allowing people to write
436 apps to the API which run across different conformant widget sets.
437
ca4050f @abw prep for 2.02
authored
438 * support themes which define a set of styles
c8d76d4 @abw *** empty log message ***
authored
439
ca4050f @abw prep for 2.02
authored
440 * May be wise to move Splash out to a separate distribution.
c8d76d4 @abw *** empty log message ***
authored
441
f4df3b6 @abw approach v2.03
authored
442 Randal Schwartz highlighted some problems with non-compliant HTML
443 being generated. These include:
444
445 * no DOCTYPE declaration (added to html/header)
446
447 * ALT attribute missing from many <img> tags
448
449 * <font ...><table>...</table></font> is illegal (not sure where this
450 gets done)
451
452 * <tr> shouldn't have HEIGHT attribute
453
454 * <H3> block element inside inline element
455
456 * <A> not allowed here (not sure)
457
c8d76d4 @abw *** empty log message ***
authored
458
459 #------------------------------------------------------------------------
460 # Test Suite
461 #------------------------------------------------------------------------
462
ca4050f @abw prep for 2.02
authored
463 * t/file.t and t/directry.t are currently disable on Win32 until I get
464 a chance to fix a couple of minor bugs relating to '/' vs '\' file
465 separators.
c8d76d4 @abw *** empty log message ***
authored
466
467
468 #------------------------------------------------------------------------
469 # Facilities
470 #------------------------------------------------------------------------
471
472 Core facilities currently implemented by Template::Context should be
473 moved out into separate facilities. These currently fall into the
474 categories of things like stash, view, plugins, filters, parser and
475 maybe some others. (NOTE: this might tie in very closely with Camelot
476 and the resource/presenter/actor breakdown, aka model/view/controller).
477
478 * 'view' would handle template fetching and processing. It is the view
479 that talks to a provider, possibly adding special prefixes, suffixes,
480 doing default templates, special dispatch logic, etc.
481
482 * 'stash' is responsible for storing variables, as it currently is.
483
484 * 'plugins' is responsible for fetching plugins.
485
486 * 'filters' is responsible for fetching filters.
487
488 * maybe both the above would get bundled into something like 'logic'?
489
490 * 'parser' would make parts of the parser accessible
491
492 * 'output' could be used to generate output
493
494 There would be some facility to install, customise and remove facilities
495 to modify TT behaviour as required. This would allow us to disable
496 certain plugins, or remove the plugin facility altogether, for example.
497 Or we could install a new stash facility which generated a different kind
498 of code (e.g. less magic, more speed). Or install a new custom facility
499 to do some application or domain specific task.
500
501 Facilities should be accessible via the context:
502
503 my $stash = $context->stash(); # currently works
504 my $view = $context->view(); # not yet
505
506 General form:
507
508 my $xyz = $context->facility('xyz');
509
510 Multiple form:
511
512 my ($a, $b, $c) = $context->facility(qw[ a b c ]);
513
514 This can then be written into generated code pretty much as the stash
515 currently is. The facilities would define the code generators that
516 currently clutter up Template::Directives. They would ensure that the
517 facility is scheduled to be requested from the context at the start of
518 the sub:
519
520 sub {
521 my $context = shift;
522 my ($stash, $view) = $context->faciity(qw( stash view ));
523
524 and then transform the various directives into appropriate callbacks
525 into the facility:
526
527 $output .= $stash->get('x');
528 $output .= $view->process('header');
529
530 The context becomes a switching centre for the Template Toolkit, with
531 most, if not all of its existing functionality moved out to
532 facilities. The context should acquire all facilities at the start of
533 a process lifecycle, run the template, and then release them all
534 again. This should all be done according to the process contract
535 which specifies which facilities should be installed, which can be
536 modified, what can and can't be be loaded, and so on. The
537 contract would also define things like PRE_PROCESS templates, error
538 handling, etc.
539
540 Thus the role of Template::Service is to undertake a contract with the
541 client and attempt to fulfill it. A Template::Contract defines the
542 terms of the contract and the Template::Context becomes an embodiment
543 (runtime instance) of a contract.
544
545 The current context would be available as the 'tt2' template variable,
546 with facilities available as object methods. Thus, the following become
547 possible:
548
549 [% tt2.stash.get('foo') %] # [% foo %]
550 [% tt2.view.process('header') %] # [% PROCESS header %]
551 [% tt2.parser.start_tag %] # can't do this currently
552
553 Directives would be re-written into code like that above. You can
554 use the 'tt2.facility.whatever' form when directive syntax would
555 otherwise get in the way:
556
557 [% mycode( header = tt2.view.process('my/fancy/header'),
558 footer = tt2.view.process('your/dull/footer') ) %]
559
560 Or to explicitly disambiguate:
561
562 [% tt2.stash.get('foo.size') %] # object method
563 [% tt2.stash.list.size(foo) %] # virtual method
564 [% foo.size %] # lucky dip :-)
565
566 Facility management would itself be a facility. Thus, to disable runtime
567 facility loading, you would simply unload (or not load) the facility
568 management facility.
569
570 [% tt2.facility.install(module='my_facility', name='foo') %]
571 [% tt2.foo.bar(123) %]
572
573 Note that there are some issues relating to cross-cutting facilities,
574 otherwise known as "aspects" (see Aspect Oriented Programming). For
575 example, variable localisation cross cuts views and data management
576 (i.e. tt2.view.include('header', title='my title') must first localise
577 the stash and delocalise it again afterwards). It may be appropriate
578 to install aspects as separate entities (e.g. 'localisation') which
579 can be invoked to apply cross cutting concerns in a generic way.
580 Perhaps aspects are implemented as their own facility?
581
582 [% tt2.aspect.localise %] ... [% tt2.aspect.delocalise %]
583 or
584 [% aspect = tt2.aspect.localise %] # cloned & specialised context
585 [% aspect.view.process('header', title='my title') %]
586 or
587 ...
588
589 Another example would be debugging:
590
591 [% tt2dbg = tt2.aspect.debug(...params...) %]
592 [% tt2dbg.view.process('header') %]
593 or:
594 [% tt2 = tt2.aspect.debug(...) %]
595 ...
596 [% tt2 = tt2.release %]
597
598
599 #------------------------------------------------------------------------
600 # Output
601 #------------------------------------------------------------------------
602
603 It should be possible to stack output buffers. In other words, you
604 stop writing to the current output buffer and open a new buffer and
605 start writing to that. The final output is simply the concatenation
606 of all output buffers.
607
608 The clever part of all this is that is should be possible to keep a
609 handle on an earlier buffer and go back and append to it at some point
610 in the future. A typical use is for generating tables of contents at
611 the start of a document when you don't know in advance what the document
612 contains. Simply push a new output buffer at the point of the TOC,
613 generate the rest of the document (keeping track of all the section
614 titles, etc) and at the end of the document, go back and generate the
615 TOC onto the end of the first buffer.
616
617 Haven't decided on any syntax yet, but it will almost certainly be
618 implemented as a facility. At the lowest level, something like
619 this perhaps:
620
621 [% INCLUDE header %] # write content to first buffer
622
623 [% toc = tt2.output.push %] # save current buffer as toc
624
625 Blah blah blah # write content to second buffer
626
627 [% INCLUDE footer %]
628
629 [% tt2.output.buffer = toc %] # re-instate first buffer
630
631 This is the TOC # append to first buffer
632
633 The output stack would look something like this:
634
635 +-----------------+
636 | <header> |
637 | This is the TOC |
638 +-----------------+
639 |
640 V
641 +-----------------+
642 | Blah blah blah |
643 | <footer> |
644 +-----------------+
645
646 Which to the end user, would silently be concatenated into:
647
648 <header>
649 This is the TOC
650 Blah blah blah
651 <footer>
652
653 Another use is to ensure dependencies on other templates get resolved.
654 For example, many of the PostScript library templates rely on other
655 templates. At present, each template sets a global variable to
656 say "I've been loaded" while also inspecting these variables for any
657 templates that it relies on, loading them via INCLUDE/PROCESS if not
658 set. e.g. ps/cross:
659
660 [% # this works, but it's a bit clunky
661 DEFAULT radius = '5 mm';
662 PROCESS ps/mm UNLESS global.ps.loaded.mm;
663 global.ps.loaded.cross = 1;
664 -%]
665 /cross {
666 ...
667 }
668
669 Better would be to have each template simply activate the flags for
670 those templates that it relies on. The header file pushes a new output
671 buffer and the footer file goes back to the header buffer and INCLUDEs
672 the dependant templates.
673
674 [% PROCESS ps/header + ps/complex %]
675
676 10 mm 10 mm complex
677
678 [% PROCESS ps/footer %]
679
680 ps/complex:
681
682 [% global.ps.require.simple = 1 %]
683 /complex {
684 ...
685 simple
686 ...
687 }
688
689 ps/simple:
690
691 [% global.ps.require.mm = 1 %]
692 /simple {
693 ...
694 31 mm 41 mm moveto
695 ...
696 }
697
698 ps/header:
699
700 %%!PS-Adobe-3.0
701 ...
702 %%EndComments
703
704 [% global.ps.header = tt2.output.push %]
705
706 ps/footer:
707
708 [% FOREACH file = ['mm','simple',...];
709 INCLUDE $file IF global.ps.require.$file;
710 END;
711 %]
712
713 Ultimately, the whole ps library would become a facility. The
714 acquire() method (called by the Template::Service to acquire the
715 facility at the start of processing a template) would do the 'header'
716 part (i.e. push the output buffer), and the release() method (called
717 at the tail end to release the facility) would do the dependency
718 checks. The dependency registrations would be facility features,
719 e.g.
36ff03e @abw *** empty log message ***
authored
720
c8d76d4 @abw *** empty log message ***
authored
721 gs/complex:
3ebfa07 @abw Initial revision
authored
722
c8d76d4 @abw *** empty log message ***
authored
723 [% tt2.ps.require.mm = 1 %] # either
724 [% tt2.ps.require('mm', 'simple') %] # or
Something went wrong with that request. Please try again.