cld-nicetoknow.tex /size: 5204 b    last modification: 2023-12-21 09:43
1% language=us runpath=texruns:manuals/cld
2
3\startcomponent cld-nicetoknow
4
5\environment cld-environment
6
7\startchapter[title=Nice to know]
8
9\startsection[title=Introduction]
10
11As we like to abstract interfaces it is no surprise that \CONTEXT\ and
12therefore it's \LUA\ libraries come with all kind of helpers. In this
13chapter I will explain a few of them. Feel free to remind of adding more
14here.
15
16\stopsection
17
18\startsection[title=Templates]
19
20{\em Eventually we will move this to the utilities section.}
21
22When dealing with data from tables or when order matters it can be handy
23to abstract the actual data from the way it is dealt with. For this we
24provide a template mechanism. The following example demonstrate its use.
25
26\startbuffer
27require("util-ran") -- needed for this example
28
29local preamble = [[|l|l|c|]]
30local template = [[\NC %initials% \NC %surname% \NC %length% \NC \NR]]
31
32context.starttabulate { preamble }
33    for i=1,10 do
34        local row = utilities.templates.replace(template, {
35            surname  = utilities.randomizers.surname(5,10),
36            initials = utilities.randomizers.initials(1,3),
37            length   = string.format("%0.2f",math.random(140,195)),
38        })
39        context(row)
40    end
41context.stoptabulate()
42\stopbuffer
43
44\typebuffer
45
46This renders a table with random entries:
47
48\ctxluabuffer
49
50The nice thing is that when we change the order of the columns, we don't need to
51change the table builder.
52
53\starttyping
54local preamble = [[|c|l|l|]]
55local template = [[\NC %length% \NC %initials% \NC %surname% \NC \NR]]
56\stoptyping
57
58The \type {replace} function takes a few more arguments. There are also a some
59more replacement options.
60
61\starttyping
62replace("test '%[x]%' test",{ x = [[a 'x'  a]] }))
63replace("test '%[x]%' test",{ x = true }))
64replace("test '%[x]%' test",{ x = [[a 'x'  a]], y = "oeps" },'sql'))
65replace("test '%[x]%' test",{ x = [[a '%y%'  a]], y = "oeps" },'sql',true))
66replace([[test %[x]% test]],{ x = [[a "x"  a]]}))
67replace([[test %(x)% test]],{ x = [[a "x"  a]]}))
68\stoptyping
69
70The first argument is the template and the second one a table with mappings from
71keys to values. The third argument can be used to inform the replace mechanism
72what string escaping has to happen. The last argument triggers recursive
73replacement. The above calls result in the following strings:
74
75\starttyping
76test 'a 'x' \127 a' test
77test 'true' test
78test 'a ''x''  a' test
79test 'a ''oeps''  a' test
80test a \"x\" \127 a test
81test "a \"x\" \127 a" test
82\stoptyping
83
84These examples demonstrate that by adding a pair of square brackets we get
85escaped strings. When using parenthesis the quotes get added automatically. This
86is somewhat faster in case when \LUA\ is the target, but in practice it is not
87that noticeable.
88
89% replace(str,mapping,how,recurse)
90
91\stopsection
92
93\startsection [title=Extending]
94
95Instead of extending tex endlessly we can also define our own extensions. Here
96is an example. When you want to manipulate a box at the \LUA\ end you have the
97problem that the following will not always work out well:
98
99\starttyping
100local b = tex.getbox(0)
101-- mess around with b
102tex.setbox(0,b)
103\stoptyping
104
105So we end up with:
106
107\starttyping
108local b = node.copylist(tex.getbox(0))
109-- mess around with b
110tex.setbox(0,b)
111\stoptyping
112
113The reason is that at the \TEX\ end grouping plays a role which means that values
114are saved and restored. However, there is a save way out by defining a function
115that cheats a bit:
116
117\starttyping
118function tex.takebox(id)
119    local box = tex.getbox(id)
120    if box then
121        local copy = node.copy(box)
122        local list = box.list
123        copy.list = list
124        box.list = nil
125        tex.setbox(id,nil)
126        return copy
127    end
128end
129\stoptyping
130
131Now we can say:
132
133\starttyping
134local b = tex.takebox(0)
135-- mess around with b
136tex.setbox(b)
137\stoptyping
138
139In this case we first get the box content and then let \TEX\ do some housekeeping.
140But, because we only keep the list node (which we copied) in the register the
141overhead of copying a whole list is gone.
142
143\stopsection
144
145% require("util-sto") require("char-def") require("char-ini")
146
147% local myformatter = utilities.strings.formatters.new()
148
149% string.addformatter("upper",  [[upper (%s)]],[[local upper  = characters.upper ]]) -- maybe handy
150% string.addformatter("lower",  [[lower (%s)]],[[local lower  = characters.lower ]]) -- maybe handy
151% string.addformatter("shaped", [[shaped(%s)]],[[local shaped = characters.shaped]]) -- maybe handy
152
153% utilities.strings.formatters.add("upper",  [[lpegmatch(p_toupper,%s)]],[[local p_toupper = lpeg.patterns.toupper]]) -- maybe handy
154% utilities.strings.formatters.add("lower",  [[lpegmatch(p_tolower,%s)]],[[local p_tolower = lpeg.patterns.tolower]]) -- maybe handy
155% utilities.strings.formatters.add("shaped", [[lpegmatch(p_toshape,%s)]],[[local p_toshape = lpeg.patterns.toshape]]) -- maybe handy
156
157% print("\n>>>",string.formatters["Is this %s handy or not?"](characters.upper("ÀÁÂÃÄÅàáâãäå")))
158% print("\n>>>",string.formatters["Is this %!upper! handy or not?"]("ÀÁÂÃÄÅàáâãäå"))
159% print("\n>>>",string.formatters["Is this %!shaped! handy or not?"]("ÀÁÂÃÄÅàáâãäå"))
160
161\stopchapter
162
163\stopcomponent
164