用 expl3 编写 | 1)如何正确使用 expl3 语法编写初始化部分?

用 expl3 编写 | 1)如何正确使用 expl3 语法编写初始化部分?

正如所述先前的问题,我希望将用 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_tll局部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进行“详尽扩展” 。xn

现在处理选项并加载基类:

\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}

相关内容