# Latex dynamic macro definition

I am trying to dynamically define variables. What I want to do is be able to define a person in the following way \definePerson{MrTestKey}{Mr Test}{0400 000 000}{mr@test.com} and then subsequently call \nameMrTestKey to return "Mr Test", \phoneMrTestKey to return "0400 000 000" and \emailMrTestKey to return "mr@test.com".

This is what I have tried so far... I use the \defineVariable macro so that I can call \nameMrTestKey to return a formatted (\emph) name and \nameMrTestKey* to return an unformatted name.

% To allow (un)formatted variables
% See http://tex.stackexchange.com/questions/51652/remove-formatting/
\usepackage{xparse}
\NewDocumentCommand\defineVariable{mmm}{%
\NewDocumentCommand#1{s}{\IfBooleanTF{##1}{#3}{#2{#3}}}%
}

% \definePerson{key}{name}{phone}{email}
\newcommand\definePerson[4]{%
\defineVariable\name#1{\emph}{#2}
\defineVariable\phone#1{\emph}{#3}%
\defineVariable\email#1{\emph}{#4}%
}

-
 Why not use a key value syntax instead? \definePerson[MrTest][name={Mr Test}, phone={...}, email={...}]. For multiple arguments like this, IMHO a key value syntax is easier to remember than the order of the arguments. – Aditya Jul 20 '12 at 13:56

You need to use \csname ... \endcsname to create a control sequence with the desired name. So the following creates a macro named \nameMrTestKey with the value being \emph{Mr Test} if called with \definePerson{MrTestKey}{Mr Test}...

\expandafter\newcommand\csname name#1\endcsname{\emph{#2}}


The name in the control sequence name is hard coded, and MrTestKey is the first parameter passed to \definePerson.

The \expandafter is required as the \newcommand needs to be dealt with after the \csname. See follow-up question: How to know whether or not we need \expandafter?

## Code:

\documentclass{article}

\newcommand\definePerson[4]{%
\expandafter\newcommand\csname name#1\endcsname{\emph{#2}}
\expandafter\newcommand\csname phone#1\endcsname{\emph{#3}}
\expandafter\newcommand\csname email#1\endcsname{\emph{#4}}
}

\begin{document}

\definePerson{MrTestKey}{Mr Test}{0400 000 000}{mr@test.com}

Name is \nameMrTestKey

Phone is \phoneMrTestKey

\end{document}


\documentclass{article}

\usepackage{xparse}
\NewDocumentCommand\defineVariable{mmmm}{%
\global\expandafter\NewDocumentCommand\csname#1#2\endcsname{s}{\IfBooleanTF{##1}{#4}{#3{#4}}}%
}

\newcommand\definePerson[4]{%
\defineVariable{name}{#1}{\emph}{#2}
\defineVariable{phone}{#1}{\emph}{#3}
\defineVariable{email}{#1}{\emph}{#4}
}

\begin{document}

\definePerson{MrTestKey}{Mr Test}{0400 000 000}{mr@test.com}

Name is \nameMrTestKey\ or \nameMrTestKey*

Phone is \phoneMrTestKey\ or \phoneMrTestKey*

Email address is \emailMrTestKey\ or \emailMrTestKey*
\end{document}

-
Almost perfect. Thanks. In order to use my \defineVariable command... I did the following. \newcommand\definePerson[4]{% \expandafter\defineVariable\csname name#1\endcsname{\person}{#2} \expandafter\defineVariable\csname phone#1\endcsname{\phone}{#3} \expandafter\defineVariable\csname email#1\endcsname{\email}{#4} } – Joshua Spence Jul 20 '12 at 5:58
@JoshuaSpence: See updated solution which incorporates adapts your xparse version. – Peter Grill Jul 20 '12 at 6:03

I would take a slightly different tack and have a much tighter user interface. As Bruno answered in \NewDocumentCommand with constructed csname, the general feeling of the team is to try to have well defined interface commands which are not 'dynamically' generated.

At the same time, I would store the data in a 'proper' structure rather than using a \csname-based array (there are performance implications to the latter approach due to hash table collisions). The information required can be stored in a series of property lists:

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\prop_new:N \g__JS_name_prop
\prop_new:N \g__JS_telephone_prop
\prop_new:N \g__JS_email_prop
\NewDocumentCommand { \defineperson } { m m m m }
{
\prop_gput:Nnn \g__JS_name_prop {#1} {#2}
\prop_gput:Nnn \g__JS_telephone_prop {#1} {#3}
\prop_gput:Nnn \g__JS_email_prop {#1} {#4}
}
\NewDocumentCommand { \getperson } { s m }
{
\IfBooleanTF #1
{ \emph }
{ \use:n }
{ \prop_get:Nn \g__JS_name_prop {#2} }
}
\NewDocumentCommand { \gettelephone } { s m }
{
\IfBooleanTF #1
{ \emph }
{ \use:n }
{ \prop_get:Nn \g__JS_telephone_prop {#2} }
}
\NewDocumentCommand { \getemail } { s m }
{
\IfBooleanTF #1
{ \emph }
{ \use:n }
{ \prop_get:Nn \g__JS_email_prop {#2} }
}
\ExplSyntaxOff
\defineperson{MrTestKey}{Mr Test}{0400 000 000}{mr@test.com}
\begin{document}
\getperson*{MrTestKey} \getemail{MrTestKey}
\end{document}


(I have written code for a spreadsheet-like 'data tabe' variable type, but this is still experimental and probably not needed here.)

-

Here is a single macro that defines the necessary commands to use a starred/unstarred version of name, phone and email:

\documentclass{article}
\usepackage{xparse}% http://ctan.org/pkg/xparse
\makeatletter
\let\var@format\relax% Default formatting
\NewDocumentCommand\definePerson{mmmm}{%
\expandafter\gdef\csname name@#1\endcsname{\var@format{#2}}%
\expandafter\gdef\csname phone@#1\endcsname{\var@format{#3}}%
\expandafter\gdef\csname email@#1\endcsname{\var@format{#4}}%
\expandafter\NewDocumentCommand\expandafter{\csname name#1\endcsname}{s}{%
{\IfBooleanTF{##1}{\let\var@format\emph}{}\csname name@#1\endcsname}}%
\expandafter\NewDocumentCommand\expandafter{\csname phone#1\endcsname}{s}{%
{\IfBooleanTF{##1}{\let\var@format\emph}{}\csname phone@#1\endcsname}}%
\expandafter\NewDocumentCommand\expandafter{\csname email#1\endcsname}{s}{%
{\IfBooleanTF{##1}{\let\var@format\emph}{}\csname email@#1\endcsname}}%
}
\makeatother
\begin{document}

\definePerson{MrTestKey}{Mr Test}{1-234-567-8901}{mr@test.com}
\definePerson{MrsTestKey}{Mrs Test}{1-234-567-8901}{mrs@test.com}
\nameMrTestKey\ \phoneMrTestKey*\ \emailMrTestKey \par
\nameMrsTestKey*\ \phoneMrsTestKey\ \emailMrsTestKey*

\end{document}


xparse is not really needed for this since the LaTeX \@ifstar can also be used to discern between starred variants.

-