|
| 1 | +Temple expression documentation |
| 2 | +=============================== |
| 3 | + |
| 4 | +Temple uses S-expressions to represent the parsed template code. The S-expressions |
| 5 | +are passed from filter to filter until the generator. The generator transforms |
| 6 | +the S-expression to a ruby code string. See the {file:README.md README} for an introduction. |
| 7 | + |
| 8 | +In this document we documented all the expressions which are used by Temple. There is also |
| 9 | +a formal grammar which can validate expressions. |
| 10 | + |
| 11 | +The Core Abstraction |
| 12 | +-------------------- |
| 13 | + |
| 14 | +The core abstraction is what every template evetually should be compiled |
| 15 | +to. Currently it consists of six types: |
| 16 | +multi, static, dynamic, code, newline and capture. |
| 17 | + |
| 18 | +When compiling, there's two different strings we'll have to think about. |
| 19 | +First we have the generated code. This is what your engine (from Temple's |
| 20 | +point of view) spits out. If you construct this carefully enough, you can |
| 21 | +make exceptions report correct line numbers, which is very convenient. |
| 22 | + |
| 23 | +Then there's the result. This is what your engine (from the user's point |
| 24 | +of view) spits out. It's what happens if you evaluate the generated code. |
| 25 | + |
| 26 | +### [:multi, *sexp] |
| 27 | + |
| 28 | +Multi is what glues everything together. It's simply a sexp which combines |
| 29 | +several others sexps: |
| 30 | + |
| 31 | + [:multi, |
| 32 | + [:static, "Hello "], |
| 33 | + [:dynamic, "@world"]] |
| 34 | + |
| 35 | +### [:static, string] |
| 36 | + |
| 37 | +Static indicates that the given string should be appended to the result. |
| 38 | + |
| 39 | +Example: |
| 40 | + |
| 41 | + [:static, "Hello World"] |
| 42 | +is the same as: |
| 43 | + _buf << "Hello World" |
| 44 | + |
| 45 | + [:static, "Hello \n World"] |
| 46 | +is the same as |
| 47 | + _buf << "Hello\nWorld" |
| 48 | + |
| 49 | +### [:dynamic, ruby] |
| 50 | + |
| 51 | +Dynamic indicates that the given Ruby code should be evaluated and then |
| 52 | +appended to the result. |
| 53 | + |
| 54 | +The Ruby code must be a complete expression in the sense that you can pass |
| 55 | +it to eval() and it would not raise SyntaxError. |
| 56 | + |
| 57 | +Example: |
| 58 | + |
| 59 | + [:dynamic, 'Math::PI * r**2'] |
| 60 | + |
| 61 | +### [:code, ruby] |
| 62 | + |
| 63 | +Code indicates that the given Ruby code should be evaluated, and may |
| 64 | +change the control flow. Any \n causes a newline in the generated code. |
| 65 | + |
| 66 | +Example: |
| 67 | + |
| 68 | + [:code, 'area = Math::PI * r**2'] |
| 69 | + |
| 70 | +### [:newline] |
| 71 | + |
| 72 | +Newline causes a newline in the generated code, but not in the result. |
| 73 | + |
| 74 | +### [:capture, variable_name, sexp] |
| 75 | + |
| 76 | +Evaluates the Sexp using the rules above, but instead of appending to the |
| 77 | +result, it sets the content to the variable given. |
| 78 | + |
| 79 | +Example: |
| 80 | + |
| 81 | + [:multi, |
| 82 | + [:static, "Some content"], |
| 83 | + [:capture, "foo", [:static, "More content"]], |
| 84 | + [:dynamic, "foo.downcase"]] |
| 85 | +is the same as: |
| 86 | + _buf << "Some content" |
| 87 | + foo = "More content" |
| 88 | + _buf << foo.downcase |
| 89 | + |
| 90 | +Control flow abstraction |
| 91 | +------------------------ |
| 92 | + |
| 93 | +Control flow abstractions can be used to write common ruby control flow constructs. |
| 94 | +These expressions are compiled to [:code, ruby] by Temple::Filters::ControlFlow |
| 95 | + |
| 96 | +### [:if, condition, if-sexp, optional-else-sexp] |
| 97 | + |
| 98 | +Example: |
| 99 | + |
| 100 | + [:if, |
| 101 | + "1+1 == 2", |
| 102 | + [:static, "Yes"], |
| 103 | + [:static, "No"]] |
| 104 | +is the same as: |
| 105 | + if 1+1 == 2 |
| 106 | + _buf << "Yes" |
| 107 | + else |
| 108 | + _buf << "No" |
| 109 | + end |
| 110 | + |
| 111 | +### [:block, ruby, sexp] |
| 112 | + |
| 113 | +Example: |
| 114 | + |
| 115 | + [:block, |
| 116 | + '10.times do', |
| 117 | + [:static, 'Hello']] |
| 118 | +is the same as: |
| 119 | + 10.times do |
| 120 | + _buf << 'Hello' |
| 121 | + end |
| 122 | + |
| 123 | +### [:case, argument, [condition, sexp], [condition, sexp], ...] |
| 124 | + |
| 125 | +Example: |
| 126 | + |
| 127 | + [:case, |
| 128 | + 'value', |
| 129 | + ["1", "value is 1"], |
| 130 | + ["2", "value is 2"], |
| 131 | + [:else, "don't know"]] |
| 132 | +is the same as: |
| 133 | + case value |
| 134 | + when 1 |
| 135 | + _buf << "value is 1" |
| 136 | + when 2 |
| 137 | + _buf << "value is 2" |
| 138 | + else |
| 139 | + _buf << "don't know" |
| 140 | + end |
| 141 | + |
| 142 | +### [:cond, [condition, sexp], [condition, sexp], ...] |
| 143 | + |
| 144 | + [:cond, |
| 145 | + ["a", "a is true"], |
| 146 | + ["b", "b is true"], |
| 147 | + [:else, "a and b are false"]] |
| 148 | +is the same as: |
| 149 | + case |
| 150 | + when a |
| 151 | + _buf << "a is true" |
| 152 | + when b |
| 153 | + _buf << "b is true" |
| 154 | + else |
| 155 | + _buf << "a and b are false" |
| 156 | + end |
| 157 | + |
| 158 | +Escape abstraction |
| 159 | +------------------ |
| 160 | + |
| 161 | +The Escape abstraction is processed by Temple::Filters::Escapable. |
| 162 | + |
| 163 | +### [:escape, bool, sexp] |
| 164 | + |
| 165 | +The boolean flag switches escaping on or off for the content sexp. Dynamic and static |
| 166 | +expressions are manipulated. |
| 167 | + |
| 168 | +Example: |
| 169 | + |
| 170 | + [:escape, true, |
| 171 | + [:multi, |
| 172 | + [:dynamic, "code"], |
| 173 | + [:static, "<"], |
| 174 | + [:escape, false, [:static, ">"]]]] |
| 175 | +is transformed to |
| 176 | + [:multi, |
| 177 | + [:dynamic, 'escape_html(code)'], |
| 178 | + [:static, '<'], |
| 179 | + [:static, '>']] |
| 180 | + |
| 181 | +HTML abstraction |
| 182 | +---------------- |
| 183 | + |
| 184 | +The HTML abstraction is processed by the html filters (Temple::HTML::Fast and Temple::HTML::Pretty). |
| 185 | + |
| 186 | +### [:html, :doctype, string] |
| 187 | + |
| 188 | +Example: |
| 189 | + [:html, :doctype, '5'] |
| 190 | +generates |
| 191 | + <!DOCTYPE html> |
| 192 | + |
| 193 | +Supported doctypes: |
| 194 | + |
| 195 | +<table> |
| 196 | +<tr><td><b>Name</b></td><td><b>Generated doctype</b></td></tr> |
| 197 | +<tr><td>1.1</td><td><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"></td></tr> |
| 198 | +<tr><td>html, 5</td><td><!DOCTYPE html></td></tr> |
| 199 | +<tr><td>strict</td><td><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"></td></tr> |
| 200 | +<tr><td>frameset</td><td><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"></td></tr> |
| 201 | +<tr><td>mobile</td><td><!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd"></td></tr> |
| 202 | +<tr><td>basic</td><td><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd"></td></tr> |
| 203 | +<tr><td>transitional</td><td><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"></td></tr> |
| 204 | +</table> |
| 205 | + |
| 206 | +### [:html, :comment, sexp] |
| 207 | + |
| 208 | +Example: |
| 209 | + [:html, :comment, [:static, 'comment']] |
| 210 | +generates: |
| 211 | + <!--comment--> |
| 212 | + |
| 213 | +### [:html, :condcomment, condition, sexp] |
| 214 | + |
| 215 | +Example: |
| 216 | + [:html, :condcomment, 'IE', [:static, 'comment']] |
| 217 | +generates: |
| 218 | + <!--[if IE]>comment<![endif]--> |
| 219 | + |
| 220 | +### [:html, :tag, identifier, attributes, optional-sexp] |
| 221 | + |
| 222 | +HTML tag abstraction. Identifier can be a String or a Symbol. If the optional content Sexp is omitted |
| 223 | +the tag is closed (e.g. `<br/>` `<img/>`). The tag is also closed if the content Sexp is empty |
| 224 | +(consists only of :multi and :newline expressions) and the tag is registered as auto-closing. |
| 225 | + |
| 226 | +Example: |
| 227 | + [:html, :tag, 'img', [:html, :attrs, [:html, :attr, 'src', 'image.png']]] |
| 228 | + [:html, :tag, 'p', [:multi], [:static, 'Content']] |
| 229 | +generates: |
| 230 | + |
| 231 | + <img src="image.png"/> |
| 232 | + <p>Content</p> |
| 233 | + |
| 234 | +### [:html, :attrs, attributes] |
| 235 | + |
| 236 | +List of html attributes [:html, :attr, identifier, sexp] |
| 237 | + |
| 238 | +### [:html, :attr, identifier, sexp] |
| 239 | + |
| 240 | +HTML attribute abstraction. Identifier can be a String or a Symbol. |
| 241 | + |
| 242 | +### [:html, :js, code] |
| 243 | + |
| 244 | +HTML javascript abstraction which wraps the js code in a HTML comment or CDATA depending on document format. |
| 245 | + |
| 246 | +Formal grammar |
| 247 | +-------------- |
| 248 | + |
| 249 | +Validate expressions with Temple::Grammar.match? and Temple::Grammar.validate! |
| 250 | + |
| 251 | + Temple::Grammar.match? [:multi, [:static, 'Valid Temple Expression']] |
| 252 | + Temple::Grammar.validate! [:multi, 'Invalid Temple Expression'] |
| 253 | + |
| 254 | +The formal grammar is given in a Ruby DSL similar to EBNF and should be easy to understand if you know EBNF. Repeated tokens |
| 255 | +are given by appending ?, * or + as in regular expressions. |
| 256 | + |
| 257 | +* ? means zero or one occurence |
| 258 | +* \* means zero or more occurences |
| 259 | +* \+ means one or more occurences |
| 260 | + |
| 261 | +<!-- Find a better way to include the grammar --> |
| 262 | +<script src="http://gist-it.appspot.com/github/judofyr/temple/raw/master/lib/temple/grammar.rb"></script> |
0 commit comments