[Tex/LaTex] How to define a key=value that has an equivalent boolean value key

automationkey-valuemacrosxkeyval

Assume you're defining a key=value align for some environment realign that you'll use in the following way:

\usepackage{xkeyval}% http://ctan.org/pkg/xkeyval
\newenvironment{realign}[1][]
  {\setkeys{fam}{#1}\myalignment}% \begin{realign}
  {}% \end{realign}

You define the align choice key to set \myalignment by using (taken from the xkeyval documentation):

\define@choicekey*{fam}{align}[\val\nr]{left,center,right}{%
  \ifcase\nr\relax
    \def\myalignment{\raggedright}% align=left
  \or
    \def\myalignment{\centering}% align=center
  \or
    \def\myalignment{\raggedleft}% align=right
  \fi
}

However, now you have the awesome idea of creating corresponding boolean keys left, center and right such that left|center|right=true is equivalent to align=left|center|right. Is it possible to define the boolean keys inside a macro definition, for example, via something like \newboolkey{left}:

\newcommand{\newboolkey}[1]{
  \define@boolkey{fam}[@bool@]{#1}[true]{%
    \csname if@bool@#1\endcsname%
      \setkeys{fam}{align=#1}%
    \fi%
  }%
}

This doesn't work, since the argument #1 of \newboolkey doesn't translate properly to the definition of the left key.

Of course, removing \define@boolkey from \newboolkey and explicitly stating the key (instead of #1) works. However, I'm not interested in creating a boolean key in this way (by hand). I'd like to use a macro definition to do this since it should be automated and flexible.

Here's a non-working minimal example:

\documentclass{article}
\usepackage{lipsum}% http://ctan.org/pkg/lipsum
\usepackage{xkeyval}% http://ctan.org/pkg/xkeyval
\newenvironment{realign}[1][]
  {\setkeys{fam}{#1}\myalignment}% \begin{realign}
  {}% \end{realign}
\makeatletter
\define@choicekey*{fam}{align}[\val\nr]{left,center,right}{%
  \ifcase\nr\relax
    \def\myalignment{\raggedright}% align=left
  \or
    \def\myalignment{\centering}% align=center
  \or
    \def\myalignment{\raggedleft}% align=right
  \fi
}
\newcommand{\newboolkey}[1]{
  \define@boolkey{fam}[@bool@]{#1}[true]{%
    \csname if@bool@#1\endcsname%
      \setkeys{fam}{align=#1}%
    \fi%
  }%
}

\makeatother
\begin{document}
\begin{realign}[align=left]
\lipsum[1]
\end{realign}

\newboolkey{left}% Create a boolean equivalent for align=left
\makeatletter
\if@bool@left\else% Check if key is defined.
  \texttt{left} key defined
\fi

\begin{realign}[left]% Doesn't work
\lipsum[1]
\end{realign}
\end{document}

Best Answer

Marco's already posted a version, but this is I think a bit closer to what you were trying, just fixed the #1/##1 confusion.

\documentclass{article}
\usepackage{lipsum}% http://ctan.org/pkg/lipsum
\usepackage{xkeyval}% http://ctan.org/pkg/xkeyval
\newenvironment{realign}[1][]
  {\let\myalignment\relax\setkeys{fam}{#1}\myalignment}% \begin{realign}
  {}% \end{realign}
\makeatletter
\define@choicekey*{fam}{align}[\val\nr]{left,center,right}{%
  \ifcase\nr\relax
    \def\myalignment{\raggedright}% align=left
  \or
    \def\myalignment{\centering}% align=center
  \or
    \def\myalignment{\raggedleft}% align=right
  \fi
}
\newcommand{\newboolkey}[1]{
  \define@boolkey{fam}[@bool@]{#1}[true]{%
    \csname if##1\endcsname
      \setkeys{fam}{align=#1}%
    \csname fi\endcsname
  }%
}

\makeatother
\begin{document}
\begin{realign}[align=left]
\lipsum[1]
\end{realign}

\newboolkey{left}% Create a boolean equivalent for align=left
\makeatletter
\if@bool@left\else% Check if key is defined.
  \texttt{left} key defined
\fi

\begin{realign}[left]% Doesn't work
\lipsum[1]
\end{realign}
\end{document}
Related Question