Definir comandos globales en el archivo auxiliar

Definir comandos globales en el archivo auxiliar

Estoy escribiendo un documento largo y, para hacerme la vida más fácil, me gusta definir cantidades que uso como macros para tener que actualizarlas en un solo lugar cuando cambian. Para mí, tiene sentido definirlos a medida que avanzo, en la sección de mi documento que sea más relevante para ellos. Sin embargo, a veces me gustaría usar estos comandos en otros capítulos, a veces incluso en capítulos anteriores.

Por lo tanto, me gustaría agregar una macro que escupe una definición de un comando en los .auxarchivos latex, de modo que un comando pueda usarse en todas partes una vez que se haya definido. Hasta ahora tengo esto:

% Make a command which defines a macro with \providecommand but in the aux file,
% so it's accessible to all other chapters
\makeatletter
\newcommand{\doccommand}[2]{%
\protected@write\@auxout{}{\protect\providecommand\protect#1{#2}}%
}
\makeatother

Esto coloca lo siguiente en el archivo auxiliar.

\providecommand \tester {123}

para un capítulo como este:

\chapter{Test chapter}

This is a test chapter!

Tester is \tester{}.

\doccommand{\tester}{123}

Desafortunadamente, no funciona. Incluso usar el comando dentro del capítulo de prueba me da "Secuencia de control indefinida", y lo mismo en otros capítulos.

Originalmente pensé que esto podría tener algo que ver con los espacios que terminaron en el .auxarchivo, pero los eliminé manualmente y los compilé con un \includeonly{a_different_chapter}archivo que todavía muestra el mismo error.

¿Lo que da?

Actualizar:

Gracias a toda la ayuda aquí, logré que esto funcionara y lo escribí en un pequeño paquete. Si estás interesado, puedes encontrarlo en CTAN enhttps://ctan.org/pkg/globalvals

Respuesta1

Yo usaría una estrategia diferente: usar un comando contenedor, en lugar de definir macros directamente.

\documentclass{article}

\makeatletter
\newcommand{\usevalue}[1]{%
  \ifcsname usevalue@#1\endcsname
    \csname usevalue@#1\endcsname
  \else
    ??%
  \fi
}
\newcommand{\definevalue}[2]{%
  \write\@auxout{%
    \unexpanded{\global\@namedef{usevalue@#1}{#2}}%
  }
}
\makeatother

\begin{document}

Something with \usevalue{tester}.

Something else.

Now we can define \texttt{tester} and use again it: \usevalue{tester}.

\definevalue{tester}{42}

\end{document}

Salida de la primera ejecución

ingrese la descripción de la imagen aquí

Salida de la segunda ejecución

ingrese la descripción de la imagen aquí

Respuesta2

podrías escribir

\makeatletter
\newcommand{\doccommand}[2]{%
  \immediate\write\@auxout{\gdef\noexpand#1{\unexpanded{#2}}}%
  \gdef#1{#2}%
}
\makeatother

Esto hará una definición global sin expandir el texto de reemplazo. Agregué un directo adicional \gdefpara que el comando pueda usarse sin volver a ejecutar TeX.

Pero esto no es una buena idea: si nunca usa el comando antes del punto donde está definido, definirlo en el archivo auxiliar es inútil. Si usa el comando antes de definirlo, LaTeX nunca llega al punto donde escribe la entrada del archivo auxiliar.

Por lo tanto, solo puede usar el comando después de ejecutar TeX una vez con el comando definido pero no usado. Si alguna vez elimina el archivo auxiliar, su documento estará roto. Si alguna vez incluye solo un capítulo diferente, la entrada del archivo auxiliar no se escribirá, por lo que su documento se romperá.

En su lugar, podría crear un archivo separado con las definiciones que incluya en el preamplificado. Es más trabajo, pero da como resultado un documento mucho más estable.

Respuesta3

Gracias @egreg por un enfoque inteligente. Modifiqué su código ligeramente para agregar un mensaje de error si se realizan dos definiciones en el mismo documento:

\documentclass{article}    

\usepackage{siunitx}

\makeatletter
\newcommand{\useVal}[1]{%
  \ifcsname useVal@#1\endcsname
    \csname useVal@#1\endcsname
  \else
    ??%
  \fi
}
\newcommand{\defVal}[2]{%
\ifcsname useVal@#1@defined\endcsname
    \PackageError{useVal}{Value "#1" already defined}{}
\else
  \write\@auxout{%
    \unexpanded{\global\@namedef{useVal@#1}{#2}}%
  }
  \global\@namedef{useVal@#1@defined}{}
\fi
}
\makeatother

\begin{document}

Testval is \useVal{testVal}.

Now defining testval...

\defVal{testVal}{\SI{123}{\meter}}

Now it's \useVal{testVal}. 

% This would throw an error:
% \defVal{testVal}{Not this please!}

\end{document}

información relacionada