# Declare commands that can only be used inside others commands

I am new to Latex and I am creating my own CV class.

I want to be able to use commands I create in my class inside other commands, so they can be grouped around specific topics. Here is one snippet I created to ilustrate what I want to accomplish:

\documentclass[11pt,a4paper]{my-cv}

\CVInfo{
\FirstName{myFirstName}
\LastName{myLastName}
\Email{myEmail}
\Phone{myPhone}
\Picture{myPicture}
\RoundedPictureOptions{
\PictureScale{0.4}
\PictureXShift{-0.1cm}
\PictureYShift{-0.4cm}
\PictureBorder{
\PictureBorderIsDashed{Y}
\PictureBorderThickness{thick}
\PictureBorderColor{blue}
}
}
}

\begin{document}
...
\end{document}



As you can see, all information about the CV is inside the \CVInfo command, all information about the border of the picture is inside the \PictureBorder command, and so on.

Inside the class, these commands should only set some values to internal commands that would be used elsewhere:

\newcommand{\FirstName}[1]{
\def\@firstName{#1}
}


To summarize, I want to the use of that commands to be strictly the way its shown in the code above, i.e., this:

\FirstName{myFirstName}
\CVInfo{
...
}


and this:

\CVInfo{
...
}
\FirstName{myFirstName}


should do nothing to the \FirstName command.

Is there a way to do this? Anyway, Im not quite sure if this is the approach I should take when creating my own class, so feel free to share any comment about a better way to do this.

Thank you!

• I think one approach would be to have the \CVInfo macro set a switch, and then have the inside commands check for whether that switch is true. But I think the pgfkeys solution below is better. – Seamus Aug 12 '20 at 14:34
• What do you mean by "...should do nothing to the \FirstName command." ? Shall the command \FirstName not be executed and thus \@firstName not be redefined? – Ulrich Diez Aug 13 '20 at 7:32

If you prefer a macro-interface to a key=value-interface, you can define commands \FirstName, \LastName, etc, to append to a token-register directives for redefining the internal macros. If you do this, you need to make sure that within the .tex-input-file every line inside the optional argument of \CVInfo ends with either a comment-character or something that gets tokenized as a control-word-token. Otherwise undesired space-tokens and thus undesired horizontal glue might come into being at places where lines inside the argument of \CVInfo end with } or some other thing that does not get tokenized as a control-word-token.

\documentclass[11pt,a4paper]{article}

