Mi ejemplo específico:

Mi ejemplo específico:

Estoy intentando crear muchos comandos diferentes basados ​​en un solo comando (esencialmente un encabezado personalizado) de una manera predecible. ¿Hay alguna manera de hacer esto en TeX/LaTeX?

Mi ejemplo específico:

Estoy escribiendo una especificación de módulo, donde cada uno de los subtítulos se indica con \modulespec{description}{the description}o \modulespec{learning outcomes}{the learning outcomes}, etc. Espero que TeX pueda generar comandos como \mdescription{the description}y\mlearningoutcomes{the learning outcomes}

Sé que en una expansión tipo bash combinada con TeX escribiría

for i in 'description' 'learning outcomes'
do
    \def\csname m\getRidOfSpaces{$i} \endcsname{\modulespec{$i}{#1}}
done

(si disculpa la combinación de idiomas) donde \getRidOfSpacescambia learning outcomesa learningoutcomes. ¿Es esto posible/factible con TeX/LaTeX?

M(no)NOSOTROS:

\documentclass{article}
\usepackage{blindtext}

% In the real thing, this definition is much more complicated
\newcommand{\modulespec}[2]{\section{#1} #2}

% The code I want in pure TeX/LaTeX
for i in 'description' 'learning outcomes'
do
    \def\csname m\getRidOfSpaces{$i} \endcsname{\modulespec{$i}{#1}}
done
% end of non TeX code


\begin{document}

% Both work
\modulespec{description}{\blindtext}
\modulespec{learning outcomes}{\blindtext}

% These two commands should produce the same output as the previous two
\mdescription{\blindtext}
\mlearningoutcomes{\blindtext}

\end{document}

Respuesta1

Aquí hay una implementación de LaTeX3.

\documentclass{article}
\usepackage[margin=1cm]{geometry} % to fit in one page
\usepackage{blindtext}
\usepackage{xparse}

\newcommand{\modulespec}[2]{\section{#1} #2}

\ExplSyntaxOn

\NewDocumentCommand{\definemodules}{m}
 {
  \farley_definemodules:n { #1 }
 }

\tl_new:N \l_farley_temp_tl
\cs_new_protected:Npn \farley_definemodules:n #1
 {
  \clist_map_inline:nn { #1 }
   {
    \tl_set:Nn \l_farley_temp_tl { ##1 }
    \tl_replace_all:Nnn \l_farley_temp_tl { ~ } { }
    \cs_new_protected:cpn { m \l_farley_temp_tl } { \modulespec { ##1 } }
   }
 }

\ExplSyntaxOff

\definemodules{
  description,
  learning outcomes
}

\begin{document}

\modulespec{description}{\blindtext}
\modulespec{learning outcomes}{\blindtext}

% These two commands should produce the same output as the previous two
\mdescription{\blindtext}
\mlearningoutcomes{\blindtext}

\end{document}

ingrese la descripción de la imagen aquí

Algunos comentarios sobre el código.

Definimos una macro a nivel de usuario para definir todos los módulos de una sola vez; esto es \definemodulessimplemente entregar el control a la función de nivel del programador \farley_definemodules:n(esta es la mejor práctica según las pautas de programación LaTeX3).

Ahora la función \farley_definemodules:ndivide su argumento entre comas y realiza un bucle sobre los elementos. El elemento actual está disponible como #1, pero lo necesitamos ##1porque estamos dentro de una definición.

Cada ciclo almacena el elemento en la variable de lista de tokens reutilizables \l_farley_temp_tlpara que podamos aplicarlo \tl_replace_all:Nnn. El reemplazo es “cualquier espacio es reemplazado por nada”; en el entorno de programación los espacios se ignoran, por lo que un "espacio real" se indica con ~.

Ahora usamos la \cs_new_protected:cpnfunción que es análoga al estilo antiguo \@namedef: el primer argumento se convierte en un nombre de secuencia de control con \csname...\endcsname(la lista de tokens se expande aquí mediante la regla TeX).

Respuesta2

Parece que quieres hacer un bucle "para cada". El kernel de LaTeX tiene una macro \@forque hace esto para cada elemento de una lista separada por comas. También necesitas \zap@spaceo similar para eliminar espacios. Por ejemplo:

\newcommand{\modulespec}[2]{\section{#1} #2}
\makeatletter
\@for\@tempa:=description,learning outcomes\do{%
  \edef\@tempa
    {\expandafter\expandafter\expandafter\zap@space
      \expandafter\@tempa\space\@empty}%
  \expandafter\edef\csname m\@tempa\endcsname
    {\noexpand\modulespec{\@tempa}}%
}
\makeatother

definirá \mdescriptiony \mlearningoutcomessegún sea necesario. He usado un \edefpara forzar la expansión de la variable en los lugares correctos. (No sirve de nada aplicar \protected@edefaquí ya que el 'texto' tiene que ser 'seguro' en el interior \csname).

Respuesta3

Uso \xintForde las utilidades del kernel LaTeX2e (con un @en sus nombres):

\documentclass{article}
\usepackage[english]{babel}
\usepackage{blindtext}
\usepackage{xinttools}
% In the real thing, this definition is much more complicated
\newcommand{\modulespec}[2]{\section{#1} #2}

% % The code I want in pure TeX/LaTeX
% for i in 'description' 'learning outcomes'
% do
%     \def\csname m\getRidOfSpaces{$i} \endcsname{\modulespec{$i}{#1}}
% done
% % end of non TeX code

% Nota bene: in the above you probably meant \long\def, not \def
\makeatletter
\xintFor #1 in {description, learning outcomes}\do
{\long\@namedef{m\zap@space #1 \@empty}##1{\modulespec{#1}{##1}}}
\makeatother

\begin{document}

% Both work
\modulespec{description}{\blindtext}
\modulespec{learning outcomes}{\blindtext}

% These two commands should produce the same output as the previous two
\mdescription{\blindtext}
\mlearningoutcomes{\blindtext}

\end{document}

bucle de definición

información relacionada