4

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.

See Macro factory and argument passed at calling for the whole context.

Following the answers on question the previous question (Macro factory and argument passed at calling ) , I could make a new MWE with some points still opened :

  • point 1 : I put comas in the \clist_map_inline to artificially delimit each argument
  • point 2 : I put the list of the argument in the definition (the 3 m) : \NewDocumentCommand{\DefinitionVariables}{ m m m }%
  • point 3 : I put all the arguments in the \clist_map_inline function : \clist_map_inline:nn { #1, #2, #3}%

So the questions following these changes are :

  • point 1 : How can I, not have to put a comas ? I guess it has to do with the \clist_map_inline function, with coma being a built-in delimiter. It raises an issue when there is a coma inside an argument as the function will cut it as it considers it's a delimiter. I was thinking of having kind of a \foreach argument in {all the arguments}. Does such a thing exist ?
  • point 2 : How can I make this m dynamic ? By dynamic, I mean : sometimes, the function can take 3 arguments, but sometimes it can be 7 or 9 (between 1 and 9). Something like numberOfArgument * m
  • point 3 : It's related to the previous point, how can I also make this dynamic and not hard-coded ? (the \foreach argument in {all the arguments} would solve it).

    \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
    %==================================================================================
    
    \iffalse
    \fi
    \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 5  : utilise la syntaxe expl3
    \iftrue
    %\iffalse
    
    \ExplSyntaxOn
    \NewDocumentCommand{\DefinitionVariables}{ m m m }%     <=== point 2 : there is as much 'm' as there is arguments
     {
      \int_zero:N \l_tmpa_int
      %\clist_map_inline:nn { #1 }
      \clist_map_inline:nn { #1, #2, #3}%         <=== point 3 : allows not to put comas in the arguments, but rise the pb if there is comas inside the argument // 
       {
        \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
    
    \DefinitionVariables{Laetitia, 8 }{Pierre, 10}{Cedric}%        <=== point 1 : coma inside the argument will be considered as a delimiter, so the mapping of variable will be wrong
    La variable 2 est : \variableII  \\  FIN\\
    La variable 1 est : \variableI  \\  FIN\\
    La variable 3 est : \variableIII  \\  FIN\\
    La variable 1 est : \variableI  \\  FIN\\
    \fi
    

Any help is very appreciate !

  • I'm not sure what the expansion of \variableI should be. Should it be “Laetitia, 8”? – egreg Apr 29 '17 at 14:05
  • Yes, it should be the parameter passed. @egreg : I don't get why you are reformulating the call of \DefinitionVariables. The syntax is \DefinitionVariables{arg1}..{argX}..{argN} with X = 1 to X = N (N is 9 at max). Is this a latex rule ? – Aline Apr 29 '17 at 14:34
  • With passing a comma separated list (or anyhow delimited) you can override the limit of nine arguments. – egreg Apr 29 '17 at 14:41
  • Ah ok. Nice, but I still need to pass the arguments with the syntax of each argument being a real argument. I tried to put }{ as a delimiter, but an error is occuring. – Aline Apr 29 '17 at 14:54
  • Why should it be necessary to use the {...}{...} syntax? This limits you to nine arguments. – egreg Apr 29 '17 at 14:57
4

A development version of the previous code; the new \DefinitionVariables accepts two optional arguments, the fixed name and the delimiter; the latter is (almost) completely arbitrary, just choose a character (or combination thereof) that doesn't appear in the values you want to give the variables.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\DefinitionVariables}{O{variable}mO{,}}
 {
  \aline_df:nnn { #1 } { #2 } { #3 }
 }

\int_new:N \l_aline_df_int
\seq_new:N \l_aline_df_values_seq

\cs_new_protected:Nn \aline_df:nnn
 {
  \int_zero:N \l_aline_df_int
  \seq_set_split:Nnn \l_aline_df_values_seq { #3 } { #2 }
  \seq_map_inline:Nn \l_aline_df_values_seq
   {
    \int_incr:N \l_aline_df_int
    \tl_clear_new:c { #1 \int_to_Roman:n { \l_aline_df_int } } 
    \tl_set:cn { #1 \int_to_Roman:n { \l_aline_df_int } } { ##1 }
   }
 }
\ExplSyntaxOff

\begin{document}

\DefinitionVariables{
  Laetitia, 8; Patrick, 10; Cedric
}[;]

\noindent
La variable 1 est : \variableI\\
La variable 2 est : \variableII\\
La variable 3 est : \variableIII\\
FIN

\bigskip

\DefinitionVariables[var]{A,B,C}

\noindent
La var 1 est : \varI\\
La var 2 est : \varII\\
La var 3 est : \varIII\\
FIN

\end{document}

enter image description here

A different routine based on a recursion for allowing the arguments to be delimited by braces. So long as an open brace follows, a new variable is defined.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\DefinitionVariables}{O{variable}}
 {% pass control to an inner function
  % #1 is the "name part", default "variable"
  \aline_df:n { #1 }
 }

% define an integer variable
\int_new:N \l_aline_df_int

\cs_new_protected:Nn \aline_df:n
 {
  % the integer variable assigns the trailing roman number
  \int_zero:N \l_aline_df_int
  % start the recursion
  \__aline_df_peek:n { #1 }
 }
\cs_new_protected:Nn \__aline_df_peek:n
 {
  % check whether the next token is { (ignoring spaces)
  \peek_catcode_ignore_spaces:NT \c_group_begin_token
   {
    % if it is, increment the counter and call
    % \__aline_df_next:nn { #1 } { #2 }, where
    % { #2 } is the next braced group
    \int_incr:N \l_aline_df_int
    \__aline_df_next:nn { #1 }
   }
 }
\cs_new_protected:Nn \__aline_df_next:nn
 {
  % if the variable is already defined, clear it
  % otherwise create it
  \tl_clear_new:c { #1 \int_to_Roman:n { \l_aline_df_int } }
  % set the variable
  \tl_set:cn { #1 \int_to_Roman:n { \l_aline_df_int } } { #2 }
  % restart the recursion
  \__aline_df_peek:n { #1 }
 }
\ExplSyntaxOff

\begin{document}

\DefinitionVariables{Laetitia, 8}{Patrick, 10}{Cedric}

\noindent
La variable 1 est : \variableI\\
La variable 2 est : \variableII\\
La variable 3 est : \variableIII\\
FIN

\bigskip

\DefinitionVariables[var]{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}

\noindent
La var 1 est : \varI\\
La var 2 est : \varII\\
La var 3 est : \varIII\\
La var 11 est : \varXI\\
FIN

\end{document}

enter image description here

  • Thx for the answer, this is definitely addressing point 2 and 3. – Aline Apr 29 '17 at 14:56
  • Fantastic !!! This is exactly what I needed ! I will put myself into expl3 and study it a bit more. Thx a lot @egreg for this answer and all the back and forth. – Aline Apr 29 '17 at 16:18
  • @Aline I added some comments to the code – egreg Apr 29 '17 at 16:25

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.