修补重要的 LaTeX 命令,例如 \usepackage

修补重要的 LaTeX 命令,例如 \usepackage

这属于“有用但令我紧张的事情”类别。

我在 LuaLaTeX 中使用了一个非常复杂的自定义文档类。但我的问题可以用这个通用的 MWE 轻松说明:

\documentclass{article}
\RequirePackage{xifthen}
\RequirePackage{letltxmacro}
\LetLtxMacro\myusepackage\usepackage\relax
\LetLtxMacro\myRequirePackage\RequirePackage\relax
\renewcommand\usepackage[2][]{%
  \ifthenelse{\equal{#2}{hyperref}}{}{\myusepackage[#1]{#2}}% 
}
\renewcommand\RequirePackage[2][]{%
  \ifthenelse{\equal{#2}{hyperref}}{}{\myRequirePackage[#1]{#2}}% 
}
%
\usepackage{xstring} % should work
\usepackage{hyperref} % should do nothing
%
\begin{document}
OK
\end{document}

如果用户尝试加载 hyperref,它将被默默忽略。我知道还有其他替代方案,例如\PassOptionsToPackage,但这不是我想要的效果。

我经常修补各种 LaTeX 包中的命令,但这些是可选包中的高级命令,而不是像\usepackage或 这样的基本命令\RequirePackage。所以我的问题是:上述 MWE 代码是否有任何隐藏的陷阱?

我只是hyperref为了 MWE 的目的而选择的,所以没有必要问为什么我要在真实文档中阻止它。

编辑:对于那些想知道我为什么要这样做的人:由于\immediate\write命令,我的自定义文档类需要以精确的顺​​序加载某些内容。 如果用户过早加载包,目前我会通过在类代码中抛出错误来检测\@ifpackageloaded,就在我自己的代码加载包之前\AtEndPreamble。 但在我看来,简单地忽略过早加载会更加用户友好。

EDIT2:根据评论和回答,我认为我应该保留我目前的方法,而不是按照问题要求去做。“糟糕的用户界面”(DC 的说法)是一个重点。

无需深入研究超过 200K 字节的自定义文档类,我可以说明我一直在做什么。这已经运行了好几个月了。“myscustomclass.cls”的一般概念如下:

a) 当 mycustomclass 加载时,它还会加载和预配置许多包。它还提供自己的命令。

b) 它包含\AtEndPreamble将加载和配置附加包。这些包直到用户前言之后才能加载,因为它需要查看用户前言并决定要做什么。

c) 至少一个稍后加载的包具有\immediate\write,这不能早于某个时间发生。这就是为什么它被推迟到\AtEndPreamble

目前(良好的工作代码)我做这样的事情:

\AtEndPreamble{
  % lots of code here
  @ifpackageloaded{hyperref}{ % Should not have been loaded by user! Too early!
    \ClassError{mycustomclass}%
    {Cannot load hyperref in preamble}{See myscustomclass docs section XX.XXX}
  }{
    \usepackage[various options]{hyperref}
  }
  % lots of code here
}

答案1

不确定这里的问题是什么,但\usepackage在某些情况下,如图所示的修补将无法按预期工作,例如

\usepackage{longtable,hyperref}

因为它不会将其hyperref视为参数,并且它将完全破坏有效的用法,例如

\usepackage{hyperref}[2001/01/01]

因为它删除了可选参数,所以 latex 会尝试[2001/01/01]在序言中进行排版。

答案2

此外大卫的回答, 考虑

\usepackage{bookmark}

bookmark.sty包括

\RequirePackage{hyperref}[2010/06/18]

以及一堆其他的东西,然后是一堆依赖于的代码hyperref

或者

\usepackage[<options>]{hyperref}

您只是丢弃了用户的选项。

或者

\usepackage{hyperref}
\usepackage{cleveref}

或者其他必须在之后加载的包hyperref

或者

\usepackage{hyperref}
\hypersetup{...}

相关内容