\newcommand e \renewcommand aninhados

\newcommand e \renewcommand aninhados

Lendo a aula twentysecondcv.clsnotei que existe um comando definido desta forma:

\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 que serve o \renewcommandinterior aninhado?\newcommand

A aula completa éno GitHub.

Responder1

Definir \skillsdesta forma tem o efeito de que, no primeiro uso, é necessário um argumento. Em seguida skillsé redefinido para armazenar este valor (mais algum processamento) de forma que a partir de agora o comando (sem argumento) reproduza o que foi configurado na primeira chamada.

Como exemplo, tome a definição

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

Quando você executa

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

then \mynameirá representar Stefanoa partir deste momento, ou seja, cada uso de \mynamewill typeset Stefano.

Responder2

TeX não possui variáveispor si sócomo outras linguagens de programação. Existem registros de propósito especial para armazenar coisas como contagens (inteiros), dimensões, fluxos de entrada e saída, listas de tokens, etc., mas na maior parte tudo é definido em termos de macros. Isso significa que para salvar informações em uma variável, em vez disso, define-se uma macro.

O que foi feito aqui não é idiomático e é limitado, pois agora o \skillscomando mudou seu significado irrevogavelmente e o usuário ingênuo da classe descobrirá resultados inesperados caso use \skillsduas vezes. Normalmente, em vez de redefinir o comando, alguém teria feito algo assim:

\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 armazenaria o valor \@skillspara uso posterior (nesta classe de documento, o uso posterior vem na \makeprofiledefinição do comando.

Uma coisa mais idiomática, na verdade, teria sido fazer

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

e então mover todo o tikzpictureambiente para a \makeprofiledefinição.

Responder3

O comando \makeprofileé definido 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}
}

e você deveria dizer \skills{x,y,z}antes de fazer \makeprofile.

Não acho uma boa programação, porque não verifica erros.

Seria melhor fazer

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

e em \makeprofile, em vez de ligar \skills, faça

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

Com esse código, a mensagem de erro se referiria exatamente ao que deu errado.

Também \skillstextparece não ser usado em nenhum lugar nos modelos fornecidos. Se alguém esquecer \skills, a chamada \makeprofileserá engolida \skillstext. Se nenhum \skilltextcomando aparecer, ele irá devorar \scriptsize, o que parece estar ali apenas com o propósito de ser engolido ou completamente ignorado.

Melhor ainda

\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}%
}

where \twentisecondscv@repeattambém pode ser usado para outros comandos que devem ser emitidos apenas uma vez.

informação relacionada