Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I have defined a command using xparse as

\DeclareDocumentCommand\mymacro{o o o}

and I want to call it with various numbers of arguments (up to 3)

\mymacro, \mymacro[test][two], \mymacro[][][test]

etc...

The issue is that [] doesn't seem to return a \NoValue but an empty token as the tests I use \IfNoValueTF never return false on it.

Is there a way to make an "empty" argument like \mymacro[] set #1 to \NoValue when it is an empty string?

Essentially I need "empty" arguments to be set to \NoValue for my code to work.

I could always do

\mymacro[\NoValue][test][\NoValue]

but of course that defeats the purpose of making it simple.

In my code I use \IfNoValueTF{#n} a lot but for it to work on empty arguments I would need something like \IfNoValueOrEmptyTF.

share|improve this question
2  
Instead of three optional arguments you might want to consider using key-value pairs. –  egreg Jul 13 '12 at 19:15
add comment

3 Answers

up vote 2 down vote accepted

Using a mixture of xparse and \ifx conditionals you can test for empty arguments:

enter image description here

\documentclass{article}
\usepackage{xparse}% http://ctan.org/pkg/xparse
\makeatletter
\DeclareDocumentCommand\mymacro{o o o}{
  \def\@tempa{#1}Arg 1 is \ifx\@tempa\@empty\relax empty\else #1\fi. \par
  \def\@tempa{#2}Arg 2 is \ifx\@tempa\@empty\relax empty\else #2\fi. \par
  \def\@tempa{#3}Arg 3 is \ifx\@tempa\@empty\relax empty\else #3\fi.
}
\makeatother
\begin{document}
\verb|\mymacro|:\par\mymacro

\verb|\mymacro[test][two]|: \par\mymacro[test][two]

\verb|\mymacro[][][test]|: \par\mymacro[][][test]

\verb|\mymacro[][][]|: \par\mymacro[][][]

\verb|\mymacro[one][][three]|: \par\mymacro[one][][three]
\end{document}​
share|improve this answer
    
This worked. Wasn't fun changing the different syntaxes({} to \else\fi) it at least it works. I imagine one could wrap IfNoValue to include empty values easy enough though. –  AbstractDissonance Jul 13 '12 at 19:14
    
\makeatletter \newcommand{\IfNoValueOrEmptyTF}[3] {\IfNoValueTF{#1}{#2}{\def\@tempa{#1}\ifx\@tempa\@empty#2\else#3\fi}} \makeatother –  AbstractDissonance Jul 13 '12 at 19:18
    
\if\relax\detokenize{#1}\relax is more economic. –  egreg Jul 13 '12 at 19:19
add comment

Here is a \IfNoValueOrEmpty macro:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\IfNoValueOrEmptyTF}{mmm}
 {
  \IfNoValueTF{#1}{#2}
   {
    \tl_if_empty:nTF {#1} {#2} {#3}
   }
 }
\ExplSyntaxOff

\NewDocumentCommand{\mymacro}{ooo}{%
  \IfNoValueOrEmptyTF{#1}{\typeout{\#1 is empty}}{\typeout{\string#1 is `#1'}}%
  \IfNoValueOrEmptyTF{#2}{\typeout{\#2 is empty}}{\typeout{\string#2 is `#2'}}%
  \IfNoValueOrEmptyTF{#3}{\typeout{\#3 is empty}}{\typeout{\string#3 is `#3'}}%
}

\mymacro
\mymacro[a]
\mymacro[a][b]
\mymacro[a][b][c]
\mymacro[][b]
\mymacro[][][c]
\mymacro[][][]

However, a command with three optional arguments is difficult to manage, because one needs to remember which is which. A key-value syntax might be easier to employ.

share|improve this answer
    
Should this solution work with the current xparse version (2013/11/19)? I do get an empty document when trying to use this. –  Jörg Dec 9 '13 at 22:42
    
@Jörg This document is not supposed to produce output, but only messages on the terminal. –  egreg Dec 9 '13 at 22:49
    
Silly me, I missed the typeout... –  Jörg Dec 9 '13 at 22:56
add comment

Empty arguments and NoValue ones are not the same (and indeed using \NoValue directly is not supported as we will soon change the definition). Unlike LaTeX2e's \newcommand, xparse differentiates between an argument which is given but is empty and one which is not given. Thus if you want to be able to have input of the form

\foo[][][baz]

you don't want a NoValue test at all, but rather

\ExplSyntaxOn
\DeclareDocumentCommand{\foo}{ O{} O{} O{} }
  {
    \tl_if_empty:nTF {#1}
    ...
  }

testing for an empty value using the code-level test. (We do not have a design-level empty test at the present time.)

share|improve this answer
    
Ok, that makes sense but I can't seem to get it to work using lualatex. I've tried including expl3 and things but it causes problems later on in some of my macros –  AbstractDissonance Jul 13 '12 at 18:56
    
@AbstractDissonance expl3 should not interfere with any code which does not use it. Could you give more detail? –  Joseph Wright Jul 13 '12 at 19:00
    
All I know is when I replaced If IfNoValueTF with tl_if_empty:NTF, added \ExplSyntaxOn and \usepackage{expl3} some of my lua code failed(saying some functions did not exist). Going to try werners method –  AbstractDissonance Jul 13 '12 at 19:06
    
@AbstractDissonance Did you use \tl_if_empty:NTF or \tl_if_empty:nTF - the two are distinct. I really would appreciate an example so I can check there is not an issue in epxl3: could you e-mail me what you saw (joseph.wright@morningstar2.co.uk)? –  Joseph Wright Jul 13 '12 at 19:12
2  
@AbstractDissonance You said you added \ExplSyntaxOn, did you also include the corresponding \ExplSyntaxOff after defining the command? –  Scott H. Jul 13 '12 at 19:48
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.