6
\$\begingroup\$

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}
\$\endgroup\$
4
\$\begingroup\$

About your points:

  1. The interface seems pretty clear.

  2. 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 a stretch key could help for these cases.

  3. Yes, you're abusing local and global assignments.

Some comments about the code:

  1. There is no point in the key alphabet to set a tl variable, which is then converted to a clist

  2. There's no need to set a .default:n for the font key: the value specified with .default:n would be used if the key is called without assigning a value

  3. \int_step_inline:nnnn can be done more simply using the * feature of tabular

  4. Never use \expandafter in expl3 code

  5. You should not use global assignments on local variables

  6. \clist_gpop:NN should be \clist_gpop_left:NN (but I changed it into \seq_pop_left:NN)

  7. 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}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.