# Generate l3keys meta key from subkey

I’ve created a simple package with options settable via l3keys2e. I was able to figure out how to make the syntax

\usepackage[format = international]{phone}


work, but I’d like to make the syntax

\usepackage[international]{phone}


be a synonym. The method I’m using in the code below works, but is very repetitive, especially when I’ve got more formatting options. Is there a simpler way?

Here’s the code:

\RequirePackage{expl3, l3keys2e, xparse}
\ProvidesExplPackage
{phone}{2013/06/19}{0.1}{Format phone numbers}

\cs_new_nopar:Npn \phone_international_fmt:NNN  #1#2#3
{ +1 - #1 - #2 - #3 }

\cs_new_nopar:Npn \phone_parendash_fmt:NNN  #1#2#3
{ (#1) \nobreakspace #2 - #3 }

\keys_define:nn { phone }
{
format .choice_code:n =
{
\cs_new_eq:Nc \phone_fmt:NNN
{ phone_ \tl_use:N \l_keys_choice_tl _fmt:NNN }
},
format .generate_choices:n =
{
international,
parendash,
},
% These next lines will become repetitive if I have many more formatting options
international .meta:n = { format = international },
parendash     .meta:n = { format = parendash     },
}

\ProcessKeysOptions { phone }

\NewDocumentCommand \phone
{ >{ \SplitArgument {2} {-} } m }
{ \phone_fmt:NNN #1 }

\endinput


A minimal example using this package looks like this:

\documentclass{article}

% \usepackage[parendash]{phone}
\usepackage[format = parendash]{phone}

\begin{document}

\phone{212-555-1212}

\end{document}


This yields the desired result

(212) 555-1212

• I’m not at all certain I’ve got the nomenclature correct; feel free to rename this question to fix this. Jun 19, 2013 at 23:23
• Aside: \cs_new_nopar:Npn \phone_international_fmt:NNN isn't really encouraged, and I'd suggest \cs_new:Npn \phone_international_fmt:NNN instead. Apart from a few specific internals, we've standardised on a position that functions with arguments should be 'long'. Jun 20, 2013 at 7:46
• Shouldn't the :NNN argument spec rather be :nnn? Jun 20, 2013 at 8:04
• @cgnieder Yes; in that code all the :NNN should be :nnn Jun 20, 2013 at 8:55
• @JosephWright, is that the case, even though xparse defaults to short arguments? Jun 20, 2013 at 14:46

You could use an unknown key handler for this whereby you pass any unknown key back into the system as format = <unknown key> (a similar system is used by TikZ to recognise colours and node shapes). Here's an example which uses that. It gives a warning if there isn't a corresponding format.

I have to use a helper command to feed the unknown key back into the key handler since if I just did format / unknown .code:n = { \keys_set:nn { phone} { format = #1 } } then the #1 would be \l_keys_key_tl and L3 would be extremely careful and not expand the \l_keys_key_tl until the last minute, by which time it would have changed its value from the unknown key to format. The helper macro allows me to use the value of \l_keys_key_tl instead of the token list variable.

I also fixed the NNN to nnn. Because I wanted to set a default, the setter inside the key handler is now \cs_set_eq:Nc instead of \cs_new_eq:Nc.

\documentclass{article}
%\url{http://tex.stackexchange.com/q/120102/86}
\usepackage{filecontents}

\begin{filecontents}{phone.sty}
\RequirePackage{expl3, l3keys2e, xparse}
\ProvidesExplPackage
{phone}{2013/06/19}{0.1}{Format phone numbers}

\cs_new_nopar:Npn \phone_international_fmt:nnn  #1#2#3
{ +1 - #1 - #2 - #3 }

\cs_new_nopar:Npn \phone_parendash_fmt:nnn  #1#2#3
{ (#1) \nobreakspace #2 - #3 }

% Set a default
\cs_set_eq:NN \phone_fmt:nnn \phone_parendash_fmt:nnn

\msg_new:nnnn {phone} {no~ format} {Format~ #1'~ is~ not~ recognised~ by~ this~ package,~ using~ the~ default~ parendash'~ instead.} {}

\keys_define:nn { phone }
{
format .choice:,
format .choice_code:n =
{
\cs_set_eq:Nc \phone_fmt:nnn
{ phone_ \tl_use:N \l_keys_choice_tl _fmt:nnn }
},
format .generate_choices:n =
{
international,
parendash,
},
format / unknown .code:n = {
\msg_warning:nnn {phone} {no~ format} {#1}
},
unknown .code:n = {
\phone_unknown_key:V \l_keys_key_tl
},
}

\cs_new:Npn \phone_unknown_key:n #1
{
\keys_set:nn { phone} { format = #1 }
}

\cs_generate_variant:Nn \phone_unknown_key:n {V}

\ProcessKeysOptions { phone }

\NewDocumentCommand \phone
{ >{ \SplitArgument {2} {-} } m }
{ \phone_fmt:nnn #1 }

\endinput
\end{filecontents}
\usepackage[british]{phone}

\begin{document}

\phone{212-555-1212}

\end{document}

• This answers the question I asked, hence the upvote and acceptance. As it happens, the actual package has multiple keys for which I want the values as shortcuts, so I’ll actually be using Joseph’s solution. Jun 20, 2013 at 14:51

The approach you've taken looks correct. Internally, the .meta:n property is creating a standard key which is more-or-less equivalent to

key-name-1 .code:n = { \keys_set:nn { module } { key-name-2 = #1 } }


If you have a large number of these meta keys to create, you might want to use a comma-list mapping

\clist_map_inline:nn { key-one , key-two , key-three ... }
{ \keys_define:nn { mymodule } { #1 .meta:n = { format = #1 } }


but for just a couple this is probably making your code more not less complex.

• Considering that I’ll also be adding .value_forbidden: for each of these shortcuts, the benefit starts to outweigh the cost very quickly. Jun 20, 2013 at 14:59