1

I'm creating a command to generate a series of macros all with equivalent styling. i.e. something along the lines of 1

\newcommand{\newcustommacro}[2]{\newcommand{#1}[1][Default]{#2{##1}}}
\newcustommacro{\macroA}{\textbf}

Now, I want my macro to have Special behavior if optional argument is not passed so I'm using David Carlisle's answer from that question.

However, when that \newcommand method is nested inside another \newcommand then it stops working.

\documentclass{standalone}

\makeatletter
\newcommand{\testA}[1][\@nil]{
  \def\tmp{#1}%
  \ifx\tmp\@nnil%
    No arg: Hello%
  \else
    Yes arg: Bye(#1)%
  \fi
}
\makeatother

\newcommand{\makeamacro}[2]{%
  \makeatletter
  \newcommand{#1}[1][\@nil]{
    \def\tmp{##1}%
    \ifx\tmp\@nnil%
      No arg: Hello%
    \else
      Yes arg: #2(##1)
    \fi
  }
  \makeatother
}

\makeamacro{\testB}{Bye}

\begin{document}

  testA, no arg: \testA

  testA, yes arg: \testA[arg]

  testB, no arg: \testB

  testB, yes arg: \testB[arg]

\end{document}

Output

I doubled the #'s as required for passing arguments to nested newcommands. What do I need to do for the @'s? I'm stumped.

I have no averstion to xparse so if someone suggests a nested verison of egreg's answer to the same question linked above then that'd be ok too.


1: I know the example is just making a macro that is basically just \textbf{}

  • Wrong position of \makeatletter and \makeatother – egreg Nov 26 '17 at 9:56
2

You're placing \makeatletter and \makeatother in the wrong place.

Whey you want to use macros with @ in their name, such as \@nnil, the whole code should be surrounded by \makeatletter and \makeatother:

\documentclass{article}

\makeatletter
\newcommand{\testA}[1][\@nil]{% <--- don't forget
  \def\tmp{#1}%
  \ifx\tmp\@nnil
    No arg: Hello%
  \else
    Yes arg: Bye(#1)%
  \fi
}

\newcommand{\makeamacro}[2]{%
  \newcommand{#1}[1][\@nil]{% <--- don't forget
    \def\tmp{##1}%
    \ifx\tmp\@nnil
      No arg: Hello%
    \else
      Yes arg: #2(##1)
    \fi
  }
}
\makeatother

\makeamacro{\testB}{Bye}

\begin{document}

  testA, no arg: \testA

  testA, yes arg: \testA[arg]

  testB, no arg: \testB

  testB, yes arg: \testB[arg]

\end{document}

enter image description here

This said, xparse is easier under this respect:

\usepackage{xparse}

\NewDocumentCommand{\testA}{o}{%
  \IfNoValueTF{#1}
    {No arg: Hello}%
    {Yes arg: Bye(#1)}%
}

\NewDocumentCommand{\makeamacro}{mm}{%
  \NewDocumentCommand{#1}{o}{%
    \IfNoValueTF{##1}
      {No arg: Hello}%
      {Yes arg: #2(##1)}%
  }%
}
  • That was easy to fix. – tmgriffiths Nov 26 '17 at 22:54
  • @tmgriffiths The concept of category codes is not so easy to grasp, but once one gets the hang of it, it becomes almost routine. ;-) – egreg Nov 26 '17 at 22:55
0

Do you search for something like that? (xparse)

\documentclass{article}
\usepackage{xparse}

\NewDocumentCommand{\testA}{o D(){Bye}}{
  \IfNoValueTF {#1}
    {No arg: Hello}
    {Yes arg: #2(#1)}
}

\begin{document}

  testA, no arg: \testA 

  testA, yes arg: \testA[arg]

  testA, yes arg: \testA[arg](notbye)

\end{document}

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.