Source

templ / misc / tutorial.core.templ

The default branch has multiple heads

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
{#
    Copyright 2013 Brian Mearns

    This file is part of templ.

    templ is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    templ is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with templ.  If not, see <http://www.gnu.org/licenses/>.
}{
}{v {:
    {$ TEMPLATE-CODE {lambda
        {' :TEMPLATE }
        {pre {' :syntax templ} {$ :TEMPLATE }}
    }}

    {$ EXAMPLE-TEMPLATE {lambda
        {' :SYNTAX :INTRO :OUTRO :TEMPLATE }
        {implode <<<
            {p {' {$ :INTRO}}}
            {TEMPLATE-CODE {$ :TEMPLATE}}

            {p {' {$ :OUTRO}}}
            {pre
                {' :syntax {$ :SYNTAX}}
                {buffer {eval {$ :TEMPLATE}}}
            }
        >>> }
    }}

    {$ templ {macro {' code "templ" }}}

}}{doc "templ - Basic Tutorial and Overview"

%Body content
{'

    {section "Introduction" {'

        {section "Overview" {'
            {p 
<<<{b templ} (pronounced just like "temple") is the {b Tem}plate {b P}rocessing {b L}anguage: it's used for processing template files
in order to produce an output file. Template files are simply user supplied files that define how the output
should be generated. Templates are usually just plain text, but binary content is also supported.>>>
            }

            {p 
<<<In its simplest (and least useful) form, a template file simply contains the data that is desired for
the output. However, what makes a a template file interesting, and what makes {templ} itself useful,
is the use of embedded {templ} statements, which are evaluated by the {templ} processor in order
to produce the output.>>>
            }

        }} % section "Overview"

        {section "Template Files" {'

            {p
<<<At the top level, a {templ} template file consists of two types of elements: {em text} and {em statements}.
Text is simply raw (more-or-less) content that will be written to the output stream. Statements are
{templ} code that the processor will evaluate in order to determine the output, as well as its own
behavior. What distinguishes a statement from text is that statements are wrapped in curly braces: "\{" and "\}".
Anything that's not wrapped in curly braces is treated as text and is copied very-nearly verbatim to the
output (more on all of these qualifications later).>>>
            }

        }} % end section "Template Files"

        {section "Hello, Templ!" {'

            {EXAMPLE-TEMPLATE "text"
                {implode 
<<<This wouldn't be much a programming tutorial without the classic "hello world" program. So let's see
how it looks in {templ}. Open a plain text file, and enter the contents below. Save the file as "hello.templ":>>>
                }

                {implode
<<<Now you need to invoke the {templ} processor in order to process this template file and produce the output. To do so
simply execute this command from the directory where your "hello.templ" file is saved: {code "templ hello.templ"}. The
output will be written to the console. It should look like this:>>>
                }

                "hello, templ!"
            }

            {p
<<<I apologize if you were thoroughly bored by that example, but it serves to illustrate that there is no special format
for template files: other than explicit {templ} statements, it's all just content for the output stream. So if all you do
is write some text in a file without any curly braces, all templ will do is copy it to the output.>>>
            }

            {EXAMPLE-TEMPLATE "text"

                {implode
<<<But that is really boring, so let's do something just slightly more interesting. This time, we'll actually introduce a
{templ} statement. Edit your "hello.templ" file to look like this:>>>
                }

                {implode
<<<The statement we added is the stuff between the curly braces: {code "{echo templ}"}. The output is shown below: it looks the same. 
That's because the {code echo} function simply tells {templ} to write the given string to the output stream.>>>
                }

                "hello, {echo templ}!"
            }

            {section "Get Used to Curly Braces" {'
                {p
<<<Ok, still pretty boring, but at least now we're actually writing {templ} code. There's a couple important things to notice in
this example. For one thing, the format for invoking a function may not be what you're used to in most other languages. {templ}
uses a syntax known as "S-expressions", similar to Lisp, in which the function to be invoked is the first element in a list whic
also contains the arguments to be passed to the function. The syntax is semantically the same as the more familiar "M-expressions"
in which the function is outside of the list of arguments, but the different way of writing it is important for allowing template
files to be less structured than what you would normally see in source code.>>>
                }
            }}

            {section "Basic Data Types - Strings and Lists." {'
                {p
<<<The other thing to notice from this example is that the string we passed to the {code echo} function isn't quoted in any way.
{templ} has relatively few data types: for the most part you'll be using primarily {em Strings} and {em Lists}. That means you don't
need anything special like quotes to differentiate a String: just write it out as part of an expression.>>>
                }

                {p
<<<You've already seen a List: the expression {code "{echo templ}"} is a List. You write a List by simply wrapping a sequence of
elements in curly braces. The elements can be Strings or nested Lists, and are separated by whitespace.>>>
                }
                
                {section "Quoted Strings" {'
                    {p
<<<This poses a problem if you want to include whitespace in one of those Strings, so {templ} allows you to wrap your strings in
double-quote characters, just like you're probably used to in other programming languages. Quoted Strings are only terminated by
a closing double-quote character, so they can include whitespace (even vertical whitespace, like linebreaks). You also need to use
a quoted String if you want to include a curly brace in a String, otherwise {templ} will think it's the beginning (or end) or a
List.>>>
                    }

                    {p
<<<If you want to include a double-quote character in a quoted String, you need to escape it with a leading backslash character: {wrap "\"" \}
Without the backslash, the double-quote will just tell {templ} to terminate the quoting and will not be included in the String.
Similarly, if you want to include a backslash in a quoted-string, you need to escape it with another leading backslash.>>>
                    }

                    {p
<<<The Backslash and double-quote characters are the {em only} characters that have a special meaning when escaped in a quoted String.
If any other character in a quoted String is prefixed with a backslash, the backslash is simply ignored, and the following character
is treated normally. Put another way, a backslash character in a quoted String simply tells {templ} to include the subsequent
character in the String, and ignore any special syntactic meaning it would otherwise have (which only double-quote and backslash
characters have, anyway).>>>
                    }

                    {p
<<<To be perfectly clear, {templ} quoted Strings {em do not have} the special escape sequences you might be used to from other programming
languages, such as "\\n" for linebreaks, "\\t" for horizontal tab, etc. Since these characters have no special meaning in {templ} quoted Strings,
you can just include them directly in your quoted String. Alternatively, there are built-in macros such as {code "{eol}"} and
{code "{\\t}"} for all of the common escape sequences (specifically, those defined by the ISO C99 standard), as well as the built-in {code chr} function
which returns a one-character String with character-value equal to a specified numeric value.>>>
                    }

                    {EXAMPLE-TEMPLATE "text"
                        {implode
<<<A final note about quoted Strings: a quoted String is not necessarily an isolated value, it can also be a portion of another String.
In other words, you can tie together quoted and non-quoted Strings to your heart's content, as long as there's no spaces or curly braces
in between them. For example:>>>
                        }

                        {implode
<<<Lexically, there are four different elements here: the two quoted Strings {code "\"he\""} and {code "\" tem\""}, and
the two {em unquoted} Strings {code "\"llo,\""} and {code "\"ple!\""}.
Stringing together all of these different lexical elements results in just a single String value: the output is shown here:>>>
                        }

                        "{echo \"he\"llo,\" tem\"ple!}"

                    }

                }} % end section "Quoted Strings" 

                % TODO: XXX: Lists. The nil function, the list function.

            }} % end section - "Basic Data Types"

        }} % end section "Hello, ..."

        {section "The temple Processing Routine" {'

            {p
<<<As mentioned, a template file consists of text and expressions. In general, {templ} expressions can be
Lists or Strings, but at the top level, only Lists are treated as expressions, everything else is treated as text.>>>
            }

            {p
<<<When a top level List element is encountered by the {templ} processor, the entire List is parsed and then {em evaluated}. 
Generally, Lists in a template file represent an {em executable} to be invoked (like the {code echo} function
we saw above). The first element of the List specifies the executable to invoke, and the remaining elements are the arguments
to pass. Like a lot of other programming languages, the arguments are generally each evaluated one at a time before invoking
the executable and passing in the values that result from the evaluation. {em Unlike} a lot of programming languages, the
elements of the List are evaluated in order from {em left to right}.
This is important because the first element of the List, the one that specifies the executable to invoke, must also be 
evaluated, and then {em resolved}. We'll learn more about what this means and why it matters later, but for now, just keep
in mind that arguments are evaluated left to right.>>>
            }

            {p
<<<When evaluating the elements of the List, Strings are {em self-evaluating}, meaning that when they are evaluated, the
resulting value is simply the String value itself. Nested Lists (elements of a List which are themselves Lists), are
evaluated just like top level Lists are: as describing an executable to invoke and the arguments to pass to it.>>>
            }

            {EXAMPLE-TEMPLATE "text"

                {implode
<<<The following template uses a nested List, and introduces another built-in function, {code glue}, which simply
joins multiple String values together in the order given.>>>
                }

                {implode
<<<The result is (suprise, surprise) the same thing as before.>>>
                }

"{echo {glue \"hello, \" \"templ!\"}}"

            }

            {p
<<<To evaluate the top level List, the {code echo} String element
is evaluated first. Strings are self evaluating, so this just results in the String value {code "\"echo\""}, which resolves
to the {code echo} function we've seen before (don't worry about resolution right now).>>>
            }

            {p
<<<The second element of the top level List is a nested list, so it needs to be evaluated next. This evaluates by invoking
the {code glue} function to glue together the two given Strings. This entire list (the nested one) therefore evaluates to
the String object {code "\"hello, templ!\""}.>>>
            }

            {p
<<<So after evaluating the elements of the top list, we end up with an expression that invokes the {code echo} function with
the argument {code "\"hello, templ!\""}, just like we had before.>>>
            }

            {EXAMPLE-TEMPLATE "text"

                {implode
<<<Of course, we can continue nesting Lists as deeply as we want to come up with some truly obnoxious code like this:>>>
                }

                {implode
<<<It's probably worth mentioning at this point that all of that whitespace I added this time around is irrelvant: {templ}
requires a whitespace character to separate adjacent String elements in a List, but you are free to add as much additional
whitespace as you'd like, it makes no difference to {templ}. This is helpful for structuring your code in a way that is
somewhat easier to follow. You can see in the output below that all that whitespace hasn't changed anything:>>>
                }

"{echo
    {glue
        {glue h e \"l\"l\"o\"}
        ,
        \" \"
        {glue 
            {glue 
                te mp 
                {glue l e}
            }
            !
        }
    }
}"
            }

            {section "Code Formatting" {'
                {p {'
                    {implode <<<A few general suggestions on formating your code:>>>}
                    {ul {'
                        {implode                    
    <<<Keep the first element of a list (the one that specifies the executable to be invoked)
    on the same line as the opening curly brace, generally with no space separating it from the brace. This makes it much
    more obvious what is being invoked.>>>
                        }

                        {implode
    <<<Indent all subsequent elements of the list relative to the opening brace. This helps establish sematic scope for the reader.>>>
                        }

                        {implode
    <<<Don't ever use tabs, use spaces. Tabstops may be set differently by different users and in different editors, so things that are
    nicely aligned with tabs in one circumstance may look horrendous in another. The standard indentation level is 4 spaces. Three is
    also acceptable but kind of weird. Two in somewhat common, and econimical, but is not as visually helpful as a larger indent. More
    than 4 is excessive and will quickly lead to lines that don't have available width. If you want to use tabs because you can't handle
    the extra couple of backspaces, either stop being lazy or get a better editor.>>>
                        }

                        {implode
    <<<Put the closing brace on a new line, aligned in the same column as the opening brace. This make it obvious where
    the List ends, and therefore what is included in it.>>>
                        }

                    }}
                }}
            }} % end section "Code Formatting"


        {section "Output Values" {'

            {p
<<<Remember that {templ} is, first and foremost, a template processing language; its main goal in life is to
process input and produce output. Therefore, when the {templ} processor finishes evaluating a top level
expression, it assumes that the result of that expression is intended as output.>>>
            }

            {p
<<<That's all fine and good when the resulting value is a String, {templ} will just write the String value to
the output stream. But {templ} can't write a List or an executable to the output stream, so if a top level
expression ever evaluates to something other than a String, {templ} will err.>>>
            }

            {p
<<<The fact that top level String values are written directly to the output stream means a lot of our examples
above which used the {code echo} function, didn't actually need to use it. If we were already invoking a
function that results in a String, such as the {code glue} function, we could simply make that our top level
expression and {templ} will output the resulting String to the output stream, just like the {code echo}
function does.>>>
            }

            {EXAMPLE-TEMPLATE "text"

                {implode
<<<In the following template, we simply did away with the {code echo} function from our previous template, and
left the call to the {code glue} function as the top level expression.>>>
                }

                {implode
<<<You can see that the output is the same, because {templ} writes the result of calling the {code glue}
function directly to the output stream.>>>
                }

"{glue
    {glue h e \"l\"l\"o\"}
    ,
    \" \"
    {glue 
        {glue 
            te mp 
            {glue l e}
        }
        !
    }
}"
            }

            {p
<<<You may be wondering why you would ever need to use the {code echo} function, if {templ} will just echo
your top level Strings automatically. There are times where you will want to write to the output stream from
somewhere other than the top level, for instance inside a loop. In times like this, the {code echo} function
comes in very useful.>>>
            }

            {section "The str Function" {'
                % TODO: Add examples, including Lists. Basic list functions are introduced in the Basic types
                % section above.
                {p
<<<For convenience, {templ} does provide a builtin {code str} function, which is used to convert any value
into a String. Simply pass in any value, and a String representation of that value will result.>>>
                }

            }} % end section "...str..."


            {section "Null Values and the void Function" {'
                {p
<<<Actually, there's one other type besides Strings that {templ} can write directly to the output stream: the
Null type. This is a special type which only has one value (called the Null value) which generally represents
the absense of a value. If a top level expression evaluates to the Null value, the output for that expression
is simply an empty string (or more accurately, there is no output).>>>
                }

                {p
<<<Note, however, that this is only a special case for the top level processor. Otherwise, a Null value is {em
not} the same thing as an empty string, they just happen to result in the same output at the top level.
Specifically, passing a Null value to the {code str} function does {em not} result in any empty string, it
results in the String value {code "\"NULL\""}.>>>
                }

                {p
<<<To produce a Null value, you can use the {code void} function. the {code void} function can take up to 1
argument, which {em is} evaluated  but the result of the {code void} expression is always a Null value. You
can also invoke it without any arguments, in which case it simply results in a Null value.>>>
                }

                {p
<<<The {code void} function is a useful way to supress the result of a top level expression. Actually it's no
longer a top level expression because you're wrapping it up in a {code void} expression, but that's the whole
point: the original expression is evaluated as desired, but the {code void} ensures that whatever
type that expression results in, the top level output will be a nice safe Null value that won't err and won't
effect your output.>>>
                }

                {p
<<<A lot of {templ} functions have {em aliases}, which are just different symbols you can use to invoke them.
The void function has a very nice alias, which is simply the single character {code v}. You are likely to see
the function referenced with this alias a lot more often than with the gratuitous {code void} symbol.>>>
                }

                {EXAMPLE-TEMPLATE "text"

                    {implode
<<<The following very simple macro shows the {code void} function at work (using the common {code v}
alias).>>>
                    }

                    {implode
<<<And the output:>>>
                    }

"Null output: {v}
A Null value, as a String: {str {v}}
The void function, to supress output: Foo{v \"---\"}Bar"

                }

            }} % end section "...null...void..."


        }} %end section "Output Values"

        }} % end section "...Processing Routine"

        {section "Comments" {'

            {p
<<<Sometimes, even the best formatting can't make the intentions of your code clear, and it helps to be able to explain yourself
in prose. Most programming languages provide a syntax for comments, and {templ} is no exception. When the {templ} parser encounters
a percent-sign character, "%", anywhere inside an expression except for in a quoted string, the subsequent characters up to and
including the end of the current line is treated as a comment. The comment is ignored by the processor, as if the entire thing
(including the initial "%" character) was just whitespace. One thing to note is that comments do function as {em separators}
between String values, just like whitespace characters.>>>
            }

            {EXAMPLE-TEMPLATE "text"
                {implode
<<<You can put whatever you want in a comment: the processor won't attempt to evaluate it, and the parser won't try to parse it, 
except to find the end of the line. That means you don't have to worry about it being well formed, and you can use comments
to comment out mis-formed code during debugging.>>>
                }

                {}

"If you're having trouble with malformed code, for instance if you've lost track of
whether or not a string is properly escaped or not, {echo 
    %\"like \\\"this\\\" one for instance, \\\"
}you can comment it out for debugging."
            }

            {section "Block Comments - The \"Dont\" Operator" {'

                {p
<<<End-of-line comments are helpful for short comments and because the contents don't need to be well formed, but they're tedious
if you want to write long comments across multiple lines. {templ} provides an operator called {code dont} which can be used for multi-line, or 
{em block} comments. The argument elements in a {code dont} expression are {em not evaluated}, and the result of the entire expression
is a special {code Null} value which we'll learn more about later. In other words, a {code dont} expression doesn't do anything, which
makes it useful for long comments.>>>
                }

                {p
<<<However, unlike end-of-line comments, the parser doesn't know about the {code dont} operator, so the entire expression must be wellformed.
The contents of the expression don't need to be evaluatable, but they do need to be parseable. The upside is that {code dont} expressions can
be nested without any issues, unlike block-comments in certain other programming languages.>>>
                }

                {p
<<<For instance, the following template is {em malformed}: {templ} will err if you try to process this template, even though the malformed code
is in a {code dont} expression.>>>
                }

                {TEMPLATE-CODE
"{dont
    Please don't evaluate {this code
}"
                }

                {p
<<<This next template, on the other hand, works fine, because we used an end-of-line comment to take care of that extra open curly brace.>>>
                }

                {TEMPLATE-CODE
"{dont
    % Please don't parse {this code
}"
                }

                {p
<<<Finally, here is an in-depth example of a {em working} block comment:>>>
                }

                {TEMPLATE-CODE
"{dont
    Block comments are good for long comments,
    Because they can span multiple lines.
    {
        They need to be well-formed, but not necessarily valid code.
    }
    {dont
        You can nest them as well, which is helpful for commenting out large
        blocks of code, even if the block already includes comments.
    }
    % For malformed code, like if you have an extra } or {, for instance,
    % you can also include end-of-line comments in block comments.
}"
                }

                {p
<<<As mentioned, {code dont} expressions evaluate to a Null type value. Despite being null, the result is still
a value, and {em will} act as an element in an element in a List, so you have to be careful about where you place
them. For instance, assuming the {code one-arg} executable only accepts one argument, the following template will
err because the {code dont} expression looks like another argument:>>>
                }

                {TEMPLATE-CODE
"{one-arg Foobar {dont ...Block Comment... }}"
                }

                {p
<<<At the top level, Null typed values simply act as empty strings, so you can put {code dont} expressions
at the top level of your template without any harm. We'll see other places it's safe to use them later when we learn about
the {code block} operator.>>>
                }

            }} % end section "Block Comments"

        }} %end section "Comments"

        {section "About all Those Qualifications on Text Elements" {'

            {p
<<<So we mentioned that text elements at the top level of a template file are just a nice easy way to specify content to put
in the output stream when there's no special processing that requires {templ} expressions. But we also kept qualifying them
as "more-or-less [raw]" and "very-nearly verbatim".>>>
            }

            {p
<<<Hopefully you're getting an idea now of why we needed to add all of these qualifications, small as they may be. There's
one particular character that can't be used directly in text elements: the open curly brace. If you try to just stick an
open curly brace in a text element, the {templ} parser will see it as the start of a List expression. So if you want to put
an open curly brace in the text, you need to escape it with a leading backslash, just like you escape double-quote characters
in quoted-strings.>>>
            }

            {p
<<<But backslash escaping does not work in general in text elements: that would be too much of a burden when you're writing
a text element if you have to escape every occurence of a backslash. Instead, a backslash in a text element only serves as
an escape when it immediately precedes an open curly brace or, for symmetry, a closing curly brace. Note that it is not
{em necessary} to escape closing curly braces, but it is recommended just for visual consistency with open curly braces.>>>
            }

            {EXAMPLE-TEMPLATE "text"
                {implode
<<<Otherwise, a backslash in a text element is simply a backslash: no need to escape it and it doesn't have any effect on
non-curly brace subsequent characters. Take a look at this example which only contains a text element:>>>
                }

                {implode
<<<The output is shown below. It looks a lot like the input template: the only difference is that the backslashes before the
curly braces at the end of the template are not included in the output, because they were only used to escape the curly braces.>>>
                }

"Unix paths use (forward) slashes: \"/usr/bin/templ\". Windows uses backslashes: \"C:\\Windows\\\".
templ uses a lot (a LOT) of curly braces, which look like \\{ and \\}."
            }
        }} % end section "All those Qualifications..."

    }} %end section "Introduction"


    {section "Variables" {'

        {p
<<<It wouldn't be much of a programming language without a way to store and recall data. {templ} uses a structure
called {em the stack} to store what are effectively variables. Essentially, the stack acts like a dictionary
which maps data to String values called {em symbols}. These symbols are the {templ} equivalent of
variables.>>>
        }

        {p
<<<Because the symbols which are used to map stored values in the stack are just ordinary String values, using
them in a {templ} expression has no special effect: it still just evaluates to the String itself, not to the
stored value. To get the stored value of a symbol from the stack, you can use the {code getset} function,
passing in the symbol you want to lookup.
>>>
        }

        {EXAMPLE-TEMPLATE "text"
            {implode
<<<As its name implies, the {code getset} function can also be used for setting the value of a symbol in the
stack. To do so, simply pass in two arguments to the {code getset} function: the symbol, and then the value to
store at that symbol. Both uses of {code getset} are shown in the following example template:>>>
            }

            {implode
<<<On the first line of the template, {code getset} is used in its "setting" form, with two arguments. The
symbol is first, "FOOBAR", and then the value, which is a self referential String. On the second line, it's
used in its "getting" form with just one argument, the symbol to lookup. One thing to notice is that this
template output the value twice. This is because the {code getset} function always results in the value of the
specified symbol, even when setting it.>>>
            }

"{getset FOOBAR \"The value of \\\"FOOBAR\\\".\"}
{getset FOOBAR}"

        }

    }}
        
}}{#


 vim: set ft=templ tw=110:
}