# meta-command - need help with expansion

To enforce labeling regulations in a document to be edited by ~50 users (imported subdocuments) i have to re-redine the existing document structuring commands part, chapter, etc to follow a predefined labeling scheme (prefixing with hierarchy level to avoid collisions).

As examples speak more than words, here my current definition for chapter (omitting details). Basically, both \chapter and \chapter* are extended with an optional parameter used to define a label which is automatically prefixed by "chap:", reusing the old \chapter command. Additionally, a command for creating references is defined where short vs. long reference text is chosen via the boolean variable \iflongrefs.

\RequirePackage{letltxmacro}
\RequirePackage{xargs}

\newcommand*\section@namelong{Section}%
\newcommand*\section@nameshort{Sect.}%
\newcommand*\section@prefix{sect}%

\LetLtxMacro{\section@old}{\section}%
\renewcommand\section{\@ifstar \section@star \section@nostar}%
\newcommandx*\section@nostar[3][1=,3=]{%
\ifx &#1&%
\section@old{#2}%
\else%
\section@old[#1]{#2}%
\fi%
\ifx &#3&%
\else%
\label{\section@prefix:#3}%
\fi%
}%
\newcommandx*\section@star[2][2=]{%
\section@old*{#1}%
\ifx &#2&%
\else%
\label{\section@prefix:#2}%
\fi%
}%

\newcommand*\sectionref[1]{
\iflongrefs
\section@namelong~\ref{\section@prefix:#1}
\else
\section@nameshort\,\ref{\section@prefix:#1}
\fi
}


Now, I need similar definitions for part, subsection, etc... Of course I can copy & paste this, replacing \section@XXX with \part@XXX etc accordingly. However I'd prefer a more elegant solution, such as a "higher-order command" \extend encapsulating the (re)definitions. A call to \extend for chapters should look like the line given below, and produce all the code seen above.

\extend{section}{Section}{Sect.}{sect}


How can I make this work? Reading through various forum posts I feel \expandafter is the way to go, but I did not understand the examples enough to get it working for me. Any help?

-

With the help of etoolbox (but only for convenience): just change all \section into #1, but using \csdef and \csuse; the important thing is to refer to arguments of macros defined inside the metamacro by doubling # symbols.

\documentclass{article}
\makeatletter
\RequirePackage{etoolbox}
\RequirePackage{xargs}

\newif\iflongrefs

\newcommand{\extend}[4]{%
\csdef{#1@namelong}{#2}%
\csdef{#1@nameshort}{#3}%
\csdef{#1@prefix}{#4}%
\csletcs{#1@old}{#1}%
\csdef{#1}{\@ifstar{\csuse{#1@star}}{\csuse{#1@nostar}}}%
\expandafter\newcommandx\expandafter*\csname#1@nostar\endcsname[3][1=,3=]{%
\ifx &##1&%
\csuse{#1@old}{##2}%
\else
\csuse{#1@old}[##1]{##2}%
\fi
\ifx &##3&%
\else
\label{\csuse{#1@prefix}:##3}%
\fi
}%
\expandafter\newcommandx\expandafter*\csname#1@star\endcsname[2][2=]{%
\csuse{#1@old}*{##1}%
\ifx &##2&%
\else
\label{\csuse{#1@prefix}:##2}%
\fi
}
\csdef{#1ref}##1{%
\iflongrefs
\csuse{#1@namelong}~\ref{\csuse{#1@prefix}:##1}%
\else
\csuse{#1@nameshort}\,\ref{\csuse{#1@prefix}:##1}%
\fi
}%
}
\makeatother

\extend{section}{Section}{Sect.}{sect}
\extend{subsection}{Subection}{Subsect.}{subsect}

\begin{document}

\section{abc}

\section[aaa]{abc}[def]

\sectionref{def}

{\longrefstrue\sectionref{def}}

\subsection[uuu]{vvv}[www]

\subsectionref{www}

\end{document}


Note that \LetLtxMacro is not necessary, as \section and friends are not defined to have optional arguments.

## Added – xparse version

Instead of xargs you may want to use the modern xparse package:

\RequirePackage{etoolbox}
\RequirePackage[log-declarations = false]{xparse}

\newcommand{\extend}[4]{%
\csdef{#1@namelong}{#2}%
\csdef{#1@nameshort}{#3}%
\csdef{#1@prefix}{#4}%
\csletcs{#1@old}{#1}%
\expandafter\DeclareDocumentCommand\csname#1\endcsname{s o m o}{
\IfBooleanTF{##1}
{\csuse{#1@old}*{##3}
%       \IfNoValueTF{##4}
%         {}
%         {\label{\csuse{#1@prefix}:##4}}
}
{\IfNoValueTF{##2}
{\csuse{#1@old}{##3}}
{\csuse{#1@old}[##2]{##3}}
\IfNoValueTF{##4}
{}
{\label{\csuse{#1@prefix}:##4}}
}
}
\expandafter\DeclareDocumentCommand\csname#1ref\endcsname{m}{
\iflongrefs
\csuse{#1@namelong}~\ref{\csuse{#1@prefix}:##1}
\else
\csuse{#1@nameshort}\,\ref{\csuse{#1@prefix}:##1}
\fi
}%
}


The three commented lines are because it's not clear what's the purpose of a label to a \section* command.

-
Really works like a charm - thank you so much! Btw I kept the lines you commented out as I extended the code to also build \XXXpageref commands which can definitely make sense for unnumbered elements as well. –  DrTH Nov 1 '11 at 5:18