# Three-way optional argument in xparse

I am trying to programme a command in x parse that has one optional argument, but which can behave in three ways in the following situations: a) no argument specified, b) optional argument specifies a specific value (p), c) optional argument specifies a different value (q).

The commands would look as follows:

\command

\command[p]

\command[q]

and would give the result

command

command preface

command q

I have tried to use the star and token arguments instead of the standard optional argument but the documentation is very sparse for the package and I cannot work out, even from looking at examples on this site, how I might achieve the above.

My attempt was as follows:

\documentclass{article}
\usepackage{xparse}

\NewDocumentCommand \command { tp } {%
\IfNoValueTF{#1}{%
command}%
{{\IfBooleanTF{#1}%
{command preface}%
{command #1}%
}}}

\begin{document}

\command
\command[p]
\command[10]

\end{document}

• –1: Questions only asking “do it for me” or the like are not really welcome here. Please add a MWE showing your own efforts and I’ll be happy to take my downvote back ;-) – Tobi Nov 26 '13 at 11:14
• xparse is meant to grab arguments: further processing of the content is left to 'other code'. What have you tried so far? – Joseph Wright Nov 26 '13 at 11:16
• Tobi: I thought I might get that response, but I genuinely tried and my efforts were so far from working that I didn't see much point in posting them. Truth is, I didn't really know where to start with the problem. I would have been happy with a response like "here is a site that explains xparse in more detail than the documentation" rather than an actual solution, as I could not find such a resource. – DavidR Nov 26 '13 at 11:34
• @DavidRowthorn: Hm … showing some code even if it don’t work will help. I don’t like questions that have the “just do it for me” attitude – and your’s looks that way ;-) But as you can see in the fact that I provided an answer I’m not that upset ;-) and I redeem my downvote. (ps. Note that you need an @ in front of a name to get the user notified …) – Tobi Nov 26 '13 at 12:06
• Since your interface doens’t make sense to me I can hardly tell how to improve your attempt, but see what I added to my answer. – Tobi Nov 26 '13 at 12:18

You don’t need xparse in that case. You can do a case switch with the xstring package:

\documentclass{article}

\usepackage{xstring}

% with xstring
\newcommand{\mycmd}[1][-no-value-]{%
command does
\IfStrEqCase{#1}{%
{-no-value-}{no value}%
{p}{preface}%
}[#1 value]
stuff
}

% a more clever version (see comments) with xparse
\usepackage{xparse}
\NewDocumentCommand{\myothercmd}{ o }{%
command does
\IfNoValueTF{#1}{no value}{%
\IfStrEq{#1}{p}{preface}{#1}%
}
stuff
}

\begin{document}
\mycmd

\mycmd[p]

\mycmd[q]

\mycmd[-no-value-] is a 'wrong' argument and confuses the code.
So it should be something where you are sure that it won't be the
argument of \verb+\mycmd+

\bigskip
\myothercmd

\myothercmd[p]

\myothercmd[q]

\mycmd[-NoValue-] \texttt{xparse} know how to handle this.
\end{document}


Trying to correct your attempt gives

\NewDocumentCommand \yourcmd { t{+} o } {%
\IfBooleanTF{#1}{command preface}{%
\IfNoValueTF{#2}{%
command%
}{%
command #2%
}%
}%
}


As you can see the p argument take an argument specifying the <token> that should be tested this toke cant be a letter, e.g. p, because \yourcmdp will be another command in TeX’s eyes and not \yourcmd followed by token p. The corrected version can be used as

\yourcmd
\yourcmd+
\yourcmd[q]
\yourcmd+[q]


giving

command
command preface
command q
command preface

• Note that xparse's -NoValue- is not returned if you do \mycmd[-NoValue-], i.e (without significant effort) you can't 'confuse' the code with the 'wrong' optional argument. – Joseph Wright Nov 26 '13 at 11:15
• So you mean, that I should prefer the xparse way instead my own -no-value- approach? – Tobi Nov 26 '13 at 11:16
• Depends on the use case: usually you don't need to worry about users entering 'difficult' values, but it is at least worth being aware of. – Joseph Wright Nov 26 '13 at 11:17
• I was aware of the fact that my approach is confusable in that way but I wasn’t aware of the fact that xparse is more clever. Thanks! – Tobi Nov 26 '13 at 11:24
• I was not aware of the xstring package, but it is exactly what I needed. thanks – DavidR Nov 26 '13 at 13:43

xparse doesn't provide helpers for this situation, so going deeper with comparing strings is necessary.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\command}{o}
{
\IfNoValueTF{#1}
{
<No optional value code>
}
{
\rowthorn_check_argument:n { #1 }
}
}

\cs_new:Npn \rowthorn_check_argument:n #1
{
\str_case:nnF { #1 }
{
{p}{ \rowthorn_command:n { Preface } }
}
{ \rowthorn_command:n { #1 } }
}

\cs_new_protected:Npn \rowthorn_command:n #1
{
<do something with #1>
}
\ExplSyntaxOff

\begin{document}

\command

\command[p]

\command[Introduction]

\end{document}


I don't think this is a good interface, though.