8

I am making a factory macro (A) that produces another macro (B). Macro B consists in affecting what it gets as parameters to variables when called. I am currently able to do all this without A, but this is not scalable, because it requires a lot of rewritting.

I guess that what I am missing here is the reference to an argument that must be expanded during the calling of B. I tried to use multiple # because this seems to be nested arguments, but I feel like this is not what I need.

The point I am struggling with is : "#1 (to point to the first argument within the function calling self function (ie \variable1))" should be replaced by "Laetitia", because it's the first argument of the macro B.

You will find in the MWE :

  • automation trial 1 : I tried without xparse
  • automation trial 2 : with xparse
  • the handmade code of what I want to achieve.

All 3 can be executed, one at the time, by switching the \iffalse/\iftrue instruction in the beginning.

Any pointer would be helpful!

\documentclass[twoside]{article}
% package pour utiliser une macro nested ac ses propres args
\usepackage{xparse}
\errorcontextlines32
\begin{document}
%==================================================================================
%     Prerequisite : lines of code to define variableI to variableXVI
%==================================================================================
\newcommand{\DefinitVariable}[1]{%
    \expandafter\newcommand\csname variable\Roman{#1}\endcsname{}%
    }%
%    Loop for defining all the variable
\newcounter{ctr}
\loop
    \stepcounter{ctr}
    \expandafter\DefinitVariable{ctr}%
\ifnum\thectr<16
\repeat

%==================================================================================
% Automation trial 1 :
%\iftrue
\iffalse
\newcommand\DeuxiemeAffecteVariable[1]{%%
    \setcounter{ctr}{1}%
    \expandafter\renewcommand\csname variable\Roman{ctr}\endcsname{\#1 (to point to the first argument within the function calling self function (ie \textbackslash variable1))}%
}

\newcommand\definecommand[1]{%%
  \expandafter\def\csname#1\endcsname{%
    \setcounter{ctr}{1}%
    \expandafter\DeuxiemeAffecteVariable{\arabic{ctr}}%
    }%%
}%


\definecommand{DefinitionVariablesN}%
\DefinitionVariablesN{Laetitia}%
La variable 1 est : \variableI  \\  FIN\\
\fi
%==================================================================================
% Automation trial 2 with xparse :
\iftrue
%\iffalse
\newcounter{cpteurLocal}
\NewDocumentCommand{\AffecteVariable}{m}
    {%
    \setcounter{cpteurLocal}{#1}%
    \expandafter\RenewDocumentCommand\csname variable\Roman{cpteurLocal}\endcsname {m}%
    {\#1 (to point to the first argument within the function calling self function (ie \textbackslash variable1))}%
    %{m}%
    %{##1}%
    %{########1}%
    %{contenu vraiable}%
    }%

% Macro factory (A)
\newcommand{\DefinitFonctionDeDefinition}[1]{%
    \expandafter\newcommand\csname DefinitionVariablesN\endcsname{%
            \expandafter\AffecteVariable{#1}%
            %\expandafter\expandafter\AffecteVariable{#1}%
            %\AffecteVariable{#1}%
        }%
    }

\setcounter{ctr}{1}%
\DefinitFonctionDeDefinition{\arabic{ctr}}%
\DefinitionVariablesN{Laetitia}

La variable 1 est : \variableI  \\  FIN\\
\fi

%==================================================================================

% Goal to reach, but this is 'handmade' (not scalable) :

\iffalse
%\iftrue
\newcommand{\DefinitionVariablesI}[9]{
    \renewcommand{\variableI}{#1}
    \renewcommand{\variableII}{#2}
    \renewcommand{\variableIII}{#3}
    \renewcommand{\variableIV}{#4}
    \renewcommand{\variableV}{#5}
    \renewcommand{\variableVI}{#6}
    \renewcommand{\variableVII}{#7}
    \renewcommand{\variableVIII}{#8}
    \renewcommand{\variableIX}{#9}
    }
\newcommand{\DefinitionVariablesII}[7]{
    \renewcommand{\variableX}{#1}
    \renewcommand{\variableXI}{#2}
    \renewcommand{\variableXII}{#3}
    \renewcommand{\variableXIII}{#4}
    \renewcommand{\variableXIV}{#5}
    \renewcommand{\variableXV}{#6}
    \renewcommand{\variableXVI}{#7}
    }

\DefinitionVariablesI{Laetitia}{Patrick}{Marie}{Michel}{Dieter}{Sammy}{Barbara}{Donna}{Ivan}
\DefinitionVariablesII{Pierre}{Rene}{Frederic}{Ousmam}{Paul}{Virginie}{Gerard}

La variable 1 est : \variableI\\
La variable 2 est : \variableII\\
La variable 3 est : \variableIII\\
La variable 4 est : \variableIV\\
La variable 5 est : \variableV\\
La variable 10 est : \variableX\\
La variable 11 est : \variableXI\\
La variable 12 est : \variableXII\\
La variable 13 est : \variableXIII\\
La variable 14 est : \variableXIV\\
FIN
\fi
\end{document}

====================================================================== Definitely making progress thx to @egreg answer.

Follow-up on Macro factory and argument passed at calling (part 2)

  • Thx for editing, it is indeed my first question here. I only have been a reader up to now. – Aline Apr 29 '17 at 10:01
  • Welcome to TeX.SE! Just for info: when you want to ping another user who commented your post, you have to put @ followed by the nickname, for example @clemens. Otherwise, he/she won't be notified. – CarLaTeX Apr 29 '17 at 10:23
  • @Aline Please, don't modify questions so as to invalidate existing answers. Ask a followup question instead. – egreg Apr 29 '17 at 13:28
6

You can use some more advanced expl3 tools:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\DefinitionVariables}{m}
 {
  \int_zero:N \l_tmpa_int
  \clist_map_inline:nn { #1 }
   {
    \int_incr:N \l_tmpa_int
    \tl_clear_new:c { variable \int_to_Roman:n { \l_tmpa_int } } 
    \tl_set:cn { variable \int_to_Roman:n { \l_tmpa_int } } { ##1 }
   }
 }
\ExplSyntaxOff

\begin{document}

\DefinitionVariables{
  Laetitia,Patrick,Marie,Michel,Dieter,Sammy,Barbara,Donna,Ivan,
  Pierre,Rene,Frederic,Ousmam,Paul,Virginie,Gerard
}

\noindent
La variable 1 est : \variableI\\
La variable 2 est : \variableII\\
La variable 3 est : \variableIII\\
La variable 4 est : \variableIV\\
La variable 5 est : \variableV\\
La variable 10 est : \variableX\\
La variable 11 est : \variableXI\\
La variable 12 est : \variableXII\\
La variable 13 est : \variableXIII\\
La variable 14 est : \variableXIV\\
FIN

\end{document}

enter image description here

Here's a “classical” version:

\documentclass{article}

\makeatletter
\newcommand{\DefinitionVariables}[1]{%
  \count@=\z@
  \@for\next:={#1}\do{%
    \advance\count@\@ne
    \expandafter\newcommand\csname variable\@Roman\count@\expandafter\endcsname\expandafter{\next}% !!
  }%
}
\makeatother

\begin{document}

\DefinitionVariables{%
  Laetitia,Patrick,Marie,Michel,Dieter,Sammy,Barbara,Donna,Ivan,%
  Pierre,Rene,Frederic,Ousmam,Paul,Virginie,Gerard%
}

\noindent
La variable 1 est : \variableI\\
La variable 2 est : \variableII\\
La variable 3 est : \variableIII\\
La variable 4 est : \variableIV\\
La variable 5 est : \variableV\\
La variable 10 est : \variableX\\
La variable 11 est : \variableXI\\
La variable 12 est : \variableXII\\
La variable 13 est : \variableXIII\\
La variable 14 est : \variableXIV\\
FIN

\end{document}

To be on the safe side, it would be better using

\uppercase\expandafter{%
  \expandafter\def\expandafter\df@temp\expandafter{%
    \romannumeral\count@
  }%
}%
\expandafter\newcommand\csname variable\df@temp\expandafter\endcsname
  \expandafter{\next}%

instead of the line marked as !!, because some babel modules redefine \@Roman in non expandable ways.

Note, however, that line ends need to be protected in the argument to \DefineVariables. This is not required in the expl3 version, because \clist_map_inline:nn ignores spaces around the comma delimiters.

  • Thanks @egreg, I will study the package expl3. I was kind of avoiding it as it seems to be kind of non-latex/experimental. The issue with your answer is that I cannot change the calling of the macro. In the MWE, it's first names, but it could be "name, family name, birth date", so with some comas. – Aline Apr 29 '17 at 10:30
  • @Aline I'll add a “classical” version. – egreg Apr 29 '17 at 10:45
4

You can use some advanced TeX primitive tools:

\newcount\varnum
\def\DefinitionVariables#1{\varnum=0 \defvarA#1,\end,}
\def\defvarA#1#2,{%
   \ifx\end#1\else
      \advance\varnum by1
      \uppercase\expandafter
         {\expandafter\def\expandafter\tmp\expandafter{\romannumeral\varnum}}%
      \expandafter\def\csname variable\tmp\endcsname{#1#2}%
      \expandafter\defvarA\fi
}

\DefinitionVariables{
  Laetitia,Patrick,Marie,Michel,Dieter,Sammy,Barbara,Donna,Ivan,
  Pierre,Rene,Frederic,Ousmam,Paul,Virginie,Gerard
}

La variable 1 est : \variableI\\
La variable 2 est : \variableII\\
La variable 3 est : \variableIII\\
La variable 4 est : \variableIV\\
La variable 5 est : \variableV\\
La variable 10 est : \variableX\\
La variable 11 est : \variableXI\\
La variable 12 est : \variableXII\\
La variable 13 est : \variableXIII\\
La variable 14 est : \variableXIV\\

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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