5

Considering this definition of a latex macro:

\newcommand\createCMDMANUV[4]{%
  \expandafter\@ifdefinable\csname #3#2\endcsname{%
    \expandafter\xdef\csname #3#2\endcsname##1{%
      \noexpand\vcenteredhbox{%
      \noexpand\includegraphics[width=##1,trim=0 0 1 -1]{BD_CATIA/#4/#1.png}}%
    }%
  }%
}

I try to deal with empty (not optional) parameter. So I tried this definition but it is not working:

\newcommand\createCMDMANUV[4]{%
  \expandafter\@ifdefinable\csname #3#2\endcsname{%
    \expandafter\xdef\csname #3#2\endcsname##1{%
      \noexpand\vcenteredhbox{%
      \ifdefempty{##1}{\def\widthCATIA{3cm}}{\def\widthCATIA{##1}}%
      \includegraphics[width=\widthCATIA,trim=0 0 1 -1]{BD_CATIA/#4/#1.png}}%
    }%
  }%
}

I think it is due to the fact that \widthCATIA is not well defined but what is the right syntax...

I call the command \createCMDMANUV{\tA}{\tB}{\tC}{\tD} where \tA to \tD contains string.

For example if \tC contains AVV and \tB contains test the macro build the command \AVVtest.

MWE (base on the same idea):

\documentclass{standalone}
\RequirePackage{xstring}
\RequirePackage{etoolbox}

\makeatletter
\newcommand\createCMDMANUV[2]{%
  \expandafter\@ifdefinable\csname #1#2\endcsname{%
    \expandafter\xdef\csname #1#2\endcsname##1{%    
      \noexpand\textbf{##1}%
    }%
  }%
}
\makeatother

\begin{document}
\def\tA {AA}
\def\tB {BB}    
\createCMDMANUV{\tA}{\tB}

\AABB{coucou}   
\end{document}

MNWE (Minimal Not Working Example :-) ):

\documentclass{standalone}
\RequirePackage{xstring}
\RequirePackage{etoolbox}

\makeatletter
\newcommand\createCMDMANUV[2]{%
  \expandafter\@ifdefinable\csname #1#2\endcsname{%
    \expandafter\xdef\csname #1#2\endcsname##1{%    
    \ifcsempty{##1}{ \expandafter\xdef\csname ttMANU\endcsname{Ahah}}{ \expandafter\xdef\csname ttMANU\endcsname{ohoh}}%
      \noexpand\textbf{\csname ttMANU\endcsname}%
    }%
  }%
}
\makeatother

\begin{document}
\def\tA {AA}
\def\tB {BB}    
\createCMDMANUV{\tA}{\tB}

\AABB{}    
\AABB{aa}
\end{document}

\ifcsempty seems not doing well the empty test.

SOLUTION of my MNWE:

\documentclass{standalone}
\RequirePackage{xstring}
\RequirePackage{etoolbox}

\makeatletter
\newcommand\createCMDMANUV[2]{%
\ifdefempty{##1}{\def\ttMANU{ahah}}{\def\ttMANU{ohoh}}%
  \expandafter\@ifdefinable\csname #1#2\endcsname{%
    \expandafter\xdef\csname #1#2\endcsname##1{%    
    \noexpand\ifblank{##1}{\def\noexpand\ttMANU{ahah}}{\def\noexpand\ttMANU{##1}}%%
      \noexpand\textbf{\noexpand\ttMANU}%
    }%
  }%
}
\makeatother

\begin{document}    
\def\tA {AA}
\def\tB {BB}    
\createCMDMANUV{\tA}{\tB}

\AABB{}    
\AABB{aa}      
\end{document}
  • \def\widthCATIA{...} is only in the local group if \ifdefempty... Please provide a complete example, not just fragments. And I think, you should rather use \ifcsempty, not \ifdefempty, but it's unclear to me – user31729 Apr 7 '15 at 8:54
  • @ChristianHupfer I edited my post with a MWE. – Guuk Apr 7 '15 at 9:05
  • The real problem is the missing key-value expansion of \widthCATIA, in my point of view – user31729 Apr 7 '15 at 9:16
  • @ChristianHupfer What do you mean by "key-value expansion" ? I want to create the \widthCATIA when I call the final macro. – Guuk Apr 7 '15 at 9:17
  • 1
    I think he means when reading width value it still sees a macro but not its expansion. – percusse Apr 7 '15 at 9:18
5

You are trying to expand \ifdefempty at definition time; but you should use \ifblank;

\newcommand\createCMDMANUV[4]{%
  \expandafter\@ifdefinable\csname #3#2\endcsname{%
    \expandafter\xdef\csname #3#2\endcsname##1{%
      \noexpand\vcenteredhbox{%
      \noexpand\ifblank{##1}{\def\noexpand\widthCATIA{3cm}}{\def\noexpand\widthCATIA{##1}}%
      \noexpand\includegraphics[width=\noexpand\widthCATIA,trim=0 0 1 -1]{BD_CATIA/#4/#1.png}}%
    }%
  }%
}

If I call

\def\tA{AA}\def\tB{test}\def\tC{AVV}\def\tD{DD}

\createCMDMANUV{\tA}{\tB}{\tC}{\tD}

\show\AVVtest

I get the following response:

> \AVVtest=macro:
#1->\vcenteredhbox {\ifblank {#1}{\def \widthCATIA {3cm}}{\def \widthCATIA {#1}
}\includegraphics [width=\widthCATIA ,trim=0 0 1 -1]{BD_CATIA/DD/AA.png}}.

