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'm trying to create a keycommand with optional arguments, but I can't get it to work. I looked at Comparing an argument to a string when argument is a result of a command with etoolbox and although the example there works, I can't get it to work for use with keycommand, nor can I get ifcommandkey to work as expected. I recently upgraded from Tex Live 2009 to Tex Live 2011 and in 2009, ifcommandkey was working.

In Tex Live 2011, how do I check whether a key was given or not?

Below is an example where I try different things. None have the desired effect; in the third call, I want the result to be something like "No spam. No eggs. No paper. No Salt", but I get "Has spam" in every run. Why?

\documentclass{minimal}
\usepackage{keycommand}
\usepackage{etoolbox}
\begin{document}
\newcommand\myifstrempty{\expandafter\ifstrempty\expandafter}
\newkeycommand{\testkc}[spam,eggs,paper,salt][][0]{
\ifcommandkey{spam}{Spam: ``\commandkey{spam}''}{No spam}.
\ifcommandkey{eggs}{Eggs: ``\commandkey{eggs}''}{No eggs}.
\ifcommandkey{paper}{Paper: ``\commandkey{paper}''}{No paper}.
\ifcommandkey{salt}{Salt: ``\commandkey{salt}''}{No Salt}.
\ifcommandkey\expandafter{salt}{Salt: ``\commandkey{salt}''}{No Salt}.
\myifstrempty{\commandkey{spam}}{Not has spam}{Has spam}
\expandafter\ifstrempty{\expandafter{\commandkey{spam}}}{Not has spam}{Has spam}
}

\testkc[spam=bad, eggs=good, salt=horrid]

\testkc[paper=gold]

\testkc

\newcommand{\aORb}[1]{%
        \expandafter\ifstrequal\expandafter{#1}{a}{"a" was given}{not a}, %
        \expandafter\ifstrequal\expandafter{#1}{b}{"b" was given}{not b}%
}


\aORb{a}

\aORb{b}

\end{document}

The result looks like this:

result

share|improve this question
    
If you find the time, try the key commands and key environments of 'ltxkeys' package. If you encounter difficulties there, first email the package author. –  Ahmed Musa Nov 22 '11 at 16:57

1 Answer 1

up vote 8 down vote accepted

The \ifcommandkey approach

There is a bug in the definition of \ifcommandkey (2010/04/27 v3.1415). It is missing out one stage of expansion of the \commandkey (see the analysis in the section below), and as a result does not test the value of the key. (You will get TRUE even with an undefined key.) Try the following definition in the preamble after loading keycommand:

\begingroup
  \makeatletter
  \catcode`\/=8 %
  \@firstofone
    {
      \endgroup
      \renewcommand{\ifcommandkey}[1]{%
        \csname @\expandafter \expandafter \expandafter 
        \expandafter \expandafter \expandafter  \expandafter
        \kcmd@nbk \commandkey {#1}//{first}{second}//oftwo\endcsname
      }
   } 

The \ifstrempty approach

The issue here is that you are not doing enough expansion for the \ifstrempty test. What you need to ensure it that the argument this receives is the value passed to the key, and not some intermediate form. Thus you need to expand \commandkey to the content it represents. Now, there are a three approaches for this type of thing. First, we could use \edef:

\newcommand\myifstrempty[1]{%
  \begingroup
    \edef\x{%
      \endgroup
       \noexpand\ifstrempty{#1}%
    }%
    \x
}

The problem with this is that you don't know what might be given for the key value, so the \edef may go wrong.

A more controlled approach is to use the correct number of \expandafters. If you do

\show\commandkey

you'll find it expands to

\csname keycmd->testkc@#1\endcsname

inside your key-using macro. So to expand to the value of the key requires three expansions: the first to expand \commandkey, the second to expand the \csname primitive and the third to expand the resulting control sequence. Due to the way TeX expansion works, this leads to

\newcommand\myifstrempty{%
    \expandafter\expandafter\expandafter\expandafter
      \expandafter\expandafter\expandafter\ifstrempty
        \expandafter\expandafter\expandafter\expandafter
          \expandafter\expandafter\expandafter
 }

The third approach is to use the peculiar nature of \romannumeral to do what LaTeX3 would call a 'full' expansion. This is similar to doing an \edef but will halt cleanly on anything which cannot be expanded:

\newcommand\myifstrempty[1]%
  {\expandafter\ifstrempty\expandafter{\romannumeral -`0#1 }}

The later is useful in the current case as it cuts down on the number of \expandafter primitives required.

share|improve this answer
    
I've reported the issue to the package author –  Joseph Wright Nov 22 '11 at 19:04
1  
Thanks! This \expandafter stuff looks pretty complicated, makes me happy there are so many useful packages around that I don't feel the need to roll my own package (yet) :) –  gerrit Nov 22 '11 at 20:45
    
@gerrit Expansion is a tricky area, hence for example the LaTeX3 Project's work on a programming layer which deals with a lot of this. –  Joseph Wright Nov 22 '11 at 20:51

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.