针对不兼容的选项引发包/类错误

针对不兼容的选项引发包/类错误

当我编写包或类时,有时会有一些彼此不兼容的选项。我想要的是,如果同时导入两个这样的选项,则引发错误。我试过了\@ifpackagewith{mypackage}{option1,option2}{<true>}{},但这仍然会加载两个选项。此外,如果可能的话,我希望它能够更“自动化”地工作。如果我有 3 个不兼容的选项,我希望它打印一个不同的消息取决于加载了哪些选项。

这是一个包含 的 MWE,.sty其中有两个“不兼容”的选项:option1option2

\documentclass{article}

\begin{filecontents}[overwrite]{mypackage.sty}
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{mypackage}

% Incompatible options:
\DeclareOption{option1}{\newcommand{\foo}{Foo baz baa}}
\DeclareOption{option2}{\newcommand{\foo}{Baa foo baz}}
% Unknown options:
\DeclareOption*{\PackageWarning{mypackage}{No option ‘\CurrentOption’}}
\ProcessOptions\relax
\makeatletter
\@ifpackagewith{mypackage}{option1,option2}{\PackageError{mypackage}{option clash: 'option1' and 'option2'}{Options are incompatible}}{}
\makeatother

\endinput
\end{filecontents}

\usepackage[option1,option2]{mypackage}

\begin{document}

This is a test.
\foo

\end{document}

我认为,如果选项不兼容,则应使用相邻选项(但仍可以使用其他选项)。假设我有第三个选项option3并尝试了。那么结果应该与(如果与和兼容)\usepackage[option1,option2,option3]{mypackage}相同,并且出现错误。\usepackage[option3]{mypackage}option3option1option2

如果option3也不兼容:

  • option1option3被加载时,错误消息应该说option1option3不兼容,并且加载其他选项。
  • option1option2option3加载时,错误消息应该指出option1option2option3不兼容,并且不会加载这三个选项中的任何一个。

一般来说我只想打印以下选项确实装载了在错误消息中。我还希望包不使用任何冲突的选项,如上所述。

答案1

以下 (或多或少) 符合 @DavidCarlisle 的建议。如果冲突选项的总和大于 1,您可以轻松检查是否指定了冲突选项。

\documentclass{article}

\begin{filecontents}[overwrite]{mypackage.sty}
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{mypackage}

\newcommand\foo
  {\PackageError{mypackage}{No option setting \noexpand\foo specified}{}}

% Incompatible options:
\chardef\mypkg@optA=0
\chardef\mypkg@optB=0
\DeclareOption{option1}{\chardef\mypkg@optA=1\relax}
\DeclareOption{option2}{\chardef\mypkg@optB=1\relax}
% Unknown options:
\DeclareOption*{\PackageWarning{mypackage}{No option ‘\CurrentOption’}}
\ProcessOptions\relax
\ifnum\numexpr\mypkg@optA+\mypkg@optB>\@ne % easily extensible for n options
  \PackageError{mypackage}
    {The options `option1` and `option2` are mutually exclusive}
    {Sorry, but I decided that way}
\fi
\ifodd\mypkg@optA
  \renewcommand{\foo}{Foo baz baa}
\fi
\ifodd\mypkg@optB
  \renewcommand{\foo}{Baa foo baz}
\fi

\endinput
\end{filecontents}

\usepackage[option1,option2]{mypackage}

\begin{document}

This is a test.
\foo

\end{document}

下面实现了一种可以缓解这种疯狂现象的机制(抱歉,但我仍然认为这是一个糟糕的设计选择):

\documentclass{article}

\begin{filecontents}[overwrite]{mypackage.sty}
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{mypackage}

\newcommand\foo
  {\PackageError{mypackage}{No option setting \noexpand\foo specified}{}}

% Incompatible options:
\newcommand\mypkg@options@code{}
\newcommand\mypkg@DeclareOption[1]
  {\expandafter\mypkg@DeclareOption@\csname mypkg@opt@#1\endcsname{#1}}
\newcommand\mypkg@DeclareOption@[3]
  {%
    \chardef#1=\z@
    \DeclareOption{#2}{\chardef#1=\@ne}%
    \edef\mypkg@options@code
      {%
        \unexpanded\expandafter
          {%
            \mypkg@options@code
            \ifodd#1%
              \expandafter\@secondoftwo
            \fi
            \@gobble{#3}%
          }%
      }%
  }
\ExplSyntaxOn
\cs_new_eq:NN \mypkg@map@clist \clist_map_function:nN
\cs_new_eq:NN \mypkg@use@clist \clist_use:nnnn
\ExplSyntaxOff
\newcommand\mypkg@conflicting@options[1]
  {%
    \ifnum\numexpr\mypkg@map@clist{#1}\mypkg@conflicting@options@>\@ne
      \PackageError{mypackage}
        {%
          The following options are mutually exclusive:\MessageBreak
          \mypkg@use@clist{#1}{ and }{, }{ and }%
        }
        {Sorry, but I decided that way}%
    \fi
  }
\newcommand\mypkg@conflicting@options@[1]{+\csname mypkg@opt@#1\endcsname}

\mypkg@DeclareOption{option1}{\renewcommand{\foo}{Foo baz baa}}
\mypkg@DeclareOption{option2}{\renewcommand{\foo}{Baa foo baz}}
\mypkg@DeclareOption{option3}{\renewcommand{\foo}{Baz baa foo}}
% Unknown options:
\DeclareOption*{\PackageWarning{mypackage}{No option ‘\CurrentOption’}}
\ProcessOptions\relax

\mypkg@conflicting@options{option1,option2,option3}

% run the code of the options
\mypkg@options@code

\endinput
\end{filecontents}

\usepackage[option1]{mypackage}

\begin{document}

This is a test.
\foo

\end{document}

相关内容