正如所述先前的问题,我希望将用 LaTeX2e 编写的课程转换为语法
expl3
。我将尝试通过提出一系列问题、收集代码示例、进行转换来实现这一点逐步地(引用@PhelypeOleinik)。这样一来,我就能降低违反expl3
惯例的风险。
我从初始化部分开始,例如处理选项和加载类。用expl3
语法实现以下代码效果的正确方法是什么?
% (Package initialization)
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{packagename}
[2021/03/09 ...]
\RequirePackage{kvoptions}
\SetupKeyvalOptions{%
family = packagename,
prefix = packagename@
}
\DeclareBoolOption[false]{off}
\ProcessKeyvalOptions*\relax
% (Class initialization)
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{classname}
[2021/03/09 ...]
\RequirePackage{kvoptions}
\RequirePackage{etoolbox}
\SetupKeyvalOptions{
family = classname,
prefix = classname@,
setkeys= \kvsetkeys,
}
\DeclareStringOption[some-string]{option-name}
\DeclareStringOption{option-with-no-default-value}
\DeclareVoidOption{other-string}{\kvsetkeys{classname}{option-name = other-string}}
\DeclareDefaultOption{\PassOptionsToClass{\CurrentOption}{\classname@baseclass}}
\ProcessKeyvalOptions*\relax
\LoadClass{\classname@baseclass}
也许有更好的方法expl3
,我只是将这些 LaTeX2e 代码作为比较。
答案1
这里有一些内容可以供您参考。这部分代码主要是选项处理,所以我建议您看一下l3keys
模块文档涵盖了可用的密钥处理程序。我将非常简要地解释一下,因为很多这段代码中包含了一些小概念。
首先我们开始声明所需的格式,并加载l3keys2e
类选项解析:
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{l3keys2e}
然后我们声明类(或包):
\ProvidesExplClass{classname}
{2021/03/09} {1.0} {My class to learn expl3}
该命令\ProvidesExpl<thing>
已经\ExplSyntaxOn
为您完成操作,并负责在类/包结束时将其关闭,因此这是启动expl3
基于的类的正确方法。
现在定义一个常量字符串(常量意味着它不应该被改变\str_set:Nn
或类似的东西)来保存基类名称。前缀\c_...
表示它是一个常量(l
是本地的并且g
是全局的),后缀..._str
表示它是一个字符串变量:
\str_const:Nn \c__classname_base_class_str { book }
现在我们将为您的课程定义一些选项classname
:
\keys_define:nn { classname }
{
首先kvoptions
调用一个字符串选项(一个接受值的选项):
% \DeclareStringOption
, option-name .tl_set:N = \l__classname_option_name_tl
, option-name .initial:n = { some-string }
您将其用作 ,option-name
并且赋予它的值将存储在\l__classname_option_name_tl
(l
局部tl
变量)中。初始值为some-string
。 的一个特点\keys_define:nn
是它已经为您创建了变量,因此您无需\tl_new:N \l__classname_option_name_tl
事先执行此操作(但这也没有坏处)。
现在什么kvoptions
叫做 void 选项,它只执行一段代码:
% \DeclareVoidOption
, other-string .code:n =
{ \keys_set:nn { classname } { option-name = other-string } }
使用时,该other-string
选项的作用与 相同option-name=other-string
。
现在是一个布尔选项,其初始值是false
:
% \DeclareBoolOption
, off .bool_set:N = \l__classname_off_bool
, off .initial:n = { false }
最后,告诉你l3str
如何处理未知选项:
% \DeclareDefaultOption
, unknown .code:n =
{
\iow_term:x
{
Passing~option~\CurrentOption \c_space_tl to~
\str_use:N \c__classname_base_class_str
}
\PassOptionsToClass { \CurrentOption } { \c__classname_base_class_str }
}
}
它将在终端中打印“将选项传递给”。\iow_term:n
写入终端,并在将参数传递给底层变体之前对其\iow_term:x
进行“详尽扩展” 。x
n
现在处理选项并加载基类:
\ProcessKeysOptions { classname }
\LoadClass { \c__classname_base_class_str }
作为示例代码,您可以使用它\bool_if:NTF
来测试布尔变量:
\bool_if:NTF \l__classname_off_bool
{ \iow_term:n { off~true } }
{ \iow_term:n { off~false } }
并再次\iow_term:x
写入终端:
\iow_term:x { Value~of~option-name:~\tl_use:N \l__classname_option_name_tl }
综合起来:
\begin{filecontents}{classname.cls}
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{l3keys2e}
\ProvidesExplClass{classname}
{2021/03/09} {1.0} {My class to learn expl3}
\str_const:Nn \c__classname_base_class_str { book }
\keys_define:nn { classname }
{
% \DeclareStringOption
, option-name .tl_set:N = \l__classname_option_name_tl
, option-name .initial:n = { some-string }
% \DeclareVoidOption
, other-string .code:n =
{ \keys_set:nn { classname } { option-name = other-string } }
% \DeclareBoolOption
, off .bool_set:N = \l__classname_off_bool
, off .initial:n = { false }
% \DeclareDefaultOption
, unknown .code:n =
{
\iow_term:x
{
Passing~option~\CurrentOption \c_space_tl to~
\str_use:N \c__classname_base_class_str
}
\PassOptionsToClass { \CurrentOption } { \c__classname_base_class_str }
}
}
\ProcessKeysOptions { classname }
\LoadClass { \c__classname_base_class_str }
% example code:
\bool_if:NTF \l__classname_off_bool
{ \iow_term:n { off~true } }
{ \iow_term:n { off~false } }
\iow_term:x { Value~of~option-name:~\tl_use:N \l__classname_option_name_tl }
\end{filecontents}
\documentclass[10pt,a4paper,option-name=VALUE]{classname}
\begin{document}
\end{document}