\newcommand y \renewcommand anidados

\newcommand y \renewcommand anidados

Al leer la clase twentysecondcv.clsnoté que hay un comando definido de esta manera:

\newcommand\skills[1]{
    \renewcommand{\skills}{
        \begin{tikzpicture}
            \foreach [count=\i] \x/\y in {#1}{
                \draw[fill=maingray,maingray] (0,\i) rectangle (6,\i+0.4);
                \draw[fill=white,mainblue](0,\i) rectangle (\y,\i+0.4);
                \node [above right] at (0,\i+0.4) {\x};
            }
        \end{tikzpicture}
    }
}

¿Para qué se utiliza el \renewcommandinterior anidado \newcommand?

La clase completa esen GitHub.

Respuesta1

Definirlo \skillsde esta manera tiene el efecto de que, en el primer uso, necesita un argumento. Luego skillsse redefine para almacenar este valor (más algo de procesamiento) de modo que, de ahora en adelante, el comando (sin argumento) reproduzca aquello para lo que se configuró en la primera llamada.

Como ejemplo, tomemos la definición.

\newcommand\myname[1]{\renewcommand\myname{#1}}

cuando ejecutas

\myname{Stefano} % corresponds to \renewcommand\myname{Stefano}

entonces \mynamerepresentará Stefanoa partir de este momento en adelante, es decir, cada uso de \mynameserá tipografiado Stefano.

Respuesta2

TeX no tiene variablesper secomo otros lenguajes de programación. Hay registros de propósito especial para contener cosas como recuentos (enteros), dimensiones, flujos de entrada y salida, listas de tokens, etc. pero en su mayor parte todo está definido en términos de macros. Eso significa que, para guardar información en una variable, se define una macro.

Lo que se hizo aquí no es idiomático y está limitado en el sentido de que ahora el \skillscomando ha cambiado su significado irrevocablemente y el usuario ingenuo de la clase descubrirá resultados inesperados si la usa \skillsdos veces. Normalmente, en lugar de redefinir el comando, se habría hecho algo como esto:

\newcommand\skills[1]{
    \def\@skills{
        \begin{tikzpicture}
            \foreach [count=\i] \x/\y in {#1}{
                \draw[fill=maingray,maingray] (0,\i) rectangle (6,\i+0.4);
                \draw[fill=white,mainblue](0,\i) rectangle (\y,\i+0.4);
                \node [above right] at (0,\i+0.4) {\x};
            }
        \end{tikzpicture}
    }
}

que almacenaría el valor \@skillspara su uso posterior (en esta clase de documento, el uso posterior viene en la \makeprofiledefinición del comando).

De hecho, algo más idiomático habría sido hacer

\newcommand\skills[1]{\def\@skills{#1}}

y luego mover todo el tikzpictureentorno a la \makeprofiledefinición.

Respuesta3

El comando \makeprofilese define como

\newcommand{\makeprofile}{
    \begin{tikzpicture}[remember picture,overlay]
        \node [rectangle, fill=sidecolor, anchor=north, minimum width=9cm, minimum height=\paperheight+1cm] (box) at (-5cm,0.5cm){};
    \end{tikzpicture}

    %------------------------------------------------

    \begin{textblock}{6}(0.5, 0.2)
[...irrelevant code...]
        \profilesection{Skills}

        \skills
        \skillstext
        \scriptsize
        %(*)[The skill scale is from 0 (Fundamental Awareness) to 6 (Expert).]
            
        %------------------------------------------------
            
    \end{textblock}
}

y se supone que debes decirlo \skills{x,y,z}antes de hacerlo \makeprofile.

No me parece una buena programación, porque no puede comprobar si hay errores.

Sería mejor hacer

\newcommand{\skills}[1]{%
  \def\twentysecondscv@skills{...#1...}%
}

y en \makeprofile, en lugar de llamar \skills, hazlo

\ifdefined\twentysecondscv@skills
  \twentysecondscv@skills
\else
  \ClassError{twentysecondscv}
    {No \protect\skills found}
    {You need to define \protect\skills before doing \protect\makeprofile}%
\fi

Con este código, el mensaje de error se referiría exactamente a lo que salió mal.

Tampoco \skillstextparece usarse en ninguna parte de las plantillas proporcionadas. Si uno lo olvida \skills, la llamada \makeprofilesimplemente se tragará \skillstext. Si no \skilltextaparece ninguna orden, devorará \scriptsize, lo que parece estar ahí sólo con el propósito de ser tragado o ser ignorado por completo.

Aun mejor

\newcommand{\skills}[1]{%
  \def\twentysecondscv@skills{...#1...}%
  \renewcommand{\skills}[1]{\twentysecondscv@repeat{\skills}}%
}
\newcommand{\twentysecondscv@repeat}[1]{%
  \ClassError{twentysecondscv}
    {Multiple \protect#1 ignored}
    {You should have just one \protect#1 command}%
}

donde \twentisecondscv@repeattambién se puede utilizar para otros comandos que se supone que deben emitirse sólo una vez.

información relacionada