Skip to content

HTTPS clone URL

Subversion checkout URL

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