summaryrefslogtreecommitdiff
path: root/macros/luatex/latex/yamlvars/YAMLvars.tex
blob: e97b325df3b6b5f298d2e517deafc82e113ddfba (plain)
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
% Kale Ewasiuk (kalekje@gmail.com)
% 2021-09-24
%
% Copyright (C) 2021 Kale Ewasiuk
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
% of this software and associated documentation files (the "Software"), to deal
% in the Software without restriction, including without limitation the rights
% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
% copies of the Software, and to permit persons to whom the Software is
% furnished to do so, subject to the following conditions:
%
% The above copyright notice and this permission notice shall be included in
% all copies or substantial portions of the Software.
%
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
% ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
% TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
% PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
% SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
% ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
% ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
% OR OTHER DEALINGS IN THE SOFTWARE.


\documentclass{article}
\usepackage{url}
\usepackage{YAMLvars}
\setlength{\parindent}{0ex}
\setlength{\parskip}{0.75em}

\begin{document}

{\noindent\huge\bfseries YAMLvars \LARGE -- a YAML variable parser for LuaLaTeX}\\
    2021-09-24, Kale Ewasiuk, \url{kalekje@gmail.com}

YAMLvars is a LuaLaTeX-based package to help make definitions or produce LaTeX code using a YAML file.
This package might be useful for you if you want to batch create docummnts
by pushing various sets YAML data to a fixed LaTeX template,
or just find it easier to read document metadata from a YAML file compared to the
standard title, author, etc. commands.