\makeatletter
\newtoks\CVInfotoks
\newcommand\DefineDontUseTheCommandHereError[2]{%
\renewcommand#1[1]{\DontUseTheCommandHereError{#1}{#2}}%
}%
\newcommand\DefineDontUseTheCommandOptHereError[2]{%
\renewcommand#1[1][]{\DontUseTheCommandHereError{#1}{#2}}%
}%
\newcommand\DontUseTheCommandHereError[2]{%
\ClassError{my-cv}{%
You can't execute the command \string#1 within the argument of the command \string#2%
}{%
Executing the command \string#1 within the argument of the command \string#2 seems not to make sense.%
}%
}%
% Initial values:
\newcommand*\MyCV@firstName{myFirstName}%
\newcommand*\MyCV@lastName{myLastName}%
\newcommand*\MyCV@Email{myEmail}%
\newcommand*\MyCV@Phone{myPhone}%
\newcommand*\MyCV@Picture{myPicture}%
\newcommand*\MyCV@PictureScale{0.4}%
\newcommand*\MyCV@PictureXShift{-0.1cm}%
\newcommand*\MyCV@PictureYShift{-0.4cm}%
\newcommand*\MyCV@PictureBorderIsDashed{Y}%
\newcommand*\MyCV@PictureBorderThickness{thick}%
\newcommand*\MyCV@PictureBorderColor{blue}%
%
\newcommand\CVInfo[1][]{%
\begingroup
\CVInfotoks{}%
\DefineDontUseTheCommandOptHereError{\CVInfo}{\CVInfo}%
\long\def\FirstName##1{\CVInfotoks=\expandafter{\the\CVInfotoks\def\MyCV@firstName{##1}}}%
\long\def\LastName##1{\CVInfotoks=\expandafter{\the\CVInfotoks\def\MyCV@lastName{##1}}}%
\long\def\Email##1{\CVInfotoks=\expandafter{\the\CVInfotoks\def\MyCV@Email{##1}}}%
\long\def\Phone##1{\CVInfotoks=\expandafter{\the\CVInfotoks\def\MyCV@Phone{##1}}}%
\long\def\Picture##1{\CVInfotoks=\expandafter{\the\CVInfotoks\def\MyCV@Picture{##1}}}%
\newcommand\RoundedPictureOptions[1]{%
\begingroup
\DefineDontUseTheCommandOptHereError{\CVInfo}{\RoundedPictureOptions}%
\DefineDontUseTheCommandHereError{\RoundedPictureOptions}{\RoundedPictureOptions}%
\DefineDontUseTheCommandHereError{\FirstName}{\RoundedPictureOptions}%
\DefineDontUseTheCommandHereError{\LastName}{\RoundedPictureOptions}%
\DefineDontUseTheCommandHereError{\Email}{\RoundedPictureOptions}%
\DefineDontUseTheCommandHereError{\Phone}{\RoundedPictureOptions}%
\DefineDontUseTheCommandHereError{\Picture}{\RoundedPictureOptions}%
\long\def\PictureScale####1{\CVInfotoks=\expandafter{\the\CVInfotoks\def\MyCV@PictureScale{####1}}}%
\long\def\PictureXShift####1{\CVInfotoks=\expandafter{\the\CVInfotoks\def\MyCV@PictureXShift{####1}}}%
\long\def\PictureYShift####1{\CVInfotoks=\expandafter{\the\CVInfotoks\def\MyCV@PictureYShift{####1}}}%
\newcommand\PictureBorder[1]{%
\begingroup
\DefineDontUseTheCommandOptHereError{\CVInfo}{\PictureBorder}%
\DefineDontUseTheCommandHereError{\RoundedPictureOptions}{\PictureBorder}%
\DefineDontUseTheCommandHereError{\FirstName}{\PictureBorder}%
\DefineDontUseTheCommandHereError{\LastName}{\PictureBorder}%
\DefineDontUseTheCommandHereError{\Email}{\PictureBorder}%
\DefineDontUseTheCommandHereError{\Phone}{\PictureBorder}%
\DefineDontUseTheCommandHereError{\Picture}{\PictureBorder}%
\DefineDontUseTheCommandHereError{\PictureBorder}{\PictureBorder}%
\DefineDontUseTheCommandHereError{\PictureScale}{\PictureBorder}%
\DefineDontUseTheCommandHereError{\PictureXShift}{\PictureBorder}%
\DefineDontUseTheCommandHereError{\PictureYShift}{\PictureBorder}%
\long\def\PictureBorderIsDashed########1{\CVInfotoks=\expandafter{\the\CVInfotoks\def\MyCV@PictureBorderIsDashed{########1}}}%
\long\def\PictureBorderThickness########1{\CVInfotoks=\expandafter{\the\CVInfotoks\def\MyCV@PictureBorderThickness{########1}}}%
\long\def\PictureBorderColor########1{\CVInfotoks=\expandafter{\the\CVInfotoks\def\MyCV@PictureBorderColor{########1}}}%
####1%
\expandafter\endgroup
\expandafter\CVInfotoks\expandafter=\expandafter{\the\CVInfotoks}%
}%
##1%
\expandafter\endgroup
\expandafter\CVInfotoks\expandafter=\expandafter{\the\CVInfotoks}%
}%
#1%
\expandafter\endgroup\the\CVInfotoks
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\message{%
^^J%
Internal macros are now defined as follows:^^J%
\string\MyCV@firstName: \meaning\MyCV@firstName^^J%
\string\MyCV@lastName: \meaning\MyCV@lastName^^J%
\string\MyCV@Email: \meaning\MyCV@Email^^J%
\string\MyCV@Phone: \meaning\MyCV@Phone^^J%
\string\MyCV@Picture: \meaning\MyCV@Picture^^J%
\string\MyCV@PictureScale: \meaning\MyCV@PictureScale^^J%
\string\MyCV@PictureXShift: \meaning\MyCV@PictureXShift^^J%
\string\MyCV@PictureYShift: \meaning\MyCV@PictureYShift^^J%
\string\MyCV@PictureBorderIsDashed: \meaning\MyCV@PictureBorderIsDashed^^J%
\string\MyCV@PictureBorderThickness: \meaning\MyCV@PictureBorderThickness^^J%
\string\MyCV@PictureBorderColor: \meaning\MyCV@PictureBorderColor^^J%
}%
}%
\makeatother

