用或不用 @ 定义维度

用或不用 @ 定义维度

如果我正在编写 TeX 包(可以在 CTAN 上找到),则有以下方法可以定义新的维度length 应该可以由用户改变那个包裹。

  • 方法 A:使用 @ 定义不可访问的维度,并使用可访问的宏进行设置(另请参阅的意思 @

    \newdimen\PKG@length \PKG@length=5pt
    \def\setPKGlength#1{\PKG@length=#1}
    

    并要求用户使用以下方式修改尺寸\setPKGlength{7pt}

  • 方法 B:定义不使用 @ 的可访问维度

    \newdimen\PKGlength \PKGlength=5pt
    

    并要求用户使用标准技术(如\setlength{\PKGlength}{7pt}LaTeX 或\PKGlength{7pt}纯 TeX)修改尺寸(另请参阅设置尺寸参数的正确方法是什么?)。

哪种方法更安全或更具优势?还有其他选择吗?

答案1

设置维度

有几种方法:

  • 乳胶:

    \newcommand*{\setPKGlength}[1]{\setlength{\PKG@length}{#1}}
    

    优点:calc自动支持包。

  • 电子特克斯:

    \def\setPKGlength#1{\PKG@length=\dimexpr(#1)\relax}
    
  • 纯 TeX:

    \def\setPKGlength#1{\PKG@length=#1\relax}
    

    不要忘记最后\relax(见约瑟夫·赖特的回答

方法A(设置函数和内部寄存器名称)

优点:

  • 如果 PKGlength 使用 TeX 维度寄存器这一事实是实现细节,则应将其隐藏,例如通过使用 -notation@并提供 setter 函数。然后可以轻松更改内部表示,例如使用宏而不是寄存器。

缺点:

  • 至少需要一个额外的宏来设置。

  • 如果没有 getter 函数就很难获取当前值,因此很难设置相对值,例如将长度值设置为当前设置的 50%。

方法 B(直接维度寄存器)

优点:

  • 快速访问,无需设置值的开销。

  • 读访问,可以设置相对值,例如:

    \PKGlength=.5\PKGlength
    

缺点:

  • 维度寄存器成为包接口的一部分,禁止以后更改存储类型(维度寄存器、宏等)。

通过键值接口设置

问题提到了 LaTeX 和纯 TeX,因此我使用我的软件包kvdefinekeyskvsetkeys它可以与 LaTeX、纯 TeX 甚至 iniTeX 一起使用。LaTeX 的替代品有keyval、、、、...xkeyvalpgfkeysl3keys

\newdimen\PKG@length
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname RequirePackage\endcsname\relax
  % plain TeX
  \input kvdefinekeys.sty\relax
  \input kvsetkeys.sty\relax
  \begingroup\expandafter\expandafter\expandafter\endgroup
  \expandafter\ifx\csname dimexpr\endcsname\relax
    % without \dimexpr
    \kv@define@key{PKG}{PKGlength}{\PKG@length=#1\relax}%
  \else
    % with \dimexpr
    \kv@define@key{PKG}{PKGlength}{\PKG@length=\dimexpr(#1)\relax}%
  \fi
\else
  \RequirePackage{kvdefinekeys}%
  \RequirePackage{kvsetkeys}%
  \kv@define@key{PKG}{PKGlength}{\setlength{\PKG@length}{#1}}%
\fi
\def\PKGsetup#1{% or \newcommand for \LaTeX
  \kvsetkeys{PKG}{#1}%
}

% usage example
\PKGsetup{PKGlength=5pt}

答案2

使用特定的作者界面而不是向作者公开内部内容的好处是可以灵活应对未来的变化。例如,作为作者,我可能\setPKGlength{7pt}在五篇论文中使用了您的宏。

如果该命令由包内部使用,而您作为包的维护者可能\setlengthPKG{7pt}出于可读性原因决定将宏更改为,那么我将无法处理我以前的论文。

公开接口而不是内部命令是许多计算机语言编程中的常见范例。对于 TeX/LaTeX,它还带来了方程式的一致性(内部命令应该有@),外部命令不应该有 。

编辑

我个人的偏好是公开 PGF 键样式接口,用于需要大量参数的情况(请参阅更长的例子), 例如:

\cxset{try textheight/.code=\global\setlength\trytextheight@cx{#1},
   try textheight/.default=\textheight,
   try headheight/.code=\global\setlength\tryheadheight@cx{#1},
   try headheight/.default=\headheight, 
   try headsep/.code=\global\setlength\tryheadsep@cx{#1},
   ....
   try topmargin/.code=\global\setlength\trytopmargin@cx{#1},
   try topmargin/.default=\topmargin,...
}

对于更简单的情况,设置快速 setter 和 getter 是我首选的编码风格:

\documentclass{article}
\usepackage{lipsum}
\makeatletter
%  Properties.
\def\ece#1#2{\expandafter#1\csname#2\endcsname}%

% \setproperty@cx{atom}{propertyname}{value} defines the property 
% propertyname  on the ``atom'' atom to have value.

\def\setproperty@cx#1#2#3{\ece\protected@edef{#1@p#2}{#3}}%

% \getproperty@cx{atom}{propertyname} expands to the value of the property
% propertyname on atom.

\def\getproperty@cx#1#2{%
    \expandafter\ifx\csname#1@p#2\endcsname\relax
        \else \csname#1@p#2\endcsname
    \fi
}


\long\def\setminipage@cx#1#2{%
    \setproperty@cx{boxwidth}{width}{\dimexpr#1\relax}%
    \fbox{%
        \minipage{\getproperty@cx{boxwidth}{width}}
            \raggedright #2
        \endminipage
    }%
}

\def\setparindent@cx#1{%
    \setproperty@cx{parindent}{value}{\dimexpr#1\relax}% 
    \parindent\getproperty@cx{parindent}{value}%
    %begins a paragraph if necessary
    \leavevmode
}


% Author command API

\let\SetParagraphIndentation\setparindent@cx
\let\SmallBox\setminipage@cx

\makeatother

\begin{document}

\SmallBox{25pt+35pt}{lorem ipsum dorem. Lorem\par lorem.}

\lipsum[5]
\SetParagraphIndentation{.5in + 2cm + 10pt}
\lipsum[5]
\end{document}

相关内容