1#======================================================================== 2# 3# TODO 4# 5# DESCRIPTION 6# TODO list for the Template Toolkit version 2.20, containing 7# known bugs, limitations, planned enhancements, long term visions 8# and a few whacky ideas. Development on TT2 has effectively 9# ceased for everything but bug fixes. All new features and general 10# enhancements are being saved for TT3. 11# 12# AUTHOR 13# Andy Wardley <abw@wardley.org> 14# 15#======================================================================== 16 17 18#------------------------------------------------------------------------ 19# Miscellaneous 20#------------------------------------------------------------------------ 21 22* The 'eval' filter leaks memory, as reported by Colin Johnson. The 23 filter subroutine created contains a reference to the context and then 24 gets cached in the FILTER_CACHE item of the context. Hey presto - 25 circular references. The reset() method should probably clear the 26 FILTER_CACHE. Also need to check the plugins cache for similar 27 problems. UPDATE: this may now have been fixed. 28 29* The handling of the DELIMITER parameter could be improved. At the 30 moments it's hardcoded and hacked to Do The Right Thing for Win32 31 but I'd prefer it to Do The Good Thing. 32 33* If you use 'ttree' with a COMPILE_EXT or COMPILE_DIR option then 34 templates in the 'lib' directories will be compiled, but those in 35 the src directories will not. This is because ttree does a chdir() 36 to the src directory and processes files as './myfile'. TT doesn't 37 compile RELATIVE files by default. 38 39* No recursion checking is performed for BLOCKs, only 40 Template::Document instances. This is probably the way it will stay 41 (unless anyone shouts loudly enough) but it should be documented 42 anyway. STOP PRESS: I had an idea that bare BLOCK subs should be 43 blessed into Template::Document class to allow $template->process() 44 to be called regardless. Template::Document methods would need to 45 test $self for CODE/HASH and Do The Right Thing. This would then 46 allow recursion testing for BLOCKs as well as Template::Document 47 objects. 48 49* It would be nice if there was an option so that the files generated 50 under the COMPILE_DIR are relative to the INCLUDE_PATH and not absolute. 51 This could cause potential conflicts (e.g. if INCLUDE_PATH changes 52 between sessions and the same files in different INCLUDE_PATH dirs 53 maps to the samed compiled version) but is convenient for those times 54 when you know that's not going to be a problem. 55 56* Craig Barratt notes, in fixing the problem with NEXT not working 57 inside SWITCH (see Changes v2.04): 58 59 By the way, I came across another arcane bug: 60 61 NEXT FOREACH k = [1]; 62 63 is legal syntax but is an infinite loop, since $_[0]->{ INFOR } in 64 Parser.yp is not set when the NEXT is parsed, so it generates a 65 plain "next;" rather than calling $factor->next(). I don't see an 66 easy, clean fix. 67 68 69#------------------------------------------------------------------------ 70# Documentation 71#------------------------------------------------------------------------ 72 73* Extend the FAQ. 74 75 76#------------------------------------------------------------------------ 77# Directives 78#------------------------------------------------------------------------ 79 80* A 'FOR', like 'FOREACH' but without using an iterator. You wouldn't get 81 the 'loop' reference to test 'first', 'last', etc., against, but it would 82 be faster for those cases when you didn't need it. This will likely 83 be implemented as a facility feature (see later). 84 85* PRINT should be defined as a new directive, doing what the print() 86 method of Template::View currently does (the Right Thing). 87 88 [% PRINT node %] === [% tt.view.print(node) %] 89 90 NOTE TO SELF: this is a Very Good Idea [tm]. PRINT becomes the way to 91 display a data structure (e.g. hash, list, XML element, MyThingy, database 92 record, etc.) in an "intelligent" fashion. Implemented underneath via 93 the current default VIEW. 94 95* ARGS. There may be a requirement for reusable template components 96 to define what variables they plan to use. This would allow some 97 optimisation and also possibly help to avoid global variable clashes. 98 Would also be a useful "comment" directive for human readers and maybe 99 also help in debugging (WARNING: expected 'title' argument). 100 101 [% ARGS title # no default 102 bgcol='#ffffff' # default value 103 %] 104 105 106#------------------------------------------------------------------------ 107# Parser 108#------------------------------------------------------------------------ 109 110* Lists don't accept arbitrary expressions as elements, although 111 function arguments now do. So you can do this: [% foo(bar + 1) %], 112 but you can't do this: [% foo = [bar + 1] %]. This has been fixed in 113 the v3 parser. 114 115* The parser isn't as intelligent as it could be about blocks of template 116 code commented out en masse. The pre-scanner find the first terminating 117 END_TAG after an opening tag, regardless of it being on a 118 commented line or not. 119 e.g. 120 [%# 121 # 122 # [% INCLUDE blah %] <- directive ends here 123 # foo <- this gets printed 124 %] 125 126* Craig Barratt reports the following: 127 128 I looked at Parse.yp to see how hard it would be to push FILTER 129 evaluation down into the expr rule, so that you could put filters 130 inside expressions (eg: using repeat() just like "x" in 131 perl). More about that later. 132 133 In browsing through Parser.yp I noticed several issues: 134 135 - The operator precedence is very different to perl, C etc. 136 For example, these expressions evaluate differently in 137 TT2 versus perl, C etc: 138 139 + "1 || 0 && 0" evaluates to 0 in TT2 and 1 in perl or C. 140 TT2 parses it as (1||0) && 0; in perl and C && is higher 141 precedence than ||. 142 143 + "1 + !0 + 1" evaluates to 1 in TT2 and 3 in perl or C. 144 TT2 parses it as 1 + !(0 + 1); in perl and C ! is higher 145 precedence than +. 146 147 + Many other expressions parse incorrectly, but the effect 148 is benign since most rules return flat text that perl 149 correctly re-parses. Eg, 2 * 3 + 4 is incorrectly parsed 150 as (2 * (3 + 4)), but happily just the string "2 * 3 + 4" 151 is compiled by perl, which correctly evaluates it as 152 (2 * 3) + 4. 153 154 - There is no unary minus and the NUMBER token is signed. So you can 155 write "x = -2;" but not "x = -y;". Moreover, "x = 1 -1;" is a syntax 156 error (since "1 -1" returns just two tokens NUMBER, NUMBER). (As a 157 workaround you can rewrite these as "x = 0-y;" and "x = 1 - 1".) 158 159 - You cannot have expressions in lists ([..]) and function arguments. 160 161 I have modified the Parser.pm (to make NUMBER unsigned) and modified 162 Grammar.pm.skel and Parser.yp to fix most of these issues (improved 163 operator precedence, unary minus and plus), and also to allow 164 expressions in a few more places (eg: range). But the last item 165 has me stuck. 166 167 The parse rules for lists and function arguments make COMMA optional, 168 so you can equivalently write [1 2 3 4] or [1,,,,,2 3 4] or [1,2,3,4]. 169 This makes it very difficult to make each term an expression, because 170 the resulting grammar has many ambiguities. For example, is [1 -1] 171 two elements [1, -1] or a single element [0]? One partial solution is 172 to move the bracketed expression rule '(' expr ')' to the term rule, 173 allowing expressions to be included via parens. But there are also 174 ambiguities, eg: does [foo (1+1)] have 2 elements or is it a function 175 call to foo? 176 177 Without allowing expressions in lists or function arguments, the unary 178 minus change I've made means that the NUMBER token is unsigned, so with 179 my changes you cannot write [-1, 2, 3]. Not a good thing. 180 181 One solution is to change the grammar so that COMMAs are required in 182 lists and arguments, but that would break several test cases and 183 probably break lots of old templates. But this might be the only 184 way to produce a grammar that is a lot more similar to perl. 185 186 Another solution is to ignore these issues altogether and use temporary 187 variables to precompute expressions that you need in lists or function 188 arguments, or use explicit lvalue assignments, eg: 189 190 foo(x + 2); becomes temp = x + 2; 191 foo(temp); 192 193 or 194 195 List = [x+1,x+2,x+4]; becomes List = []; 196 List.0 = x+1; 197 List.1 = x+2; 198 List.2 = x+4; 199 200 Both of these look ugly to me. 201 202 Back to the FILTER issues. Ultimately I'd like to be able to embed filters 203 as low precedence operators in expressions, and write: 204 205 List = [ 206 "foo" | repeat(10), 207 "bar" | repeat(10) 208 ]; 209 210 but I doubt there is a non-ambiguous upward compatible grammar that 211 supports this. 212 213 Comments? 214 215 216#------------------------------------------------------------------------ 217# Plugins 218#------------------------------------------------------------------------ 219 220* We need a way to easily enable/disable certain plugins. This should 221 be addressed by facility provision. Probably something for v3. 222 223* The Template::Plugin DBI iterator first/last() methods don't behave 224 the same as list first/last(). Randal also reports that get_all() 225 doesn't work as it should - may be a conflict in code/docs? Again, 226 this is a problem to solve in TT3. 227 228* PLUGINS could accept a reference to an object which is used as a 229 singleton factory for a plugin. (NOTE: 2.01 includes PLUGIN_FACTORY 230 to implement this, but currently undocumented because it's likely to 231 change). 232 233* A more general solution for XML (e.g. DOM, XPath, etc) would be for 234 TT to support a PerlSAX handler which generates the appropriate 235 callbacks to the view. This should make it possible to easily 236 display XML content from XML::DOM, XML::XPath, or any other SAX 237 compliant source. 238 239 Something like this: 240 241 # define a view 242 [% VIEW my_view 243 prefix="my/xml/dom/path/" ; 244 END 245 %] 246 247 # get some XML 248 [% USE dom = XML.DOM %] 249 [% doc = dom.parser(my.files.xmldata) %] 250 251 # ask the view to print the data 252 [% my_view.print(doc) %] 253 254 The view print() method will call the relevant 2SAX method on the 255 XML node, passing a SAX2TTView handler to make the relevant calls 256 back to the view to display parts of the XML data model as SAX events 257 are received. 258 259 260#------------------------------------------------------------------------ 261# Views 262#------------------------------------------------------------------------ 263 264The current implementation is there to get me (and anybody else who's 265interested) using it and trying to identify the problems, requirements 266and general issues involved. I've got a better idea now about what a 267VIEW should be in notional terms, but I'm still not quite sure about 268the syntax and API. 269 270General thoughts: 271 272* A view defines a set of templates. Things like prefix, suffix, 273 default, etc., can be specified to customise template selection. 274 In this sense, it is like a custom provider of those templates. 275 It implements the template() method to fetch a template according 276 to those rules. 277 278* It is also a custom processor of those templates. It implements the 279 process() method. In this sense, it is like a custom context. 280 281* It also implements dispatch logic to apply the right template to the 282 right kind of data. It does this via the print() method. It may 283 have all kinds of custom dispatch logic. 284 285* A view takes responsiblity for things template related as opposed 286 to anything data related (stash) or application logic related 287 (plugins, runtime code, etc). It is the user interface facility 288 within the engine. 289 290