Ayudas de programación

En cuanto escribes código no trivial en un paquete o en el preámbulo, necesitas cosas que TeX crudo vuelve tediosas: banderas booleanas, pruebas de “¿esta orden está definida?”, pruebas de “¿esta cadena está vacía?” y añadir código a órdenes existentes. etoolbox proporciona justo esas herramientas con una sensación LaTeX, y pgfkeys es la base para construir interfaces de configuración key=value. Ambos son habituales detrás de muchos paquetes.

Qué es etoolbox

etoolbox (escrito por Philipp Lehman y mantenido ahora por Joseph Wright) es una caja de herramientas de programación para autores de clases y paquetes. Envuelve las primitivas de bajo nivel añadidas por e-TeX en una interfaz de estilo LaTeX, y añade varias utilidades generales que no dependen estrictamente de e-TeX. Como todo motor TeX moderno incluye e-TeX, basta con escribir \usepackage{etoolbox}.

Aunque expl3, la capa de programación de LaTeX3, está muy extendida, etoolbox sigue siendo popular porque encaja directamente en el mundo LaTeX2e. Argumentos que puedes escribir claramente como #1, la forma familiar {verdadero}{falso}, y sobre todo \patchcmd (abajo) para arreglar después órdenes de paquetes existentes, lo hacen valioso en preámbulos reales.

Banderas booleanas: toggles y bools

Cuando quieres mantener un estado verdadero/falso, como “¿estamos en modo borrador?”, etoolbox ofrece dos familias. La recomendada es el toggle: tiene su propio espacio de nombres, así que no choca con órdenes existentes. Decláralo con \newtoggle{flag}, cámbialo con \toggletrue{flag} / \togglefalse{flag} o \settoggle{flag}{true}, y ramifica con \iftoggle{flag}{⟨true code⟩}{⟨false code⟩}. También existe \nottoggle{flag}{⟨if not true⟩}{⟨if not false⟩} para la inversa.

latex
\usepackage{etoolbox}

\newtoggle{draft}        % フラグを宣言 / declare the flag
\toggletrue{draft}       % 真にする / set it true

% 本文や命令の中で分岐 / branch on it
\iftoggle{draft}
  {\textbf{[DRAFT]}\ }    % 真のとき / when true
  {}                     % 偽のとき / when false

La otra familia es el bool: \newbool{flag} / \setbool{flag}{true} / \booltrue{flag} / \boolfalse{flag}, probado con \ifbool{flag}{⟨true⟩}{⟨false⟩}. Internamente usa la misma maquinaria que \newif de LaTeX, por lo que reserva un nombre de comando \ifflag. Los toggles bastan casi siempre, pero los bools ayudan cuando hay que interoperar con código basado en \newif.

OrdenSignificadoNotas
\newtoggle{f}Declarar el toggle f (falso al inicio)Tiene su propio espacio de nombres
\settoggle{f}{v}Poner f a v (true/false)O \toggletrue / \togglefalse
\iftoggle{f}{T}{F}T si verdadero, F si falsoToma tres argumentos
\ifbool{f}{T}{F}Versión bool de la ramaMisma maquinaria que \newif

Pruebas de definición y cadenas

Para escribir paquetes con seguridad, a menudo quieres saber “¿esta orden ya está definida?” o “¿el argumento está vacío?”. En etoolbox todas las pruebas usan la misma rama {⟨true⟩}{⟨false⟩}. Para definiciones, usa \ifdef{\cmd}{⟨true⟩}{⟨false⟩}; para probar por nombre (una cadena), \ifcsdef{name}{⟨true⟩}{⟨false⟩}. También existen las inversas \ifundef / \ifcsundef.

Cuidado: la parecida \ifdefined es una primitiva e-TeX, no una orden de etoolbox con forma {true}{false}. Cuando quieras la rama en dos direcciones, usa \ifdef de etoolbox y pasa la orden real, con barra invertida. Para cadenas, están \ifblank{⟨string⟩}{⟨true⟩}{⟨false⟩} para “¿solo espacios?”, su inversa \notblank, \ifstrequal{⟨string⟩}{⟨string⟩}{⟨true⟩}{⟨false⟩} para igualdad, y \ifstrempty para vacío.

