7

I have to gather, in a single source file, source files from several authors, each of them with its own (many) \newcommand, \newtheorem, etc. I'd like to limit the scope of each of these customizations, in the spirit of Limit macro/newcommand scope to section. The egreg's nice solution with \onlysectioncommands{...,...,...} has in my case the drawback that these \newcommand, \newtheorem, etc. may each time be numerous.

Hence, if each customization set is put in an auxiliary file, say ⟨author⟩-customization.tex, I'm looking for a clever \cleancustomization macro that lets me able to do something like:

...
%
\input{author1-customization}
\input{author1-source}
\cleancustomization{author1-customization}
%
\input{author2-customization}
\input{author2-source}
\cleancustomization{author2-customization}
%
\input{author3-customization}
\input{author3-source}
\cleancustomization{author3-customization}
%
...

In other words, \cleancustomization should be given a fixed list of customization macros (\newcommand, \newtheorem, etc.), and then be able to parse the file given in argument and automatically \undefine all the commands, theorems, etc. defined inside this file.

Do you see a (LaTeX3) way for doing this?

1
  • 1
    You could patch \newcommand, \newtheorem etc... so that they add the macros names in a list similar to egreg's \sectioncommandslist, then \cleancustomization would process it. Jan 15, 2015 at 8:55

2 Answers 2

6

You can use something like this:

\documentclass{article}
\usepackage{etoolbox}

\makeatletter
\newcommand*{\saved@ifdefinable}{}
\newcommand*{\saved@rc@ifdefinable}{}
\newcommand{\startcustomization}{
    \def\@renewedcommands{}
    \def\@newedcommands{}
    \let\saved@ifdefinable\@ifdefinable
    \let\saved@rc@ifdefinable\@rc@ifdefinable
    \newcommand{\@saveforrestore}[1]{%
        \ifinlist{##1}{\@renewedcommands}{}{%
            \listadd\@renewedcommands##1%
            \expandafter\let\csname saved@\string##1\endcsname##1%
    }}
    \renewcommand{\@ifdefinable}[2]{%
        \listadd\@newedcommands##1%
        \saved@ifdefinable{##1}{##2}%
    }
    \let\@@ifdefinable\@ifdefinable
    \renewcommand{\@rc@ifdefinable}[2]{%
        \@saveforrestore##1%
        \saved@rc@ifdefinable{##1}{##2}%
    }
}
\newcommand{\cleancustomization}{%
    \newcommand{\saved@restore}[1]{\expandafter\let\expandafter##1\csname saved@\string##1\endcsname}%
    \forlistloop{\saved@restore}{\@renewedcommands}%
    \forlistloop{\undef}{\@newedcommands}%

    \let\@ifdefinable\saved@ifdefinable%
    \let\@rc@ifdefinable\saved@@ifdefinable%
}
\makeatother

\begin{document}

\startcustomization
    \newcommand*{\blipo}{Jill}
    \renewcommand\emph[1]{\textbf{#1}}
    Hello \blipo{}. \blipo{} is \emph{blonde}
\cleancustomization

Not defined here. \emph{Attempt} to use it--- ``generates'' error.
\end{document}

I defined two commands \startcustomization and \cleancustomization so that every command defined between the two will be undefined after \cleancustomization. I patched \@ifdefinable, as mentionned in this TeX.SE answer.

EDIT: Patching \@rc@ifdefinable, you can save the original macros when \renewcommand is used (in this code I save it in \saved@\macro, after checking that the macro isn't saved yet). This way, it is possible to restore the commands when \cleancustomization is used.

2
  • In order to insure this clever answer works in case of personal \renewcommands, it is sufficient (necessary?) to patch \@@ifdefinable exactly in the same way \@ifdefinable is. Jan 15, 2015 at 18:04
  • 1
    @DenisBitouzé See my updated answer. The code is not so clean, but I hope it will help you. Jan 20, 2015 at 10:11
2

May be too late but i find that we can do this with just grouping

\begingroup
\input{author1-customization}
\input{author1-source}
\endgroup
%
\begingroup
\input{author2-customization}
\input{author2-source}
\endgroup
%
\begingroup
\input{author3-customization}
\input{author3-source}
\endgroup
2
  • Surprisingly (at least for me), grouping is OK for \newcommand: \newcommand{\foo}{bar} in a first group doesn't conflict with \newcommand{\foo}{baz} in a subsequent group. But, unfortunately, this doesn't work for instance for \newtheorem: \newtheorem{theo}{Bar} in a first group conflicts with \newtheorem{theo}{Baz} in a subsequent group. And this is strange: though \foo was already defined and could be defined again, here the error message tells: ! LaTeX Error: Command \theo already defined. Feb 18, 2015 at 13:57
  • 1
    @DenisBitouzé Ok. \newtheorem use internally \global\@namedef{#1} and \global\@namedef{end#1} soo grouping does not work
    – touhami
    Feb 18, 2015 at 15:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .