![针对不兼容的选项引发包/类错误](https://linux22.com/image/457788/%E9%92%88%E5%AF%B9%E4%B8%8D%E5%85%BC%E5%AE%B9%E7%9A%84%E9%80%89%E9%A1%B9%E5%BC%95%E5%8F%91%E5%8C%85%2F%E7%B1%BB%E9%94%99%E8%AF%AF.png)
当我编写包或类时,有时会有一些彼此不兼容的选项。我想要的是,如果同时导入两个这样的选项,则引发错误。我试过了\@ifpackagewith{mypackage}{option1,option2}{<true>}{}
,但这仍然会加载两个选项。此外,如果可能的话,我希望它能够更“自动化”地工作。如果我有 3 个不兼容的选项,我希望它打印一个不同的消息取决于加载了哪些选项。
这是一个包含 的 MWE,.sty
其中有两个“不兼容”的选项:option1
和option2
。
\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}
option3
option1
option2
如果option3
也不兼容:
- 当
option1
和option3
被加载时,错误消息应该说option1
和option3
不兼容,并且加载其他选项。 - 当
option1
、option2
和option3
加载时,错误消息应该指出option1
、option2
和option3
不兼容,并且不会加载这三个选项中的任何一个。
一般来说我只想打印以下选项确实装载了在错误消息中。我还希望包不使用任何冲突的选项,如上所述。
答案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}