I'm trying to generate a vigenere square using expl3. My aim is to provide an easy interface for different alphabets and different scaling. Therefore I chose a tabular-based approach which seemed very easy to customize.
Points I would especially appreciate feedback to:
- Is using tabular a good idea or might it be very bad (e.g. when the user customizes array stretches)?
- Am I abusing expl3 at any point (local vs. global)?
- the user interface in general (key-value approach)
Code:
\documentclass{article}
\usepackage[landscape]{geometry}
\usepackage{xparse}
\ExplSyntaxOn
\keys_define:nn { vigenere }
{
font .code:n = { \cs_set_eq:NN \__vigenere_font: #1 },
font .default:n = { \small },
font .initial:n = { \small },
tabcolsep .dim_set:N = \l__vigenere_tabcolsep_dim,
tabcolsep .initial:n = { 3pt },
alphabet .tl_set:N = \l__vigenere_alphabet_tl,
alphabet .initial:n = { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z }
}
\NewDocumentCommand { \printvigeneretabular } { O{} }
{
\group_begin:
\keys_set:nn { vigenere } { #1 }
\clist_set:NV \l_tmpa_clist \l__vigenere_alphabet_tl
\clist_clear:N \l_tmpb_clist
\tl_clear:N \l_tmpa_tl
\int_step_inline:nnnn { 1 } { 1 } { \clist_count:N \l_tmpa_clist }
{
\tl_put_right:Nx \l_tmpa_tl { c| }
}
\__vigenere_font:
\dim_set_eq:NN \tabcolsep \l__vigenere_tabcolsep_dim
\expandafter\tabular\expandafter{\expandafter|\l_tmpa_tl}
\hline
\bool_while_do:nn { \int_compare_p:n { \clist_count:N \l_tmpa_clist > 0 } }
{
\clist_use:Nnnn \l_tmpa_clist { & } { & } { & }
\clist_if_empty:NF \l_tmpb_clist
{ & \clist_use:Nnnn \l_tmpb_clist { & } { & } { & } }
\clist_gpop:NN \l_tmpa_clist \l_tmpa_tl
\clist_gput_right:NV \l_tmpb_clist \l_tmpa_tl
\\\hline
}
\endtabular
\group_end:
}
\ExplSyntaxOff
\begin{document}
\printvigeneretabular\par
\printvigeneretabular[font=\tiny,alphabet={1,2,3,4,5,6,7,8,9,10},tabcolsep=1pt]
\end{document}
1 Answer 1
About your points:
The interface seems pretty clear.
If you fear about the
\arraystretch
parameter being abused, you're right: on a double spaced document all tables come out horribly and local remedies are often necessary. Maybe adding astretch
key could help for these cases.Yes, you're abusing local and global assignments.
Some comments about the code:
There is no point in the key
alphabet
to set a tl variable, which is then converted to aclist
There's no need to set a
.default:n
for thefont
key: the value specified with.default:n
would be used if the key is called without assigning a value\int_step_inline:nnnn
can be done more simply using the*
feature oftabular
Never use
\expandafter
inexpl3
codeYou should not use global assignments on local variables
\clist_gpop:NN
should be\clist_gpop_left:NN
(but I changed it into\seq_pop_left:NN
)One can do with a simpler loop, using
\prg_replicate:nn
I'd also prefer to prepare the table body outside the table, with sequences instead of clists, which are less efficient.
\documentclass{article}
\usepackage[landscape]{geometry}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand { \printvigeneretabular } { O{} }
{
\vigenere_tabular:n { #1 }
}
% keys
\keys_define:nn { vigenere }
{
font .code:n = { \cs_set_eq:NN \__vigenere_font: #1 },
font .initial:n = { \small },
tabcolsep .dim_set:N = \l__vigenere_tabcolsep_dim,
tabcolsep .initial:n = { 3pt },
alphabet .clist_set:N = \l__vigenere_alphabet_clist,
alphabet .initial:n = { A, B, C, D, E, F, G, H, I, J, K, L, M,
N, O, P, Q, R, S, T, U, V, W, X, Y, Z }
}
% variables
\tl_new:N \l__vigenere_tablebody_tl
\seq_new:N \l__vigenere_alphabet_seq
% internal function
\cs_new_protected:Nn \vigenere_tabular:n
{
\group_begin:
% set the keys
\keys_set:nn { vigenere } { #1 }
% make a sequence from the alphabet
\seq_set_from_clist:NN \l__vigenere_alphabet_seq \l__vigenere_alphabet_clist
% set the font and the tabcolsep
\__vigenere_font:
\dim_set_eq:NN \tabcolsep \l__vigenere_tabcolsep_dim
% prepare the table body
\tl_clear:N \l__vigenere_tablebody_tl
\prg_replicate:nn { \seq_count:N \l__vigenere_alphabet_seq }
{
\tl_put_right:Nx \l__vigenere_tablebody_tl
{
\seq_use:Nn \l__vigenere_alphabet_seq { & }
\exp_not:n { \\ \hline }
}
\seq_pop_left:NN \l__vigenere_alphabet_seq \l_tmpa_tl
\seq_put_right:NV \l__vigenere_alphabet_seq \l_tmpa_tl
}
% make the table
\tabular { | *{\clist_count:N \l__vigenere_alphabet_clist }{ c| } }
\hline
\tl_use:N \l__vigenere_tablebody_tl
\endtabular
\group_end:
}
\ExplSyntaxOff
\begin{document}
\printvigeneretabular
\printvigeneretabular[font=\tiny,alphabet={1,2,3,4,5,6,7,8,9,10},tabcolsep=1pt]
\end{document}