latex
% 命令が未定義のときだけ用意する / provide a command only if missing
\ifdef{\highlight}
  {}                              % 既にあれば何もしない / leave it alone
  {\newcommand{\highlight}[1]{\textbf{#1}}}

% 引数が空かどうかで出し分け / vary on an empty argument
\newcommand{\field}[1]{\ifblank{#1}{(none)}{#1}}

Hooks y añadir a comandos

etoolbox también proporciona comandos para hooks, lugares que contienen código a ejecutar en un momento concreto. Los hooks de inicio/fin de documento \AtBeginDocument / \AtEndDocument son del núcleo de LaTeX, pero etoolbox los complementa con \AtEndPreamble al final del preámbulo, \AfterEndDocument al final de todo, y hooks alrededor de un entorno específico: \AtBeginEnvironment{⟨env⟩}{⟨code⟩} / \AtEndEnvironment / \BeforeBeginEnvironment / \AfterEndEnvironment.

Para añadir después a esos hooks, o a cualquier macro, se usan los comandos de añadido. \appto{\cmd}{⟨code⟩} añade al final, \preto{\cmd}{⟨code⟩} al principio (\gappto es global, \eappto expande antes). Para añadir con seguridad a una macro con argumentos, usa \apptocmd{\cmd}{⟨code⟩}{⟨success⟩}{⟨failure⟩} / \pretocmd, con ramas de éxito y fallo.

latex
% すべての itemize の冒頭に行間設定を差し込む
\AtBeginEnvironment{itemize}{\setlength{\itemsep}{2pt}}

% 文書開始時に走るフックへ追記 / append to the begin-document hook
\appto{\@begindocumenthook}{\typeout{Hello from etoolbox}}

Parchear comandos con \patchcmd

La herramienta más famosa de etoolbox es \patchcmd. Sustituye solo parte del cuerpo de una orden ya definida, útil cuando quieres ajustar una orden de otro paquete o del núcleo sin redefinirla entera. Su forma toma cinco argumentos:

latex
\patchcmd{\cmd}{⟨search⟩}{⟨replace⟩}{⟨success⟩}{⟨failure⟩}

Busca en la definición de \cmd la primera ocurrencia que coincida con ⟨search⟩; si la encuentra, la sustituye por ⟨replace⟩ y ejecuta ⟨success⟩; si no, deja la orden intacta y ejecuta ⟨failure⟩. Solo se reemplaza la primera ocurrencia. Puedes dejar ⟨success⟩ / ⟨failure⟩ vacíos, pero es más seguro poner una advertencia en la rama de fallo para notar cuando el parche deja de aplicarse.

Dos consejos prácticos. Primero, la orden objetivo y ⟨search⟩ casi siempre contienen @ porque son internas; envuelve el parche en \makeatletter\makeatother, o cuenta con que \patchcmd convierte temporalmente @ en letra mientras trabaja. Segundo, si un parche no entra, pon \tracingpatches en el preámbulo: el log mostrará diagnósticos como “indefinido” o “patrón no encontrado”. Para especificaciones de argumentos o reemplazos múltiples, es cómodo el paquete xpatch, que amplía etoolbox.

document.tex
\usepackage{etoolbox}

\makeatletter
% 例:ある内部命令 \@foo の定義中の \small を \footnotesize に差し替える
\patchcmd{\@foo}
  {\small}            % 探す / search
  {\footnotesize}     % 置き換える / replace
  {}                  % 成功時 / on success
  {\PackageWarning{mypkg}{Patch to \protect\@foo\space failed}} % 失敗時
\makeatother

Listas y bucles

etoolbox también ofrece listas internas ligeras y formas de iterarlas. Añade un elemento con \listadd{\mylist}{⟨item⟩} y llama a un manejador de un argumento para cada elemento con \forlistloop{⟨handler⟩}{\mylist}. Para recorrer directamente una cadena separada por comas, \docsvlist{a,b,c} y \forcsvlist{⟨handler⟩}{a,b,c} son opciones rápidas. También está \DeclareListParser para crear un analizador con tu propio separador.

latex
% カンマ区切りの各要素を箇条書きにする / each CSV item becomes a bullet
\newcommand{\asitem}[1]{\item #1}
\begin{itemize}
  \forcsvlist{\asitem}{apples, pears, plums}
\end{itemize}

pgfkeys: base para interfaces key=value

pgfkeys es el potente motor clave-valor incluido en PGF/TikZ. La sintaxis familiar de TikZ [draw, thick, fill=blue], y muchas interfaces de paquetes estilo \…setup{...}, están implementadas en gran medida con él. El centro es \pgfkeys{/my/key=value}. Las claves se organizan en espacios de nombres mediante rutas (families) separadas por /, y a cada clave se le asigna un manejador que dice qué hacer cuando se llama.

Los manejadores usados para definir claves son el punto crucial. Para guardar el valor literalmente en una macro, usa .store in=\macro (internamente \def\macro{value}). Para ejecutar código con el valor, usa .code={... #1 ...}, donde el valor pasado llega como #1. El valor usado cuando se llama a la clave sin =value se da con .default=value, y el valor inicial con .initial=value. También existe .is choice para enumerar opciones.

latex
\usepackage{pgfkeys}

% キーを定義する / define keys under /book
\pgfkeys{
  /book/title/.store in = \bookTitle,        % 値をマクロに格納
  /book/edition/.code   = {Edition #1},       % #1 は渡された値
  /book/edition/.default = 1,                  % =値 省略時の既定
  /book/draft/.initial   = false,              % 初期値
}

% キーを設定する / set them
\pgfkeys{/book/title=TeX by Topic, /book/edition=3}

Cuando un paquete expone una entrada como \mypkgsetup{...}, fija una ruta predeterminada para que los usuarios no tengan que anteponer /mypkg/ cada vez. El modismo es \pgfqkeys{/mypkg}{⟨key list⟩} (la “q” es de quick), atajo de \pgfkeys{/mypkg/.cd, ⟨key list⟩}. Con un wrapper de una línea como el de abajo, los usuarios configuran con nombres de clave cortos.

latex
% パッケージ側:設定窓口を一行で / the package: a one-line entry point
\newcommand{\mypkgsetup}[1]{\pgfqkeys{/mypkg}{#1}}

% 利用者側:短いキー名で設定 / the user: short key names
\mypkgsetup{title = My Report, edition = 2}

En el lado LaTeX3 existe un equivalente, l3keys, el módulo clave-valor de expl3, que declara interfaces similares con \keys_define:nn y afines. Una división razonable: usa l3keys al escribir un paquete nuevo en expl3, y pgfkeys cuando quieras encajar con código derivado de TikZ/pgf o activos existentes.