tengo el siguiente paquete
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{mypkg}
\providecommand*\@mycmd{No {\MakeUppercase Mycmd} defined}
\newcommand*\Mycmd[1]{\renewcommand*\@mycmd{#1}}
\newcommand*\showDF[1]{\csname @#1\endcsname}
\endinput
Proporciona al usuario el comando \Mycmd{}
para renovar \@mycmd
y \showDF{mycmd}
mostrar su contenido:
\documentclass[a4paper,titlepage,11pt,twoside,openright]{report}
\usepackage{mypkg}
\begin{document}
\showDF{mycmd}\par
\Mycmd{Test}
\showDF{mycmd}
\end{document}
Me gustaría tener los dos primeros comandos definidos con una macro para generar varios pares de cmd.
\@newDF{mycmd}{Mycmd}
lo he intentado con
\newcommand*\@newDF[2]{
\providecommand*\csname @#1\endcsname{No {\MakeUppercase #2} defined}
\newcommand*\csname #2\endcsname[1]{\renewcommand\csname @#1\endcsname{##1}}
}
pero no funcionará.
\newcommand*\newDF[2]{
\expandafter\providecommand\expandafter*\csname @#1\endcsname{No {\MakeUppercase #2} defined}
\expandafter\newcommand\expandafter*\csname #2\endcsname[1]{\renewcommand\csname @#1\endcsname{##1}}
}
compila, pero realmente no sé por qué los puse \expandafter
allí y, de todos modos, \MakeUppercase
se ignora cuando \showDF{mycmd}
se ejecuta y \Mycmd{Hi}
no tiene ningún efecto. Reemplazar \csname @#1\endcsname
con uno @nameuse{@#1}
o \csuse{@#1}
ninguno funciona. ¿Qué me estoy perdiendo?
Respuesta1
Brevemente, la razón por la cual su uso \expandafter
falla es que no tiene suficientes. Para obtener más detalles, consulte las elocuentes explicaciones de esto en otras partes de este sitio, como¿por qué-necesitamos-once-expandafters-para-expandir-cuatro-tokens-en-el-orden-correcto?.
El problema que tiene \MakeUppercase
es que no es expandible, lo que significa que no puede usarlo directamente dentro de una \csname...\endcsname
definición. Esto se explica detalladamente en las respuestas al post.
crear-un-token-macro-en-mayúscula-usando-csname.
Werner ha dado una solución en la que evita el problema de las mayúsculas al pasar tanto el nombre en mayúscula como el nombre sin mayúscula al creador de la macro. Aquí hay otra solución que "pone en mayúsculas" el nombre de la macro automáticamente.
En lugar de usar \providescommand
para verificar si \@my<command>
ya se ha definido, verifico esto directamente usando, \ifcsdef
ya que usar \providescommand
requeriría algunos \expandafter
mensajes de texto que preferiría evitar. Finalmente, como beneficio adicional, el siguiente código también define una "función de fábrica" \@DefineMyCommands
para crear una familia de dichos comandos a partir de una lista separada por comas.
\documentclass{article}
\usepackage{etoolbox}
\makeatletter
\newcommand\@DefineMyCommand[1]{\@ReallyDefineMyCommand#1\relax}
\def\@ReallyDefineMyCommand#1#2\relax{%
% Define command <#1#2> to set @my#1#2={arg of <#1#2>}
% Here #1 is the first character of the comamnd and #2 is the rest.
% We have isolated #1 so that we can uppercase it on the next line
\uppercase{\expandafter\gdef\csname #1}#2\endcsname##1{\@namedef{@my#1#2}{##1}}
% if \@my#1#2 is not already defined then define it
\ifcsdef{@my#1#2}{\relax}{\@namedef{@my#1#2}{No \MakeUppercase{#1#2} defined!}}
}
\newcommand{\@DefineMyCommands}{\forcsvlist{\@DefineMyCommand}}% factory function
\@DefineMyCommands{mycmd, test, fred, julie}% define a bunch of macros
\makeatother
\newcommand*\showDF[1]{\csname @my#1\endcsname}
\begin{document}
\showDF{mycmd}
\Mycmd{A command!}
\showDF{mycmd}
\showDF{test}
\Test{A test!}
\showDF{test}
\end{document}
Aquí está el resultado "esperado":
EditarEn realidad, definir un comando de fábrica es un poco tonto si sólo se va a utilizar una vez. A menos que haya una gran cantidad de estas macros, sería más inteligente escribir
\forcsvlist{\@DefineMyCommand}{mycmd, test, fred, julie}
ya que esto aplica el comando \@DefineMyCommand
a los elementos de la lista sin crear una macro innecesaria.
Respuesta2
Así es como puedes hacer esto:
\documentclass{article}
\makeatletter
%\providecommand*\@mycmd{No {\MakeUppercase Mycmd} defined}
%\newcommand*\Mycmd[1]{\renewcommand*\@mycmd{#1}}
\newcommand{\@newDF}[2]{%
\@namedef{@#1}{No \MakeUppercase{#2} defined}%
%\expandafter\newcommand\csname @#1\endcsname{No \MakeUppercase{#2} defined}% Alternative to above
\expandafter\newcommand\csname #2\endcsname[1]{%
\expandafter\renewcommand\csname @#1\endcsname{##1}}
}
\@newDF{mycmd}{Mycmd}
\newcommand*\showDF[1]{\csname @#1\endcsname}
\makeatother
\begin{document}
\showDF{mycmd}\par
\Mycmd{Test}
\showDF{mycmd}
\end{document}
La salida es:
No hay prueba definida por MYCMD
ElLas definiciones se dan con un\show
:
> \@mycmd=macro:
->No \MakeUppercase {Mycmd} defined.
> \Mycmd=\long macro:
#1->\expandafter \renewcommand \csname @mycmd\endcsname {#1}.