Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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}
share|improve this question
3  
LaTeX2e does not provide a full set of 'programming' tools: there is no global version of \newcommand. That's why programming LaTeX2e requires quite a bit of TeX, and why the LaTeX3 work has focussed on a programming layer. –  Joseph Wright Apr 13 '12 at 6:21

3 Answers 3

up vote 15 down vote accepted

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
share|improve this answer
    
I don't think that works for optional argument forms though, as you need to make both two commands global in that case and only the internal command gets made long with the star or long code. –  David Carlisle Apr 13 '12 at 9:36
    
@DavidCarlisle You're right; I've added a corrected version. –  egreg Apr 13 '12 at 9:59

It's a bit tricky as for optional argument forms you need to make sure that both the top level command (that just applies protection and checks for [) needs to be global and the internal command. this seems to work:

enter image description here

\documentclass{article}

\makeatletter
\def\reset@l@texglobal{\let\l@texglobal\relax}
\reset@l@texglobal
\def\latexglobal{\let\l@texglobal\global}
\long \def \@yargd@f#1#2{%
  \def \reserved@a ##1#1##2##{%
    \expandafter\def\expandafter#2\reserved@b ##1#1%
    }%
  \afterassignment\reset@l@texglobal
  \l@texglobal\l@ngrel@x \reserved@a 0##1##2##3##4##5##6##7##8##9###1%
}

\long\def\@xargdef#1[#2][#3]#4{%
  \@ifdefinable#1{%
      \l@texglobal\expandafter\def\expandafter#1\expandafter{%
          \expandafter
          \@protected@testopt
          \expandafter
          #1%
          \csname\string#1\endcsname
          {#3}}%
       \expandafter\@yargdef
          \csname\string#1\endcsname
           \tw@
           {#2}%
           {#4}}}

\makeatother

\begin{document}

\newcommand\abc{abc}

\begin{center}

\latexglobal
\newcommand\hohum[3][\textbf{hello}]{[#1][#2][#3]}

\hohum{one}{two}

\hohum[aaa]{three}{four}


\latexglobal\renewcommand\abc{xyz}

\abc

\renewcommand\abc{rst}

\abc

\end{center}


\hohum{one}{two}

\hohum[aaa]{three}{four}

\abc

\end{document}
share|improve this answer

I have to admit I didn't follow your code closely, but shouldn't

\renewcommand\SetPropertyAValue[1]{...}
\global\let\SetPropertyAValue\SetPropertyAValue

work?

share|improve this answer
3  
This may have adverse effects on the "save stack" usage: with \def\x{a}{\def\x{b}\global\let\x\x} and \tracingrestores=1 the log file shows {retaining \x=macro:->b} so some space is the save stack is wasted. –  egreg Apr 13 '12 at 9:21
    
I can't quite get this to work. Can you try to delete the \renewcommand and replace the commented line in the MWE with this and see if you can get the last line to be as shown in the question. Sorry about my code not being clear: I want to know what is defined in the external file for one particular macro and ignore everything else in the file. –  Peter Grill Apr 13 '12 at 15:29
    
As well, I think you might get into serious troble if you made the parameter optional. –  yo' Apr 13 '12 at 16:45

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.