7

I want to automatize some of the code that I usually include to setup my theorem environment functionality into a package. So here is what I do to control within which counter my theorems are numbered:

\RequirePackage{filecontents}

\begin{filecontents}{mytheorems.sty}
    \RequirePackage{xkeyval}
    \RequirePackage{amsthm}

    \DeclareOptionX{numberwithin}{%
        \theoremstyle{plain}%
        \newtheorem{theorem}{Theorem}[#1]%
    }
    \DeclareOptionX{nonumberwithin}{%
        \theoremstyle{plain}%
        \newtheorem{theorem}{Theorem}%
    }
    \ProcessOptionsX

    \theoremstyle{plain}
    \newtheorem{lemma}[theorem]{Lemma}
\end{filecontents}

\documentclass{article}

\usepackage[nonumberwithin]{mytheorems}%or use option [numberwithin=section] for example

\begin{document}
    \begin{lemma}
        content...
    \end{lemma}
\end{document}

Now I would like that the package is loaded with [nonumberwithin] if no option is given. However adding \ExecuteOptionsX{nonumberwithin} to the package won't allow [numberwithin=section] any longer because the two options clash. So what should I do?

2 Answers 2

7

In my opinion, the numberwithin etc. options should set a \if... variable and postpone the definition of the theorem according to the state of the, say, \if@numberwithin boolean. The argument of numberwithin must be stored, however.

As far as I know this is the way how standard LaTeX classes process mutually exclausive states for options.

\RequirePackage{filecontents}

\begin{filecontents}{mytheorems.sty}
    \RequirePackage{xkeyval}
    \RequirePackage{amsthm}

    \newif\if@numberwithin
    \def\@numberwithin{section}% Defining a default if needed        
    \DeclareOptionX{numberwithin}{%
      \@numberwithintrue
      \gdef\@numberwithin{#1}%
    }
    \DeclareOptionX{nonumberwithin}{%
      \@numberwithinfalse
    }
    \ExecuteOptionsX{nonumberwithin}
    \ProcessOptionsX

    \if@numberwithin
    \theoremstyle{plain}
    \newtheorem{theorem}{Theorem}[\@numberwithin]%
    \else
    \theoremstyle{plain}
    \newtheorem{theorem}{Theorem}%
    \fi

    \theoremstyle{plain}
    \newtheorem{lemma}[theorem]{Lemma}
\end{filecontents}

\documentclass{article}

%\usepackage[numberwithin=section]{mytheorems}%or use option [numberwithin=section] for example

\usepackage{mytheorems}%or use option [numberwithin=section] for example

\begin{document}
    \begin{lemma}
        content...
    \end{lemma}
\end{document}
3
  • Thank you. Good to know that it is common practice to only set some booleans in a package option.
    – user157036
    Mar 27, 2018 at 10:10
  • Could you explain why you use \gdef here? In my primitive test samples, your code also works if I use \def.
    – user157036
    Mar 27, 2018 at 10:11
  • @JohnDorian: I was unsure whether there is a grouping involved during option processing, so I used \gdef (\global\def) for 'safety' reasons. If it works with \def as well, the better
    – user31729
    Mar 27, 2018 at 10:13
3

Add a default option to numberwithin, so that calling

\usepackage[numberwithin]{mytheorems}

or

\usepackage[numberwithin=section]{mytheorems}

will be equivalent as well as \usepackage{mytheorems}, because of \ExecuteOptionsX{numberwithin}. Then delay the association of the counter after processing the options.

\ProvidesPackage{mytheorems}
\RequirePackage{xkeyval}
\RequirePackage{amsmath}
\RequirePackage{amsthm}

\DeclareOptionX{numberwithin}[section]{%
  \def\mthm@numberwithin{#1}%
}
\DeclareOptionX{nonumberwithin}{%
  \def\mthm@numberwithin{}%
}
\ExecuteOptionsX{numberwithin}
\ProcessOptionsX

\theoremstyle{plain}
\newtheorem{theorem}{Theorem}

\ifx\mthm@numberwithin\@empty\else
  \numberwithin{theorem}{\mthm@numberwithin}
\fi

\newtheorem{lemma}[theorem]{Lemma}

You must log in to answer this question.