# xparse and key value arguments

I'm trying to learn how to do macros.

I want to use xparse as it seems the most powerful tool. I also want named arguments, as numbered arguments make me, as a programmer, uncomfortable.

\DeclareDocumentCommand{\myMacro} {o o}
{
\DeclareDocumentCommand{\foo} {} {#1}
\DeclareDocumentCommand{\bar} {} {#2}
The foo argument was \foo and the bar argument was \bar

}


But this wouldn't work, because of nesting and wouldn't extend to DocumentEnviroments, I guess since different scoping for beginning and end sections.

My goal is to have some sections of a document that are highly structured. For example I might have a list of movies, which have parameters like title, date, director etc. and I might manipulate them in complex ways (perhaps building them into a paragraph), and I don't want to have to remember which order the parameters were in when defining this.

Perhaps I am thinking wrong for a LaTeX user, I guess in many programming languages you need to know the order when invoking a function (though in this case, I would like to use the name of arguments when invoking - for clarity)

-
See also Latex, named parameter macros –  Martin Schröder Jun 21 '13 at 16:29
Thanks, I was meaning to link that here, after i created it, but I got distracted. –  Oxinabox Jun 22 '13 at 9:28

Here is a very elementary view on LaTeX's key-value system using keyval, similar to what was presented in How to create a command with key values?:

\documentclass{article}
\usepackage{keyval,xparse}% http://ctan.org/pkg/{keyval,xparse}

\makeatletter
% ========= KEY DEFINITIONS =========
\define@key{mymacro}{first}{\def\mm@first{#1}}
\define@key{mymacro}{second}{\def\mm@second{#1}}
\define@key{mymacro}{third}{\def\mm@third{#1}}
\define@key{mymacro}{last}{\def\mm@last{#1}}
\DeclareDocumentCommand{\myMacro}{m}{%
\begingroup%
% ========= KEY DEFAULTS + new ones =========
\setkeys{mymacro}{first={FIRST arg},second={SECOND arg},third={THIRD arg},last={LAST arg},#1}%
First arg: \mm@first \par
Second arg: \mm@second \par
Third arg: \mm@third \par
Last arg: \mm@last
\endgroup%
}
\makeatother

\begin{document}

\myMacro{last=LaSt,first=FiRsT} \par \hrulefill

\myMacro{} \par \hrulefill

\myMacro{third={$x^2$ \textbf{stuff}},second={}}
\end{document}


It should be evident that using a key-value approach removes the requirement to remember the order of the keys. That is, unless the keys have some interaction with one another.

Grouping (via \begingroup...\endgroup) localizes the changes to the keys. However, you can make things available globally. It just depends on your application. Moreover, it would be possible to adapt the key-values to actually create key-macros that you can re-use. This may be helpful if you have a area in your document where you perform a bunch of declarations, and want to re-use them later.

The above example translates just as well to document environments.

More extensions are provided by xkeyval, ltxkeys and even l3keys from expl3 (see Programming key–value in expl3).

Here's a practical example of using key-values to store data regarding movies through a movie declaration (\newMovie{<tag>}{<key-values>}) and printing it (\showMovie{<tag>}):

\documentclass{article}
\usepackage{keyval,xparse,url}% http://ctan.org/pkg/{keyval,xparse,url}

\makeatletter
% ========= KEY DEFINITIONS =========
\define@key{movie}{title}{\expandafter\def\csname \movietag @title\endcsname{#1}}
\define@key{movie}{releaseyear}{\expandafter\def\csname \movietag @releaseyear\endcsname{#1}}
\define@key{movie}{genre}{\expandafter\def\csname \movietag @genre\endcsname{#1}}
\define@key{movie}{url}{\expandafter\def\csname \movietag @url\endcsname{#1}}
\DeclareDocumentCommand{\newMovie}{m m}{%
% ========= KEY DEFAULTS + new ones =========
\def\movietag{#1}% Store movie tag (used when setting/storing keys)
\setkeys{movie}{title={},releaseyear={},genre={},url={},#2}% Create keys
}
\DeclareDocumentCommand{\showMovie}{m}{%
\textbf{\csname #1@title\endcsname} (\csname #1@releaseyear\endcsname),
\textit{\csname #1@genre\endcsname},
\expandafter\expandafter\expandafter\url\expandafter\expandafter\expandafter{\csname #1@url\endcsname}.
}
\makeatother

\begin{document}

% Movie declarations
\newMovie{anchorman2}{
url={http://www.imdb.com/title/tt1229340/},
releaseyear=2013,
title={Anchorman: The Legend Continues},
genre=Comedy}
\newMovie{lego}{
title={The Lego Movie},
releaseyear=2014,
url={http://www.imdb.com/title/tt1490017/},
genre={Animation, Action, Comedy}}
\newMovie{magic}{
title={Now You See Me},
url={http://www.imdb.com/title/tt1670345/},
releaseyear=2013,
genre={Crime, Thriller}}

% Show movie details
\showMovie{magic}

\showMovie{anchorman2}

\showMovie{lego}

\end{document}


There are other (perhaps better) ways of dealing with this, but again, this is just to showcase what you can do with key-value approaches to macros (and databases).

-

An implementation entirely in expl3, using key-value pairs and property lists.

Each \newMovie command defines a property list and stores the values. Then \showMovie displays them in the preferred order.

\documentclass{article}
\usepackage{xparse,url}

\ExplSyntaxOn
% keys
\keys_define:nn { oxinabox/movies }
{
title .tl_set:N = \l_oxinabox_title_tl,
releaseyear .tl_set:N = \l_oxinabox_releaseyear_tl,
genre .tl_set:N = \l_oxinabox_genre_tl,
url .tl_set:N = \l_oxinabox_url_tl,
}

% user level commands
\NewDocumentCommand{\newMovie}{m m}
{
\oxinabox_newmovie:nn { #1 } { #2 }
}

\NewDocumentCommand{\showMovie}{m}
{
\oxinabox_showmovie:n { #1 }
}

% internal functions
\cs_new_protected:Npn \oxinabox_newmovie:nn #1 #2
{
\group_begin: % keep the assignment to the keys local
\prop_new:c { g_oxinabox_movie_#1_prop }
\keys_set:nn { oxinabox/movies } { #2 }
\prop_gput:cnV { g_oxinabox_movie_#1_prop } { title } \l_oxinabox_title_tl
\prop_gput:cnV { g_oxinabox_movie_#1_prop } { releaseyear } \l_oxinabox_releaseyear_tl
\prop_gput:cnV { g_oxinabox_movie_#1_prop } { genre } \l_oxinabox_genre_tl
\prop_gput:cnV { g_oxinabox_movie_#1_prop } { url } \l_oxinabox_url_tl
\group_end:
}

\cs_new:Npn \oxinabox_getvalue:nn #1 #2
{
\prop_get:cn { g_oxinabox_movie_#1_prop } { #2 }
}
\cs_new_protected:Npn \oxinabox_showmovie:n #1
{
\par\noindent
\textbf{ \oxinabox_getvalue:nn { #1 } { title } }, ~ %
\textbf{ \oxinabox_getvalue:nn { #1 } { releaseyear } }, ~ %
\textbf{ \oxinabox_getvalue:nn { #1 } { genre } },
\\
\use:x { \exp_not:N \url { \oxinabox_getvalue:nn { #1 } { url } } }
}
\ExplSyntaxOff
\begin{document}

% Movie declarations
\newMovie{anchorman2}{
url={http://www.imdb.com/title/tt1229340/},
releaseyear=2013,
title={Anchorman: The Legend Continues},
genre=Comedy}
\newMovie{lego}{
title={The Lego Movie},
releaseyear=2014,
url={http://www.imdb.com/title/tt1490017/},
genre={Animation, Action, Comedy}}
\newMovie{magic}{
title={Now You See Me},
url={http://www.imdb.com/title/tt1670345/},
releaseyear=2013,
genre={Crime, Thriller}}

% Show movie details
\showMovie{magic}

\showMovie{anchorman2}

\showMovie{lego}

\end{document}


Thanks to Werner for the data. ;-)

-