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 would like to prepare a macro with an optional argument like [wide], using xkeyval. (something whether to use \figure or \figure* inside) My test program below presents the output

test0=false test1=false test2=false test3=false test4=false

What do I wrong? It seems to me that the default case stays valid in all use cases.

Also, I an not sure it is the right tool to do what I want. The xkeyval documentation states that if no equals sign is present, an error will normally be raised. My test program does not make so. Also, I do not want to use something like [wide=].

\documentclass{report}
\usepackage{xkeyval}
\makeatletter
\define@key{METest}{wide}{\def\pb@wide{#1}}
\setkeys{METest}{wide=false}%
\newcommand\METest[2][]{
   \begingroup%
        #2=\pb@wide \ 
  \endgroup%
}
\makeatother

\begin{document}
\METest[]{test0}
\METest[wide]{test1}
\METest[wide=]{test2}
\METest[wide=true]{test3}
\METest[wide=false]{test4}
\end{document}
share|improve this question

1 Answer 1

up vote 5 down vote accepted

The command \setkeys{METest}{wide=false} sets this key to false, so you have no chance to provide another value. \setkey should be inside the macro using the syntax \setkeys{METest}{wide=false,#1}, such that a possible override within #1 of the key value is handled.

You can specify a default value to an option, using the [] syntax as I have done with the wide option key, but not for the otherwide key.

If you want to guarantee, that a key has a definite value, \presetkeys is the correct command.

'Wrong' code, with false usage

This code will fail on purpose to show the missing =value for otherkey option.

\documentclass{report}
\usepackage{xkeyval}
\makeatletter
\define@key{METest}{wide}[false]{\def\pb@wide{#1}}

\define@key{METest}{otherwide}{\def\pb@otherwide{#1}}


\presetkeys{METest}{wide=false}{}%
\newcommand\METest[2][]{
\setkeys{METest}{wide=false,#1}% 
   \begingroup%
        #2=\pb@wide \ 
  \endgroup%
}
\makeatother

\begin{document}

\METest[]{test0}
\METest[wide]{test1}
\METest[wide=]{test2}
\METest[wide=true]{test3}
\METest[wide=false]{test4}
\METest[otherwide]{test5} % will fail here
\end{document}

Correct behaviour

\documentclass{report}
\usepackage{xkeyval}
\makeatletter
\define@key{METest}{wide}[false]{\def\pb@wide{#1}}

\define@key{METest}{otherwide}{\def\pb@otherwide{#1}}


\presetkeys{METest}{wide=false}{}%
\newcommand\METest[2][]{
\setkeys{METest}{wide=false,#1}%
   \begingroup%
        #2=\pb@wide \ 
  \endgroup%
}
\makeatother

\begin{document}

\METest[]{test0}
\METest[wide]{test1}
\METest[wide=]{test2}
\METest[wide=true]{test3}
\METest[wide=false]{test4}
\METest[otherwide=true]{test5} %
\end{document}

enter image description here

On request of the OP, another solution

This version grabs the #1 argument of the command first and checks if it is blank. If this is the case, the state is set to false, as requested. Otherwise, the \setkeys command is evaluated. However, a wrong usage such as wide= without argument is not handled (so far)

\documentclass{report}
\usepackage{etoolbox}%
\usepackage{xkeyval}
\makeatletter
\define@key{METest}{wide}[true]{\def\pb@wide{#1}}

\define@key{METest}{otherwide}{\def\pb@otherwide{#1}}


\newcommand\METest[2][]{%
  \ifblank{#1}{%
    \setkeys{METest}{wide=false}%
  }{%     
    \setkeys{METest}{#1}%
  }%
  \begingroup%
  #2=\pb@wide%
  \endgroup%
}%
\makeatother

\begin{document}

\METest[]{test0}
\METest[wide]{test1}
\METest[wide=]{test2}
\METest[wide=true]{test3}
\METest[wide=false]{test4}
\METest[otherwide=true]{test5} %
\end{document}

enter image description here

share|improve this answer
    
Thank you for your answer and pointing all this this out. However, what I really wanted, is to provide a 'false' default behavior, and 'true' with [wide] and [wide=true]. The xkeyval doc states that test1 and test3 should provide the same result, 'true'. However, test0 false, test1 true, test3 true. In other words: if wide is absent, false; if wide is present, then with or without '=true" it should result 'true'. I.e., I want a default behaviour for the macro, and, maybe, a default value for the key. From the docs, I am not sure if it is possible. –  user11708 Sep 1 at 13:01
    
I am not sure whether this possible with usage of xkeyval alone, but I added another solution –  Christian Hupfer Sep 1 at 13:24
    
Finally, after changing to \define@key{METest}{wide}[true]{\def\pb@wide{#1}}, I can get what I wanted. However, when I copy&paste it to my working file, I receive the message "Undefined control sequence \presetkeys". No other errors, the rest is OK. Any idea? –  user11708 Sep 1 at 16:30
    
@user11708: Sorry, but I do not use \presetkeys any longer in my updated solution. However, the command must be known of course! –  Christian Hupfer Sep 1 at 17:39
    
I am afraid that your other solution is not aware of whether I use another keys. –  user11708 Sep 1 at 19:41

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.