1

I'm creating a document class for bachelors' and masters' theses at my faculty. It's almost ready and tuned to this year's official requirements. However, things may change in future: for example, the management may suddenly change the title page layout or do anything like this. So, I want to add version options to my class to be specified like in the following:

\documentclass[v2018]{physvsuThesis}

With the help of these options, I plan to retain backward compatibility while being able to incorporate new requirements on demand.

However, I don't know how to manage such conditionals in a convenient way. Using plain TeX's \newif along does not seem like a viable option. The only solution I can think of is to roll out my custom commands to implement conditional logic, like this:

\DeclareOption{v2018}{\setVersion{2018}}
\DeclareOption{v2019}{\setVersion{2019}}
...

\ifVersion{2018, 2019} % logical OR
  ...
\fi

How can I implement the \ifVersion command so it can check for multiple conditions and work even if nested?

  • see if some of the stuff in etoolbox can help. It reduced the code for my faculty letter class quite a lot. – daleif Jun 8 '18 at 13:48
1

A simple implementation using expl3 with \if ... \fi:

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\str_new:N\g_my_version_str
\NewDocumentCommand\setVersion{ m }{
  \str_gset:Nn \g_my_version_str { #1 }
}
\NewDocumentCommand\ifVersion{ m }{
  \clist_if_in:nVTF { #1 } {\g_my_version_str} {\iftrue} {\iffalse}
}
\ExplSyntaxOff
\begin{document}
\setVersion{2018}
\ifVersion{2017, 2018}
+1\\
\fi
\ifVersion{2017, 2015}
+2\\
\fi
\end{document}

This leads to problems in nested conditionals because TeX does not see \ifVersion as a \if command, so the \else/\fi parsing gets out of sync in an unevaluated context.

Instead it is better to pass the conditional commands as arguments:

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\str_new:N\g_my_version_str
\NewDocumentCommand\setVersion{ m }{
  \str_gset:Nn \g_my_version_str { #1 }
}
\NewDocumentCommand\ifVersion{ m }{
  \clist_if_in:nVTF { #1 } {\g_my_version_str}
}
\ExplSyntaxOff
\begin{document}
\setVersion{2018}
\ifVersion{2017, 2018}{+1}{Not +1}
\ifVersion{2017, 2015}{+2}{Not +2}
\end{document}
1

You can do that with no package:

\documentclass{article}

\makeatletter
\newcommand{\setVersion}[1]{\def\fire@version{#1}}

\setVersion{2018-06-08}

\newcommand{\ifVersion}[1]{\ifnum\numexpr#1>0
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}

\newcommand\IS[1]{%
  \if0\expandafter\pdfstrcmp\expandafter{\fire@version}{#1}%
    \expandafter1%
  \else
    \expandafter0%
  \fi}

\newcommand\ISNOT[1]{%
  \if0\expandafter\pdfstrcmp\expandafter{\fire@version}{#1}%
    \expandafter0%
  \else
    \expandafter1%
  \fi}

\newcommand\AND[2]{(#1*#2)}

\newcommand\OR[2]{(#1+#2-#1*#2)}

\newcommand\NOT[1]{(1-#1)}

\makeatother

\begin{document}

\ifVersion
{\AND{\OR{\OR{\IS{v1}}{\IS{v2}}}{\IS{2018-06-08}}}{\ISNOT{2017-05-11}}}
{YES}
{NO}
% YES

\ifVersion
{\OR{\OR{\OR{\IS{v1}}{\IS{v2}}}{\IS{2018-06-08}}}{\IS{2017-05-11}}}
{YES}
{NO}
% YES

\ifVersion
{\AND{\OR{\OR{\IS{v1}}{\IS{v2}}}{\IS{2018-06-08}}}{\IS{2017-05-11}}}
{YES}
{NO}
% NO

\end{document}

The above solution uses \pdfstrcmp because I didn't want to assume version numbers would be only numeric.

enter image description here

The above is nestable with no problem.

Now, for more convenient infix notations, you can use xintexpr which provides \xintifboolexpr as well as the functions bool() and togl(). Check the docs. This will allow you to combine (with bool()) TeX conditionals in arbitrarily complicated logic expressions.

  • which of course fails in lualatex since it does not support \pdfstrcmp ... ;-) – daleif Jun 8 '18 at 15:59
  • @daleif it does under another name (functionality equivalent to \pdfstrcmp is requirement of LaTeX3, and as far as I know LaTeX3 is compatible with lualatex...) – user4686 Jun 8 '18 at 16:25
  • Exactly, just mentioning it here for others to come, that they cannot expect the the solution works in all LaTeX engines. – daleif Jun 8 '18 at 16:52
  • it is only a matter of adding the suitable per engine definition either as a primitive or some \directlua or whatever from copying-pasting how LaTeX3 sets it up. – user4686 Jun 8 '18 at 16:53
  • @daleif well after advanced research I could determine that xetex has \strcmp and that for luatex, one can try to un-LaTeX3 lines 1055 etc in l3str.dtx and also use l3kernel.strcmp from l3luatex.dtx... (lines 447 et al) – user4686 Jun 8 '18 at 17:27
1

A one liner in expl3:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
% this assumes that \classversion contains the version

\NewDocumentCommand{\ifVersion}{mmO{}}
 {% #1 is a list of items of the form {year,...}
  % #2 is the code to execute in case of a match
  % #3 (optional) is the code to use in case of no match
  \str_if_in:nVTF { #1 } \classversion { #2 } { #3 }
 }
\prg_generate_conditional_variant:Nnn \str_if_in:nn { nV } { T, F, TF }
\ExplSyntaxOff

\def\classversion{2018} % emulate what the class does

\begin{document}

\ifVersion{2018}{Version 2018}[Not version 2018]

\ifVersion{2017,2018}{This is 2017 or 2018}

\ifVersion{2016}{Nothing} $\leftarrow$ nothing

\ifVersion{2016}{Nothing}[Not 2016]

\ifVersion{2016,2017}{Nothing} $\leftarrow$ nothing

\end{document}

enter image description here

0

Perhaps a bit overkill, but can be done with iterating. Using e.g. pgffor and xstring:

\documentclass{article}
\usepackage{xstring}
\usepackage{pgffor}
\newif\ifIsInList

% #1: haystack
% #2: needle
% #3: action if found in list
% #4: action if not found in list
\gdef\isin#1#2#3#4{
    \global\IsInListfalse%
    \def\needle{#2}%
    \def\haystack{#1}%
    \makeatletter\IfInteger{\needle}{}{\@latex@error{ISIN: Can't look for list item that is not numeric!}{}\bye\stop}\makeatother%
    \IfInteger{\haystack}{%
        \ifnum\haystack=\needle\relax%
            #3%
        \else%
            #4%
        \fi%
    }{%
        \foreach \pp in {#1}{%
                \ifnum\pp=\needle\relax%
                    \global\IsInListtrue%
                    #3%
                \fi%
            }%
        \ifIsInList\else%
            #4%
        \fi%
    }%
}
\begin{document}
%\isin{Comma Separated List}{Look for}{If found}{If not found}
\isin{2011,2012}{2011}{2011 is in the list!}{2011 is not in the list}%
\isin{2011,2012}{2013}{2013 is in the list!}{2013 is not in the list}
\end{document}

xstring is not strictly needed - just to catch the error if the first argument is an integer, and make sure that the second argument is an integer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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