3

In a book I'm writing, I use the \IfStrEqCase from the xstring package in a command to organize access to several pieces of information I need throughout the document, without having to define a separate command for each. One of the keys is the edition/version of the book. Obviously, as this is liable to change, it's convenient to have this data localized to a single place.

In the colophon of the book, I have a copyright notice which includes the name of the book and the aforementioned edition number. I'm a big fan of the nth package, and use it elsewhere in my document. However, when I try to combine it with my command, I get compilation errors. Here's an MWE which demonstrates the error:

\documentclass{article}

\usepackage{xstring}
\usepackage{nth}

\DeclareRobustCommand{\Gkeys}[1]{%
    \IfStrEqCase{#1} {%
        {edition}{10}%
        {author}{John Doe}%
        {title}{Title of My Book}%
    }[\textbf{??key not found??}]%
}

\begin{document}

\textbf{\Gkeys{title}}, \textsc{\nth{\Gkeys{edition}} Edition}\\
\Gkeys{author} 2017

\end{document}

When I try to compile this document with pdflatex I get the following error:

! Missing number, treated as zero.
<to be read again> 
                   \protect 
l.16 ...}}, \textsc{\nth{\Gkeys{edition}} Edition}
                                                  \\
?

I'm not sure what's going here to make this not work. If I define a simple command, like say \def\BookEditionNumber{10}, this works fine, but obviously that loses the convenience of the \Gkeys command I had declared.

EDIT:

A comment pointed out that since I declared \GKeyswith \DeclareRobusCommand, I rendered it unexpandable, and thus \nth can't do anything with it. My impetus for doing so was to allow it to work with commands like \section. However, out of curiosity, I changed the command to be declared with \newcommand instead. Interestingly, this also failed to work. When I tried to compile that document, I got the following error:

! Missing number, treated as zero.
<to be read again> 
                   \let 
l.16 ...}}, \textsc{\nth{\Gkeys{edition}} Edition}
                                                  \\
? 
3
  • You declared \GKeys as robust command, this isn't expandable and \nth can do nothing here
    – user31729
    Mar 14, 2017 at 6:24
  • I see. The reason I did that was to make it work with commands like \section. Is there any way to get it both ways?
    – junius
    Mar 14, 2017 at 6:26
  • Well, \IfStrEqCase seems to be unexpandable as well, so even if \Gkeys is not robust the next cause of mischief is \IfStrEqCase
    – user31729
    Mar 14, 2017 at 6:28

2 Answers 2

3

\IfStrEqCase isn't expandable, so even if \Gkeys would be expandable itself, the inner command isn't.

I suggest to use the expandable \str_case:nnF command from the package expl3 for the checking, the syntax is almost the same compared to \IfStrEqCase.

The only thing to consider is that spaces are gobbled in the \ExplSyntaxOn...\ExplSyntaxOff domain. It is possible to use ~ here which acts as normal space token then (and not as non-breakable space)

\documentclass{article}

\usepackage{xstring}
\usepackage{nth}

\usepackage{expl3}

\ExplSyntaxOn
\newcommand{\Gkeys}[1]{%
  \str_case:nnF {#1} {
    {edition}{10}%
    {author}{John~Doe}%
    {title}{Title~of~My~Book}%
  }{\textbf{??key~not~found??}}%
}
\ExplSyntaxOff

\begin{document}
\textbf{\Gkeys{title}}

\nth{\Gkeys{edition}}

\textsc{\nth{\Gkeys{edition}} Edition}

\Gkeys{author} 2017

\section{\Gkeys{author} 2017}

\end{document}

enter image description here

5
  • Does the tilde, in this instance, cause a regular space, or a non-breaking space to be inserted?
    – junius
    Mar 14, 2017 at 6:39
  • Hmm, is there a way to insert a space without it being non-breaking?
    – junius
    Mar 14, 2017 at 6:51
  • Backslash + space os is a normal space, as in \ . Mar 14, 2017 at 7:16
  • 1
    @ChristianHupfer What do you mean? In an \ExplSyntaxOn context, ~ denotes a normal space token, not the usual tie.
    – egreg
    Mar 14, 2017 at 8:09
  • @egreg: Yes, sure. I typed on my smart phone and was on the way to leave the appartment. Of course ~ is the non-breakable space in non-expl3 - context
    – user31729
    Mar 14, 2017 at 8:47
3

You can use a handier interface such as

\defineset{my}{
  author=John Doe,
  title=Title of my book,
  edition=10,
}

In the macros below, you can define as many sets as you want; I also show how to define an abbreviated form like \Gkeys as an alias for \getkey{my}.

\documentclass{article}
\usepackage{xparse}
\usepackage{nth}

\ExplSyntaxOn
\NewDocumentCommand{\defineset}{mm}
 {
  \prop_set_eq:NN \l__keith_set_temp_prop \g_keith_set_initial_prop
  \keys_set:nn { keith/set } { #2 }
  \prop_new:c {g_keith_set_#1_prop}
  \prop_gset_eq:cN {g_keith_set_#1_prop} \l__keith_set_temp_prop
 }
\NewExpandableDocumentCommand{\getkey}{mm}
 {
  \prop_item:cn {g_keith_set_#1_prop} { #2 }
 }
\keys_define:nn { keith/set }
 {
  author  .code:n = \prop_put:Nnn \l__keith_set_temp_prop { author } { #1 },
  title   .code:n = \prop_put:Nnn \l__keith_set_temp_prop { title } { #1 },
  edition .code:n = \prop_put:Nnn \l__keith_set_temp_prop { edition } { #1 },
 }
\prop_new:N \l__keith_set_temp_prop
\prop_new:N \g_keith_set_initial_prop
\prop_gput:Nnn \g_keith_set_initial_prop { author } { ??MISSING?? }
\prop_gput:Nnn \g_keith_set_initial_prop { title } { ??MISSING?? }
\prop_gput:Nnn \g_keith_set_initial_prop { edition } { ??MISSING?? }
\ExplSyntaxOff

\defineset{my}{
  author=John Doe,
  title=Title of my book,
  edition=10,
}
\defineset{another}{
  author=Jane Doe,
  title=Title of her book,
  edition=2,
}


\newcommand{\Gkeys}[1]{\getkey{my}{#1}}

\begin{document}

\textbf{\Gkeys{title}}

\nth{\Gkeys{edition}}

\textsc{\nth{\Gkeys{edition}} Edition}

\Gkeys{author} 2017

\section{\Gkeys{author} 2017}

\nth{\getkey{another}{edition}}

\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .