[Tex/LaTex] \global\renewcommand equivalent of \global\def

groupingmacros

The following MWE works just fine, but I had to resort to using \global\def (not that there's anything wrong with it). The intent of the MWE is to provide access to the value of macro as set in an external file, but don't want it to effect the current values that have been set in the parent file via the same macro.

I would like to know how to replace the

\global\def\ExternalPropertyAValue{#1}

with something more LaTeXish as in:

\global\renewcomand{\ExternalPropertyAValue}{#1}

which compiles, but does not yield the proper result. Only need to look at last line in output which should be:

enter image description here

Code:

\documentclass{article}
\usepackage{parskip}% formatting only (no issues here)

\usepackage{filecontents}
\begin{filecontents*}{foo.tex}
  \SetPropertyAValue{FoobarA}
\end{filecontents*}

\newbox{\MyBox}

\newcommand{\GetPropertyAValue}{No Value}%
\newcommand{\ExternalPropertyAValue}{No Value}%

\newcommand{\SetPropertyAValue}[1]{\renewcommand{\GetPropertyAValue}{#1}}%

\begin{document}
\section{This works just fine}
\verb|\GetPropertyAValue|=\GetPropertyAValue

\SetPropertyAValue{BarA}
\verb|\GetPropertyAValue|=\GetPropertyAValue

\section{How get the setting PropertyA but not effect PropertyAValue }
\verb|\GetPropertyAValue|=\GetPropertyAValue (should be \verb|BarA|)\par
\verb|\ExternalPropertyAValue|=\ExternalPropertyAValue (should be \verb|No Value|)\par

\global\sbox{\MyBox}{%
    \renewcommand{\SetPropertyAValue}[1]{\global\def\ExternalPropertyAValue{#1}}
    % How do I replace the above line with something like:
    %\renewcommand{\SetPropertyAValue}[1]{\global\renewcomand{\ExternalPropertyAValue}{#1}}
    \input{foo.tex}%
}
\verb|\GetPropertyAValue|=\GetPropertyAValue (should be \verb|BarA|)\par
\verb|\ExternalPropertyAValue|=\ExternalPropertyAValue (should be \verb|FoobarA|)\par
\end{document}

Best Answer

Simple version

Just hook on the (complicated) definition of \renewcommand:

\makeatletter
\def\gnewcommand{\g@star@or@long\new@command}
\def\grenewcommand{\g@star@or@long\renew@command}
\def\g@star@or@long#1{% 
  \@ifstar{\let\l@ngrel@x\global#1}{\def\l@ngrel@x{\long\global}#1}}
\makeatother

Now \grenewcommand will have the same syntax as \renewcommand, but its action will be global. The first line after \makeatother defines also a global version of \newcommand.

CAUTION: As David comments, this won't work with commands defined with optional arguments: so \grenewcommand{\foo}[1][bar]{#1} will not work.


Full version

Here's a version that should work fully

\usepackage{etoolbox}
\makeatletter
\def\gnewcommand{\g@star@or@long\gnew@command}
\def\grenewcommand{\g@star@or@long\grenew@command}
\def\g@star@or@long#1{% 
  \@ifstar{\let\l@ngrel@x\global#1}{\def\l@ngrel@x{\long\global}#1}}
\def\gnew@command#1{\@testopt{\@gnewcommand#1}0}
\def\@gnewcommand#1[#2]{%
  \kernel@ifnextchar [{\@gxargdef#1[#2]}%
                {\@argdef#1[#2]}}
\let\@gxargdef\@xargdef
\patchcmd{\@gxargdef}{\def}{\gdef}{}{}
\let\grenew@command\renew@command
\patchcmd{\grenew@command}{\new@command}{\gnew@command}{}{}
\makeatother