\section{Package Options}
\leavevmode\llap{\texttt{useyv}\ \ \ }By default, when you specify a YAML variable, it will be defined using \texttt{gdef}
(only if it wasn't defined previously).
If you use this setting, unless otherwise specified, YAML variables will be accessible under
the \texttt{\textbackslash yv\{<var>\}} command.
This also allows numbers and symbols in the variable names.
Note that internally, the variables are stored in the command sequence
\texttt{yv--<var>}.

\leavevmode\llap{\texttt{parseCLI}\ \ \ }If this option is enabled, any arguments passed to your lualatex compile
command that end in ``.yaml'' will be used, separated by a space.
If two yaml files are passed, the first one will be the declaration file,
and the second will be the parsing file.
They will be used at the beginning of the document.
If one yaml file is passed, it will be treated as a parsing file, so you should
declare the variables somewhere in the preamble.
This option is offered to help with automation scripts.
An example is showin in Section \ref{example}.

\leavevmode\llap{\texttt{allowundeclared}\ \ \ }%
It might be helpful to define something in your YAML parsing doc without declaring it.
If you want this flexibility, use this setting. Note that eisting definitions will not be overwritten and an error
will br thrown if the name exists.

\section{Dependencies}
This package contains the \texttt{tinyyaml} Lua package.
If you want to use it for other purposes, you can bring it into Lua by either:
\begin{verbatim}
\directlua{yaml = YAMLvars.yaml}           or
\directlua{yaml = require('tinyyaml')}
\end{verbatim}
The distribution: \url{https://github.com/peposso/lua-tinyyaml}\\
The YAML specification: \url{https://yaml.org/spec/}\\

Many of the ``transform'' and ``processing'' functions built-in to this package rely on other packages.
\texttt{penlight},
\texttt{xspace},
\texttt{hyperref} for example.

\section{Declaring variables}
A declaration file can either be parsed with the command \texttt{declareYAMLvarsFile} command,
or, if you want to do it \LaTeX, you can put the YAML code in the \texttt{declareYAMLvars} environment.
It is a declaring YAML docuemnt is (like all YAML) key-value ditionary:
The top level key is the name of the variable to be defined/used.
If the value of the top level is a string: it's interpreted as a single transform function to be applied.
Otherwise, it must
be a table that contains at least one of the following keys:\\
\texttt{xfm} (transform, may be a string or list of strings),\\
\texttt{prc} (processing, must be a single string), or \\
\texttt{dft} (default value, if being defined. Must be a string).

The default value for variables is the Lua \texttt{nil}.
YAMLvars will first check if the definition exists, if so, an error will be thrown
so that we avoid overwriting.
If the token is available, it is set to a package error, so that if the variable no defined later on, an error will
tell the user they forgot to set it.
This will be overwritten when you parse the variables and assign a value to it.

You can change the default \texttt{xfm}, \texttt{prc}, or \texttt{dft} by changing
the value (in Lua): \texttt{YAMLvars.xfmDefault = ''} etc.

Here is an example of a declaration document.
\begin{verbatim}
\begin{declareYAMLvars}
Location: addxspace                      # sets xfm=addxspace
People: [arrsortlastnameAZ, list2nl]     # BAD! don't do.
People:
  xfm: [arrsortlastnameAZ, list2nl]      # Correct way
Company:
  dft: Amazon                            # Change default only
Revisions:
  dft: '1 & \today & initial version \\'
  xfm: [sortZA, list2tab]
Rhead:
  prc: setRightHead
\end{declareYAMLvars}
\end{verbatim}



\section{Parsing variables}
A YAML file to be parsed will contain the variables as the top level keys, similar to declaring.
The value can be anything you want; as long as you have applied appropriate transform and declaring
functions to it so that it can be useful. For example, a value specified as a YAML list will first be
interpreted as a Lua table (with numeric indexes/keys). You could declare a series of transforms functions
to sort this table, map functions, and convert it to a series of \LaTeX  \texttt{\textbackslash item}s.

Here is an example of a parsing document.


\begin{verbatim}
\begin{declareYAMLvars}
Location: Planet Earth
People:                # a YAML list
  - Some One           # turns into Lua table
  - No Body
# company assumed Amazon if not set here
Rhead: \today
\end{declareYAMLvars}
\end{verbatim}


 \section{xfm -- Transform Functions}
These functions accept two arguments: \texttt{(var, val)} where \texttt{var} is the variable (or key) and val is the value.
The transforms are specified as a list and are iteratively applied to the val.
Usually, the final \texttt{xfm} function should produce a string so it can be defined.

Hint: if for some reason, your \texttt{xfm} and \texttt{prc} depends on other variables,
you can access them within the function
with \texttt{YAMLvars.varsvals}

\subsection{Defining your own transform functions}
After the package is loaded, you may add your function (somewhere in Lua)
by adding it to the \texttt{YAMLvars.xfm} table.
For example, if you wanted to wrap a variable's value with ``xxx'', here's how you could do that.
\begin{verbatim}
function myfunction(var, val)
        return 'xxx'..val..'xxx'
end
YAMLvars.xfm['addmyfunction'] = myfunction
\end{verbatim}

  \section{prc -- Processing Functions}
Like the transform functions, the processing function must accept \texttt{(var, val)}.
Only one processing function is applied to the final (var, val) after the transforms are done.

This package includes \texttt{gdef} to set a definition, \texttt{yvdef} to define a variable under the \texttt{yv} command.
\texttt{title, author, date} to set \texttt{\textbackslash @title, \textbackslash @author, \textbackslash @date},
respectively

    \section{Example}\label{example}

    Suppose you had a number of bills of sales in yaml format and wanted to produce some nice pdfs.
    The following code shows how this could be done.

    \pagebreak
    \vspace*{-5em}
    \subsection{The main tex template}
    \begin{verbatim}
 %% main.tex
\documentclass{article}
\usepackage[paperheight=4in,paperwidth=3in,margin=0.25in]{geometry}
\usepackage[pl,func,extras]{penlight}
\usepackage[useyv,parseCLI]{YAMLvars}  % using command line option to make files
\usepackage{hyperref}
\usepackage{xspace}
\usepackage{luacode}

\setlength{\parindent}{0ex}
\setlength{\parskip}{0.75em}

\begin{luacode*} -- adding a custom function, put hfill between k-v pairs
    function YAMLvars.xfm.kv2hfill(var, val)
        local t = {}
        for k, v in pairs(val) do
            t[#t+1] = k..'\\hfill '..tostring(v)
        end
        return t
    end
\end{luacode*}


%! language = yaml
\begin{declareYAMLvars}
Customer: addxspace
Date: addxspace
Items:
    xfm: [kv2hfill, arr2itemize]
\end{declareYAMLvars}

\begin{document}
    Bill of sale for: \hfill \yv{Customer}\\
    Purchased: \hfill \yv{Date}\\
    \begin{itemize}
        \item[] ITEM \hfill PRICE
        \yv{Items}             % the yaml variable
        \begin{luacode*}
            totalcost = pl.tablex.reduce('+',
                pl.tablex.values(YAMLvars.varsvals['Items']), 0)
            tex.print('\\item[] TOTAL:\\hfill'..tostring(totalcost))
        \end{luacode*}
    \end{itemize}
\end{document}
    \end{verbatim}

    \subsection{The lua automation script}
    \begin{verbatim}
--automate.lua
for f in io.popen('dir .'):lines() do  -- get all files and info in cwd
    local i, j = f:find('%S*%.yaml')  --  find fnames
    if i ~= nil then
        f = f:sub(i,j) --  extract .yaml file name (no space in fname allowed)
        os.execute('lualatex -output-format=pdf main.tex '.. f)
                                    -- compile w/ yaml file as arg
        local fnew = f:gsub('yaml', 'pdf') -- file name for output pdf
        os.remove(fnew) -- delete if it exists already
        os.rename('main.pdf', fnew) -- change main.pdf to same as yaml file name
    end
end
    \end{verbatim}

\subsection{The yaml data files}
    \begin{verbatim}
# sale1.yaml
Customer: Someone Cold
Date: January 2, 2021
Items:
    Toque: 12
    Mitts: 5.6
    Boots: 80

# sale2.yaml
Customer: Someone Warm
Date: July 1, 2021
Items:
    Beer (24 pk): 24
    Sunscreen: 5
    Hat: 12
    \end{verbatim}
\end{document}