diff options
Diffstat (limited to 'tcllib/modules/textutil/expander.man')
-rw-r--r-- | tcllib/modules/textutil/expander.man | 511 |
1 files changed, 511 insertions, 0 deletions
diff --git a/tcllib/modules/textutil/expander.man b/tcllib/modules/textutil/expander.man new file mode 100644 index 0000000..c4873e8 --- /dev/null +++ b/tcllib/modules/textutil/expander.man @@ -0,0 +1,511 @@ +[comment {-*- tcl -*- doctools manpage}] +[manpage_begin textutil::expander n 1.3.1] +[see_also {[uri}] +[see_also http://www.wjduquette.com/expand] +[see_also regexp] +[see_also split] +[see_also string] +[keywords string] +[keywords {template processing}] +[keywords {text expansion}] +[copyright {William H. Duquette, http://www.wjduquette.com/expand}] +[moddesc {Text and string utilities, macro processing}] +[titledesc {Procedures to process templates and expand text.}] +[category {Documentation tools}] +[require Tcl 8.2] +[require textutil::expander [opt 1.3.1]] +[description] + +[para] + +The Tcl [cmd subst] command is often used to support a kind of +template processing. Given a string with embedded variables or +function calls, [cmd subst] will interpolate the variable and function +values, returning the new string: + +[para] + +[example { + % set greeting "Howdy" + Howdy + % proc place {} {return "World"} + % subst {$greeting, [place]!} + Howdy, World! + % +}] + +[para] + +By defining a suitable set of Tcl commands, [cmd subst] can be used to +implement a markup language similar to HTML. + +[para] + +The [cmd subst] command is efficient, but it has three drawbacks for +this kind of template processing: + +[list_begin itemized] + +[item] + +There's no way to identify and process the plain text between two +embedded Tcl commands; that makes it difficult to handle plain text in +a context-sensitive way. + +[item] + +Embedded commands are necessarily bracketed by [const [lb]] and +[const [rb]]; it's convenient to be able to choose different brackets +in special cases. Someone producing web pages that include a large +quantity of Tcl code examples might easily prefer to use [const <<] +and [const >>] as the embedded code delimiters instead. + +[item] + +There's no easy way to handle incremental input, as one might wish to +do when reading data from a socket. + +[list_end] + +[para] + +At present, expander solves the first two problems; eventually it will +solve the third problem as well. + +[para] + +The following section describes the command API to the expander; this +is followed by the tutorial sections, see [sectref TUTORIAL]. + +[section {EXPANDER API}] +[para] + +The [package textutil::expander] package provides only one command, +described below. The rest of the section is taken by a description of +the methods for the expander objects created by this command. + +[list_begin definitions] + +[call [cmd ::textutil::expander] [arg expanderName]] + +The command creates a new expander object with an associated Tcl +command whose name is [arg expanderName]. This command may be used to +invoke various operations on the graph. If the [arg expanderName] is +not fully qualified it is interpreted as relative to the current +namespace. The command has the following general form: + +[example_begin] +[arg expanderName] option [opt [arg {arg arg ...}]] +[example_end] + +[arg Option] and the [arg arg]s determine the exact behavior of the +command. + +[list_end] + +[para] + +The following commands are possible for expander objects: + +[list_begin definitions] + +[call [arg expanderName] [method cappend] [arg text]] + +Appends a string to the output in the current context. This command +should rarely be used by macros or application code. + +[call [arg expanderName] [method cget] [arg varname]] + +Retrieves the value of variable [arg varname], defined in the current +context. + +[call [arg expanderName] [method cis] [arg cname]] + +Determines whether or not the name of the current context is + +[arg cname]. + +[call [arg expanderName] [method cname]] + +Returns the name of the current context. + +[call [arg expanderName] [method cpop] [arg cname]] + +Pops a context from the context stack, returning all accumulated +output in that context. The context must be named [arg cname], or an +error results. + +[call [arg expanderName] [method ctopandclear]] + +Returns the output currently captured in the topmost context and +clears that buffer. This is similar to a combination of [method cpop] +followed by [method cpush], except that internal state (brackets) is +preserved here. + +[call [arg expanderName] [method cpush] [arg cname]] + +Pushes a context named [arg cname] onto the context stack. The +context must be popped by [method cpop] before expansion ends or an +error results. + +[call [arg expanderName] [method cset] [arg varname] [arg value]] + +Sets variable [arg varname] to [arg value] in the current context. + +[call [arg expanderName] [method cvar] [arg varname]] + +Retrieves the internal variable name of context variable + +[arg varname]; this allows the variable to be passed to commands like +[cmd lappend]. + +[call [arg expanderName] [method errmode] [arg newErrmode]] + +Sets the macro expansion error mode to one of [const nothing], +[const macro], [const error], or [const fail]; the default value is +[const fail]. The value determines what the expander does if an +error is detected during expansion of a macro. + +[list_begin definitions] +[def [const fail]] + +The error propagates normally and can be caught or ignored by the +application. + +[def [const error]] + +The macro expands into a detailed error message, and expansion +continues. + +[def [const macro]] + +The macro expands to itself; that is, it is passed along to the output +unchanged. + +[def [const nothing]] + +The macro expands to the empty string, and is effectively ignored. + +[list_end] +[para] + +[call [arg expanderName] [method evalcmd] [opt [arg newEvalCmd]]] + +Returns the current evaluation command, which defaults to + +[cmd {uplevel #0}]. If specified, [arg newEvalCmd] will be saved for +future use and then returned; it must be a Tcl command expecting one +additional argument: the macro to evaluate. + +[call [arg expanderName] [method expand] [arg string] [opt [arg brackets]]] + +Expands the input string, replacing embedded macros with their +expanded values, and returns the expanded string. + +[para] Note that this method pushes a new (empty) context on the stack of +contexts while it is running, and removes it on return. + +[para] + +If [arg brackets] is given, it must be a list of two strings; the +items will be used as the left and right macro expansion bracket +sequences for this expansion only. + +[call [arg expanderName] [method lb] [opt [arg newbracket]]] + +Returns the current value of the left macro expansion bracket; this is +for use as or within a macro, when the bracket needs to be included in +the output text. If [arg newbracket] is specified, it becomes the new +bracket, and is returned. + +[call [arg expanderName] [method rb] [opt [arg newbracket]]] + +Returns the current value of the right macro expansion bracket; this +is for use as or within a macro, when the bracket needs to be included +in the output text. If [arg newbracket] is specified, it becomes the +new bracket, and is returned. + +[call [arg expanderName] [method reset]] + +Resets all expander settings to their initial values. Unusual results +are likely if this command is called from within a call to + +[method expand]. + +[call [arg expanderName] [method setbrackets] [arg {lbrack rbrack}]] + +Sets the left and right macro expansion brackets. This command is for +use as or within a macro, or to permanently change the bracket +definitions. By default, the brackets are [const [lb]] and + +[const [rb]], but any non-empty string can be used; for example, +[const <] and [const >] or [const (*] and [const *)] or even +[const Hello,] and [const World!]. + +[call [arg expanderName] [method textcmd] [opt [arg newTextCmd]]] + +Returns the current command for processing plain text, which defaults +to the empty string, meaning [emph identity]. If specified, + +[arg newTextCmd] will be saved for future use and then returned; it +must be a Tcl command expecting one additional argument: the text to +process. The expander object will this command for all plain text it +encounters, giving the user of the object the ability to process all +plain text in some standard way before writing it to the output. The +object expects that the command returns the processed plain text. + +[para] + +[emph Note] that the combination of "[cmd textcmd] [arg plaintext]" +is run through the [arg evalcmd] for the actual evaluation. In other +words, the [arg textcmd] is treated as a special macro implicitly +surrounding all plain text in the template. + +[call [arg expanderName] [method where]] + +Returns a three-element list containing the current character +position, line, and column the expander is at in the processing of the +current input string. + +[list_end] + +[section TUTORIAL] +[subsection Basics] + +To begin, create an expander object: + +[para] +[example { + % package require textutil::expander + 1.2 + % ::textutil::expander myexp + ::myexp + % +}] +[para] + +The created [cmd ::myexp] object can be used to expand text strings +containing embedded Tcl commands. By default, embedded commands are +delimited by square brackets. Note that expander doesn't attempt to +interpolate variables, since variables can be referenced by embedded +commands: + +[para] +[example { + % set greeting "Howdy" + Howdy + % proc place {} {return "World"} + % ::myexp expand {[set greeting], [place]!} + Howdy, World! + % +}] + +[subsection {Embedding Macros}] + +An expander macro is simply a Tcl script embedded within a text +string. Expander evaluates the script in the global context, and +replaces it with its result string. For example, + +[para] +[example { + % set greetings {Howdy Hi "What's up"} + Howdy Hi "What's up" + % ::myexp expand {There are many ways to say "Hello, World!": + [set result {} + foreach greeting $greetings { + append result "$greeting, World!\\n" + } + set result] + And that's just a small sample!} + There are many ways to say "Hello, World!": + Howdy, World! + Hi, World! + What's up, World! + + And that's just a small sample! + % +}] + +[subsection {Writing Macro Commands}] + +More typically, [emph {macro commands}] are used to create a markup +language. A macro command is just a Tcl command that returns an +output string. For example, expand can be used to implement a generic +document markup language that can be retargeted to HTML or any other +output format: + +[para] +[example { + % proc bold {} {return "<b>"} + % proc /bold {} {return "</b>"} + % ::myexp expand {Some of this text is in [bold]boldface[/bold]} + Some of this text is in <b>boldface</b> + % +}] +[para] + +The above definitions of [cmd bold] and [cmd /bold] returns HTML, but +such commands can be as complicated as needed; they could, for +example, decide what to return based on the desired output format. + +[subsection {Changing the Expansion Brackets}] + +By default, embedded macros are enclosed in square brackets, + +[const [lb]] and [const [rb]]. If square brackets need to be +included in the output, the input can contain the [cmd lb] and + +[cmd rb] commands. Alternatively, or if square brackets are +objectionable for some other reason, the macro expansion brackets can +be changed to any pair of non-empty strings. + +[para] + +The [method setbrackets] command changes the brackets permanently. +For example, you can write pseudo-html by change them to [const <] +and [const >]: + +[para] +[example { + % ::myexp setbrackets < > + % ::myexp expand {<bold>This is boldface</bold>} + <b>This is boldface</b> +}] +[para] + +Alternatively, you can change the expansion brackets temporarily by +passing the desired brackets to the [method expand] command: + +[para] +[example { + % ::myexp setbrackets "\\[" "\\]" + % ::myexp expand {<bold>This is boldface</bold>} {< >} + <b>This is boldface</b> + % +}] + +[subsection {Customized Macro Expansion}] + +By default, macros are evaluated using the Tcl [cmd {uplevel #0}] +command, so that the embedded code executes in the global context. +The application can provide a different evaluation command using +[method evalcmd]; this allows the application to use a safe +interpreter, for example, or even to evaluated something other than +Tcl code. There is one caveat: to be recognized as valid, a macro +must return 1 when passed to Tcl's "info complete" command. + +[para] + +For example, the following code "evaluates" each macro by returning +the macro text itself. + +[para] +[example { + proc identity {macro} {return $macro} + ::myexp evalcmd identity +}] + +[subsection {Using the Context Stack}] + +Often it's desirable to define a pair of macros which operate in some +way on the plain text between them. Consider a set of macros for +adding footnotes to a web page: one could have implement something +like this: + +[para] +[example { + Dr. Pangloss, however, thinks that this is the best of all + possible worlds.[footnote "See Candide, by Voltaire"] +}] +[para] + +The [cmd footnote] macro would, presumably, assign a number to this +footnote and save the text to be formatted later on. However, this +solution is ugly if the footnote text is long or should contain +additional markup. Consider the following instead: + +[para] +[example { + Dr. Pangloss, however, thinks that this is the best of all + possible worlds.[footnote]See [bookTitle "Candide"], by + [authorsName "Voltaire"], for more information.[/footnote] +}] +[para] + +Here the footnote text is contained between [cmd footnote] and +[cmd /footnote] macros, continues onto a second line, and contains +several macros of its own. This is both clearer and more flexible; +however, with the features presented so far there's no easy way to do +it. That's the purpose of the context stack. + +[para] + +All macro expansion takes place in a particular context. Here, the +[cmd footnote] macro pushes a new context onto the context stack. +Then, all expanded text gets placed in that new context. + +[cmd /footnote] retrieves it by popping the context. Here's a +skeleton implementation of these two macros: + +[para] +[example { + proc footnote {} { + ::myexp cpush footnote + } + + proc /footnote {} { + set footnoteText [::myexp cpop footnote] + + # Save the footnote text, and return an appropriate footnote + # number and link. + } +}] +[para] + +The [method cpush] command pushes a new context onto the stack; the +argument is the context's name. It can be any string, but would +typically be the name of the macro itself. Then, [method cpop] +verifies that the current context has the expected name, pops it off +of the stack, and returns the accumulated text. + +[para] + +Expand provides several other tools related to the context stack. +Suppose the first macro in a context pair takes arguments or computes +values which the second macro in the pair needs. After calling +[method cpush], the first macro can define one or more context +variables; the second macro can retrieve their values any time before +calling [method cpop]. For example, suppose the document must specify +the footnote number explicitly: + +[para] +[example { + proc footnote {footnoteNumber} { + ::myexp cpush footnote + ::myexp csave num $footnoteNumber + # Return an appropriate link + } + + proc /footnote {} { + set footnoteNumber [::myexp cget num] + set footnoteText [::myexp cpop footnote] + + # Save the footnote text and its footnoteNumber for future + # output. + } +}] +[para] + +At times, it might be desirable to define macros that are valid only +within a particular context pair; such macros should verify that they +are only called within the correct context using either [method cis] +or [method cname]. + +[section HISTORY] + +[cmd expander] was written by William H. Duquette; it is a repackaging +of the central algorithm of the expand macro processing tool. + +[vset CATEGORY textutil] +[include ../doctools2base/include/feedback.inc] +[manpage_end] |