\newcommand\FirstName{Outside \string\CVInfo this command is totally different.}

\CVInfo

\CVInfo[%
\FirstName{John}%
\LastName{Doe}%
\Picture{JohnDoe.jpg}%
\RoundedPictureOptions{%
% \LastName{Smith} % uncomment to see the error-message.
% \CVInfo % uncomment to see the error-message.
% \CVInfo[] % uncomment to see the error-message.
\PictureScale{0.8}%
\PictureYShift{0.8cm}%
\PictureBorder{%
\PictureBorderIsDashed{N}%
\PictureBorderThickness{not so thick}%
\PictureBorderColor{red}%
}%
\PictureXShift{0.6cm}%
}%
\Email{john\string@doe.com}%
\Phone{123456}%
]%

\message{^^J\string\FirstName: \meaning\FirstName}
\message{^^J^^J\string\Email: \meaning\Email^^J^^J}

\begin{document}

\end{document}


When compiling the example above, the terminal provides the following messages:

This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2019/dev/Debian) (preloaded format=pdflatex)
\write18 enabled.
entering extended mode
(./test.tex
LaTeX2e <2018-12-01>
(/usr/share/texlive/texmf-dist/tex/latex/base/article.cls
Document Class: article 2018/09/03 v1.4i Standard LaTeX document class
(/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo))
(/usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty
(/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex
(/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeysfiltered.code.t
ex)))

Internal macros are now defined as follows:
\@Firstname: macro:->myFirstName
\@Lastname: macro:->myLastName
\@Email: macro:->myEmail
\@Phone: macro:->myPhone
\@Picture: macro:->myPicture
\@Picturescale: macro:->0.4
\@Picturexshift: macro:->-0.1cm
\@Pictureyshift: macro:->-0.4cm
\ifdashedborder: \iftrue
\@Pictureborderthickness: macro:->thick
\@Picturebordercolor: macro:->blue

Internal macros are now defined as follows:
\@Firstname: macro:->John
\@Lastname: macro:->Doe
\@Email: macro:->john\string @doe.com
\@Phone: macro:->123456
\@Picture: macro:->JohnDoe.jpg
\@Picturescale: macro:->0.8
\@Picturexshift: macro:->0.6cm
\@Pictureyshift: macro:->0.8cm
\ifdashedborder: \iffalse
\@Pictureborderthickness: macro:->not so thick
\@Picturebordercolor: macro:->red
(./test.aux) (./test.aux) )
No pages of output.
Transcript written on test.log.


The so-called key-tree of the pgfkeys package also serves as a database for storing whatsoever pieces of data.

Instead of defining internal macros, you can use \pgfkeysvalueof for obtaining values of value-keys:

\documentclass{article}

\usepackage{pgfkeys}

