ネストされた \newcommand と \renewcommand

ネストされた \newcommand と \renewcommand

クラスを読んでいると、twentysecondcv.cls次のように定義されたコマンドがあることに気付きました。

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

ネストされた\renewcommand内部は何\newcommandに使用されますか?

完全なクラスはGitHubで

答え1

このように定義すると\skills、最初の使用時に引数が必要になります。その後、skillsこの値 (およびいくつかの処理) を格納するように再定義され、今後はコマンド (引数なし) が最初の呼び出し時に設定された内容を再現します。

例として、定義を見てみましょう

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

実行すると

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

then は、この瞬間から\mynameを表します。つまり、 を使用するたびに とタイプセットされます。Stefano\mynameStefano

答え2

TeXには変数がありませんそれ自体他のプログラミング言語と同様です。カウント (整数)、次元、入出力ストリーム、トークン リストなどを保持するための専用レジスタがありますが、ほとんどすべてがマクロで定義されています。つまり、変数に情報を保存するには、代わりにマクロを定義します。

ここで行われたことは非慣用的であり、\skillsコマンドの意味が取り返しのつかないほど変わってしまったため、クラスの初心者のユーザーが\skills2 回使用すると予期しない結果が発生するという点で制限があります。通常は、コマンドを再定義するのではなく、次のようにします。

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

後で使用するために値を保存します\@skills(このドキュメント クラスでは、後の使用はコマンド\makeprofile定義内にあります)。

もっと慣用的な言い方は、

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

そして、tikzpicture環境全体を定義に移動します\makeprofile

答え3

コマンドは\makeprofile次のように定義されます

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

\skills{x,y,z}そして、それをする前に言う必要があります\makeprofile

これは間違いをチェックできないので、良いプログラミングとは言えません。

そうした方が良いでしょう

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

そして では\makeprofile、 を呼び出す代わりに\skills

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

このコードを使用すると、エラー メッセージには何が問題なのかが正確に示されます。

また、\skillstext提供されているテンプレートではどこにも使用されていないようです。忘れた場合、\skills呼び出しは\makeprofile単に を飲み込みます\skillstext\skilltextコマンドが表示されない場合は を飲み込みますが\scriptsize、これは飲み込まれるか完全に無視されるためだけに存在しているようです。

さらに良い

\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@repeat、1 回だけ発行されることになっている他のコマンドにも使用できます。

関連情報