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{}

tmgriffiths
  • 493
  • 4
  • 13

2 Answers2

3

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)}%
  }%
}
egreg
  • 1,121,712
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}