It's easier with expl3:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand\createCMDMANUV { mmmm }
 {
  \guuk_create_cmd_manuv:xxxx { #1 } { #2 } { #3 } { #4 }
 }

\tl_new:N \l__guuk_width_catia_tl

\cs_new_protected:Nn \guuk_create_cmd_manuv:nnnn
 {
  \cs_new_protected:cpn { #3#2 } ##1
   {
    \vcenteredhbox
     {
      \tl_if_empty:nTF { ##1 }
       { \tl_set:Nn \l__guuk_width_catia_tl { 3cm } }
       { \tl_set:Nn \l__guuk_width_catia_tl { ##1 } }
      \includegraphics[width=\l__guuk_width_catia_tl,trim=0 ~ 0 ~ 1 ~ -1]{BD_CATIA/#4/#1.png}
     }
   }
 }

\cs_generate_variant:Nn \guuk_create_cmd_manuv:nnnn { xxxx }
\ExplSyntaxOff
\def\tA{AA}\def\tB{test}\def\tC{AVV}\def\tD{DD}

\createCMDMANUV{\tA}{\tB}{\tC}{\tD}

\show\AVVtest

The response is

> \AVVtest=\protected\long macro:
#1->\vcenteredhbox {\tl_if_empty:nTF {#1}{\tl_set:Nn \l__guuk_width_catia_tl {3
cm}}{\tl_set:Nn \l__guuk_width_catia_tl {#1}}\includegraphics [width=\l__guuk_w
idth_catia_tl ,trim=0 0 1 -1]{BD_CATIA/DD/AA.png}}.

How it works

  1. I define a “user level command” \createCMDMANUV with four arguments. Its task is just to pass the arguments to \guuk_create_cmd_manuv:xxxx

  2. I define the \guuk_create_cmd_manuv:nnnn function; the four n mean that it is a macro with four “normal” arguments.

  3. This function in turn defines a new macro based on the passed arguments; it does \cs_new_protected:cpn which is the analog of \expandafter\def\csname ...\endcsname, but adding the “undefinedness test”, so

    \cs_new_protected:cpn { <tokens> } #1 { ... }
    

    is what you're doing with

    \expandafter\def\csname <tokens>\endcsname##1{...}
    
  4. As requested, the constructed macro has one argument, which is tested for emptyness with \tl_if_blank:nTF that returns the second argument if the argument is blank, the third argument otherwise. This test is the same as etoolbox \ifblank; the code just sets the internal token list to the argument, if not blank or to 3cm

  5. The inner code of the built function is exactly the same as you build with the traditional method, but without any \noexpand

  6. The final trick: with

    \cs_generate_variant:Nn \guuk_create_cmd_manuv:nnnn { xxxx }
    

    we define from the stated function another one named \guuk_create_cmd_manuv:xxxx that, when called, first does full expansion of its four arguments and then passes the expanded arguments as normal arguments to \guuk_create_cmd_manuv:nnnn

  7. Note that in the programming environment, between \ExplSyntaxOn and \ExplSyntaxOff, spaces and blank lines are ignored, so there's no need of worrying about protecting end-of-lines. The only small complication is that wanted spaces must be explicitly inserted with ~ as in the value to the trim key above.

  • Thank you. The expl3 seems complicated for me but I think I will take time for examining it. – Guuk Apr 7 '15 at 10:57
  • @Guuk The expl3 code is pretty much the same, but there are less complications with expansion, because we tell LaTeX precisely what we want to be expanded before being fed to the main macro. – egreg Apr 7 '15 at 11:00
1

I removed my first answer because it seems that your code is overcomplicated (as usually for many users:). First of all, you have to ask why I need to use \xdef instead normal \gdef? I don't see the reason. So, your example can work with \gdef:

\def\createCMDMANUV#1#2#3#4{%
  \expandafter\@ifdefinable\csname #3#2\endcsname{%
    \expandafter\gdef\csname #3#2\endcsname##1{%
      \vcenteredhbox{%
      \includegraphics[width=\widthCATIA{##1},trim=0 0 1 -1]{BD_CATIA/#4/#1.png}}%
    }%
  }%
}
\def\withCATIA#1{\ifx^#1^3cm\else#1\fi}

Edit (in response to the comment about expansions of parameters during declaration). If you need to use expanded parameters in your \declaremacro code, then you can think about the following code:

\def\delcleremacro#1#2#3#4{\edef\tmp{\noexpand\declaremacroA{#1}{#2}{#3}{#4}\tmp}
\def\declaremacroA#1#2#3#4{%
    \expandafter\gdef\csname #3#2\endcsname##1{%
        ... here is my complicated macro, which uses declared
            and {\bf expanded} parameters #1, #2, #3, #4 and one real parameter ##1.
            I need not to use fifty times \noexpand here.
            The test of empty parameter ##1 can be done by
            \ifx^##1^empty\else nonempty\fi or (more robust but nonexpandable)
            \def\tmp{##1}\ifx\tmp\empty \def\tmp{3cm}\else\def\tmp{##1}\fi
            and you can use \tmp in your meaning of \widthCATIA.
            Here is no \noexpand problem.
}}
  • This is why I wrote the MWE and MWNE... The reason of the use of \xdef in place of \gdef is only due to the fact that I use a solution found on the internet without changing this syntax. Thank you for your solution. – Guuk Apr 7 '15 at 12:15
  • The expansion is not needed for #2 and #3, but it is for #1 and #4, because in the given usage example they should depend on the given value at definition time, not at call time. – egreg Apr 7 '15 at 12:40

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.