\makeatletter
\newif\ifdashedborder\dashedborderfalse
\pgfkeys{%
/CVInfo/RoundedPictureOptions/Border/dashed/.is if=dashedborder,
/CVInfo/RoundedPictureOptions/Border/dashed=true,
/CVInfo/RoundedPictureOptions/Border/dashed/.value required,
/CVInfo/first name/.value required, /CVInfo/first name/.initial=myFirstName,
/CVInfo/last name/.value required, /CVInfo/last name/.initial=myLastName,
/CVInfo/email/.value required, /CVInfo/email/.initial=myEmail,
/CVInfo/phone/.value required, /CVInfo/phone/.initial=myPhone,
/CVInfo/picture/.value required, /CVInfo/picture/.initial=myPicture,
/CVInfo/RoundedPictureOptions/scale/.value required, /CVInfo/RoundedPictureOptions/scale/.initial=0.4,
/CVInfo/RoundedPictureOptions/x shift/.value required, /CVInfo/RoundedPictureOptions/x shift/.initial=-0.1cm,
/CVInfo/RoundedPictureOptions/y shift/.value required, /CVInfo/RoundedPictureOptions/y shift/.initial=-0.4cm,
/CVInfo/RoundedPictureOptions/Border/thickness/.value required, /CVInfo/RoundedPictureOptions/Border/thickness/.initial=thick,
/CVInfo/RoundedPictureOptions/Border/color/.value required, /CVInfo/RoundedPictureOptions/Border/color/.initial=blue,
/CVInfo/RoundedPictureOptions/.code=\pgfkeys{/CVInfo/RoundedPictureOptions/.cd,#1},
/CVInfo/RoundedPictureOptions/.value required,
/CVInfo/RoundedPictureOptions/Border/.code=\pgfkeys{/CVInfo/RoundedPictureOptions/Border/.cd,#1},
/CVInfo/RoundedPictureOptions/Border/.value required
}%

\newcommand\CVInfo[1][]{%
\pgfkeys{/CVInfo/.cd,#1}%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\message{%
^^J%
Values of keys are set as follows:^^J%
/CVInfo/first name=\pgfkeysvalueof{/CVInfo/first name}^^J%
/CVInfo/last name=\pgfkeysvalueof{/CVInfo/last name}^^J%
/CVInfo/email=\pgfkeysvalueof{/CVInfo/email}^^J%
/CVInfo/phone=\pgfkeysvalueof{/CVInfo/phone}^^J%
/CVInfo/picture=\pgfkeysvalueof{/CVInfo/picture}^^J%
/CVInfo/RoundedPictureOptions/scale=\pgfkeysvalueof{/CVInfo/RoundedPictureOptions/scale}^^J%
/CVInfo/RoundedPictureOptions/x shift=\pgfkeysvalueof{/CVInfo/RoundedPictureOptions/x shift}^^J%
/CVInfo/RoundedPictureOptions/y shift=\pgfkeysvalueof{/CVInfo/RoundedPictureOptions/y shift}^^J%
\string\ifdashedborder: \meaning\ifdashedborder^^J%
/CVInfo/RoundedPictureOptions/Border/thickness=\pgfkeysvalueof{/CVInfo/RoundedPictureOptions/Border/thickness}^^J%
/CVInfo/RoundedPictureOptions/Border/color=\pgfkeysvalueof{/CVInfo/RoundedPictureOptions/Border/color}^^J%
}%
}%

\makeatother

\CVInfo

\CVInfo[%
first name=John,
last name=Doe,
picture=JohnDoe.jpg,
RoundedPictureOptions={%
scale=0.8,
x shift=0.6cm,
y shift=0.8cm,
Border={%
dashed=false,
thickness=not so thick,
color=red
}%
},
email=john\string@doe.com,
phone=123456
]

\begin{document}

\end{document}


When compiling the example above, the terminal will tell you the following:

\$ pdflatex -shell-escape test.tex
This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2019/dev/Debian) (preloaded format=pdflatex)
\write18 enabled.
entering extended mode
(./test.tex
LaTeX2e <2018-12-01>
(/usr/share/texlive/texmf-dist/tex/latex/base/article.cls
Document Class: article 2018/09/03 v1.4i Standard LaTeX document class
(/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo))
(/usr/share/texlive/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty
(/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex
(/usr/share/texlive/texmf-dist/tex/generic/pgf/utilities/pgfkeysfiltered.code.t
ex)))

Values of keys are set as follows:
/CVInfo/first name=myFirstName
/CVInfo/last name=myLastName
/CVInfo/email=myEmail
/CVInfo/phone=myPhone
/CVInfo/picture=myPicture
/CVInfo/RoundedPictureOptions/scale=0.4
/CVInfo/RoundedPictureOptions/x shift=-0.1cm
/CVInfo/RoundedPictureOptions/y shift=-0.4cm
\ifdashedborder: \iftrue
/CVInfo/RoundedPictureOptions/Border/thickness=thick
/CVInfo/RoundedPictureOptions/Border/color=blue

Values of keys are set as follows:
/CVInfo/first name=John
/CVInfo/last name=Doe
/CVInfo/email=john@doe.com
/CVInfo/phone=123456
/CVInfo/picture=JohnDoe.jpg
/CVInfo/RoundedPictureOptions/scale=0.8
/CVInfo/RoundedPictureOptions/x shift=0.6cm
/CVInfo/RoundedPictureOptions/y shift=0.8cm
\ifdashedborder: \iffalse
/CVInfo/RoundedPictureOptions/Border/thickness=not so thick
/CVInfo/RoundedPictureOptions/Border/color=red
(./test.aux) (./test.aux) )
No pages of output.
Transcript written on test.log.


You may wish to turn /CVInfo/RoundedPictureOptions/Border/thickness into a choice-key.