使用键值选项避免寄生类中出现虚假警告(LaTeX3 \DeclareKeys)

使用键值选项避免寄生类中出现虚假警告(LaTeX3 \DeclareKeys)

这是修改后的版本在类选项中使用参数时出现“未使用的全局选项”问题是如何创建一个寄生类(即加载另一个类的类),它接受特定于该类的键值选项,但不会生成有关未知选项的警告。

考虑,

\begin{filecontents}[overwrite]{\jobname.cls}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{\jobname}
\DeclareOption{bertha}{}
\DeclareKeys[testwork]{%
  test .code ={\newcommand{\foo}{#1}},
  test .usage = load,
}
\ProcessKeyOptions[testwork]
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}

\ProcessOptions\relax
\LoadClass{article}

\endinput
\end{filecontents}
\documentclass[test=wtf,bertha]{\jobname}

\begin{document}
test \foo
  
\end{document}

编译此示例产生了预期的排版结果,但打印到终端和记录在日志中的消息并不像预期的那样。

LaTeX Warning: Unused global option(s):
    [test].

在原始问题中,使用 创建键值选项xkeyval。我无法弄清楚如何避免这种情况下的警告,但我希望使用内置框架声明键值选项可以更好地处理。

根据clsguide.pdf只有寄生类未声明的选项才应传递给article。 例如,这是正确的bertha。 但显然, 并不正确test。 此外,如果test=wtf传递给article,我希望它与其值一起传递,即我希望出现关于 的警告,test=wtf而不是test

显然,我没有正确设置,但我不确定我做错了什么。到底该怎么做?

答案1

您混合了两个选项系统,这会混淆未使用列表处理的设置,因为对于每个系统,不同的选项是“未知的”并且因此未使用。

坚持使用一个系统(可以使用的系统\CurrentOption没有\DeclareUnknownKeyHandler记录,我们应该改变它;-))。

\begin{filecontents}[overwrite]{testoption.cls}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{testoption}
\DeclareKeys[testwork]{%
  bertha .code={},
  test .code ={\newcommand{\foo}{#1}},
  test .usage = load  
}
\DeclareUnknownKeyHandler [testwork]
 {\PassOptionsToClass{\CurrentOption}{article}}

\ProcessKeyOptions[testwork]
\LoadClass{article}
\endinput
\end{filecontents}
\documentclass[test=wtf,bertha,12pt]{testoption}

\begin{document}
test \foo
  
\end{document}

答案2

问题似乎在于使用\ProcessKeyOptions\ProcessOptions。相反,我会使用:

\begin{filecontents}[overwrite]{\jobname.cls}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{\jobname}
\DeclareKeys[testwork]{%
  test .code ={\newcommand{\foo}{#1}},
  test .usage = load,
  bertha .code = {},
  bertha .value_forbidden:n = true,
}
\DeclareUnknownKeyHandler[testwork]{%
  \PassOptionsToClass{\CurrentOption}{article}%
}
\ProcessKeyOptions[testwork]\relax

\LoadClass{article}

\endinput
\end{filecontents}
\documentclass[test=wtf,bertha,alpha,gamma=true,12pt]{\jobname}

\begin{document}
test \foo
  
\end{document}

(/usr/local/texlive/2023/texmf-dist/tex/latex/base/size12.clo)

log-file 中显示,该选项12pt已正确传递给 并被 识别article.cls

信息:

 LaTeX Warning: Unused global option(s):
     [alpha,gamma].

表明两个未知选项正确地导致警告信息。

注意:对于键值选项,LaTeX 始终只将键报告为未知。这是一个功能。


附录:如果加载的类本身处理键值选项​​,则使用此建议也有效:

\begin{filecontents}[overwrite]{test.cls}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{\jobname}
\DeclareKeys[testwork]{%
  test .code ={\newcommand{\foo}{#1}},
  test .usage = load,
  bertha .code = {},
  bertha .value_forbidden:n = true,
}
\DeclareUnknownKeyHandler[testwork]{%
  \PassOptionsToClass{\CurrentOption}{test-base}%
}
\ProcessKeyOptions[testwork]\relax

\LoadClass{\jobname-base}

\endinput
\end{filecontents}
\begin{filecontents}[overwrite]{test-base.cls}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{\jobname-base}
\DeclareKeys{%
  gamma .code= \typeout{Gamma=`#1'},
  gamma .value_required:n =true
}
\DeclareUnknownKeyHandler{%
  \PassOptionsToClass{\CurrentOption}{article}
}
\ProcessKeyOptions
\LoadClass{article}
\end{filecontents}
\documentclass[test=wtf,bertha,alpha,gamma=test,gamma=,12pt]{test}

\begin{document}
test
  
\end{document}

这里你还可以看到, 被gamma=传递为gamma=testtest-base。 (如果 被传递为gamma,则会报告错误,因为gamma需要一个值。)

答案3

编辑:第一个代码块 using\ProcessKeyOptions并没有真正起作用,因为\ProcessKeyOptions它会将所有未知选项添加到未使用的全局选项列表中,因此如果您使用一个已知article但不属于您的类的选项,您将得到一个误报。下面的 using 代码块不是这种情况expkv-opt\ekvoProcessGlobalOptions它只会删除,而不会添加到未使用的全局选项列表中。

编辑2:如果在第一个代码中使用unknown处理程序,应该会得到所需的行为,但目前(2023-11-20)选项处理中存在一个错误(已报告#1183),这个问题至少会在 LaTeX 2024-06-01 之前得到修复。


我建议颠倒一下逻辑。您不必先解析类的选项,然后将未知的选项转发给article,而是可以先加载article整个列表,然后再解析选项。只要您的类没有定义对有效的选项,这基本上会具有相同的行为,并且您的代码不会遇到太多麻烦(请参阅中article的文档)。未使用的选项列表仍然相同:\LoadClassWithOptionsclsguide.pdf

\begin{filecontents}[overwrite]{\jobname.cls}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{\jobname}
\LoadClassWithOptions{article}

\DeclareKeys[testwork]{%
  test .code  = \newcommand{\foo}{#1},
  test .usage = load,
  % the following three lines give an equivalent definition of your bertha
  % option as defined with `\DeclareOption{bertha}{}`
  bertha .code = {},
  bertha .value_forbidden:n = true,
  bertha .usage = load,
  # ignore unknown options to not add them to the unused options list
  unknown .code = {}
}
\ProcessKeyOptions[testwork]

\endinput
\end{filecontents}
\documentclass[test=wtf,bertha]{\jobname}

\begin{document}
test \foo
\end{document}

由于我必须做广告,这是使用等效代码expkv

\begin{filecontents}[overwrite]{\jobname.cls}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{\jobname}
\LoadClassWithOptions{article}
\RequirePackage{expkv-opt,expkv-def}
\ekvdefinekeys{testwork}
  {%
    % `store` isn't really equivalent to your newcommand-using code, that
    % would've been:
    %   code test = \newcommand\foo{#1}
    % Instead `store` is equivalent to ltkeys' `.store` handler.
     store test    = \foo
    ,noval bertha  = {}
  }
% if a standard class was already loaded by \LoadClassWithOptions in a parasitic
% class the unused options list is already filled, we don't need to parse local
% options any more, and only having the package's default handling of global
% options is fine.
\ekvoProcessGlobalOptions{testwork}

\endinput
\end{filecontents}
\documentclass[test=wtf,bertha]{\jobname}

\begin{document}
test \foo
  
\end{document}

相关内容