Verschachtelte \newcommand und \renewcommand

Verschachtelte \newcommand und \renewcommand

Beim Lesen der Klasse twentysecondcv.clsist mir aufgefallen, dass es einen Befehl gibt, der folgendermaßen definiert ist:

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

wofür wird das verschachtelte \renewcommandInnere \newcommandverwendet?

Die komplette Klasse istauf GitHub.

Antwort1

Diese Art der Definition \skillshat zur Folge, dass bei der ersten Verwendung ein Argument benötigt wird. Anschließend skillswird es neu definiert, um diesen Wert (plus einige Verarbeitungsschritte) zu speichern, sodass der Befehl (ohne Argument) von nun an das reproduziert, wofür er beim ersten Aufruf eingerichtet wurde.

Nehmen wir als Beispiel die Definition

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

Wenn Sie ausführen

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

„dann“ \mynamesteht Stefanovon diesem Moment an für , d. h. bei jeder Verwendung von \mynamewird gesetzt Stefano.

Antwort2

TeX hat keine Variablenan sichwie andere Programmiersprachen. Es gibt spezielle Register zum Speichern von Dingen wie Zählungen (Ganzzahlen), Dimensionen, Eingabe- und Ausgabeströmen, Tokenlisten usw., aber größtenteils wird alles in Form von Makros definiert. Das heißt, um Informationen in einer Variablen zu speichern, definiert man stattdessen ein Makro.

Was hier getan wurde, ist nicht idiomatisch und begrenzt, da der \skillsBefehl nun seine Bedeutung unwiderruflich geändert hat und der unerfahrene Benutzer der Klasse unerwartete Ergebnisse feststellen wird, wenn er ihn \skillszweimal verwendet. Normalerweise hätte man, anstatt den Befehl neu zu definieren, stattdessen etwas wie das Folgende getan:

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

dadurch wird der Wert für eine spätere Verwendung gespeichert \@skills(in dieser Dokumentklasse erfolgt die spätere Verwendung in der \makeprofileBefehlsdefinition).

Eine idiomatischere Sache wäre in der Tat gewesen,

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

tikzpictureund dann die gesamte Umgebung in die \makeprofileDefinition zu verschieben .

Antwort3

Der Befehl \makeprofileist definiert als

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

und Sie sollten es sagen, \skills{x,y,z}bevor Sie es tun \makeprofile.

Ich finde, das ist keine gute Programmierung, da hier keine Fehlerprüfung möglich ist.

Es wäre besser,

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

und in \makeprofile, statt anzurufen \skills, tun

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

Bei diesem Code würde die Fehlermeldung genau darauf verweisen, was schiefgelaufen ist.

Scheint auch \skillstextin den bereitgestellten Vorlagen nirgends verwendet zu werden. Wenn man es vergisst , wird \skillsder Aufruf \makeprofileeinfach geschluckt \skillstext. Wenn kein \skilltextBefehl erscheint, wird verschlungen \scriptsize, was anscheinend nur dazu da ist, geschluckt oder völlig ignoriert zu werden.

Noch besser

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

wobei dies \twentisecondscv@repeatauch für andere Befehle verwendet werden kann, die nur einmal ausgegeben werden sollen.

verwandte Informationen