13

I'm trying to build my own cookbook-style, which has an ingredient makro. Sometimes the ingredients should be separated and have a headline, so I tried with an optional argument. A minimum example looks like this:

\documentclass{scrartcl}
\newcommand{\ingredient}[3][]{
    #1 #2 & #3 \\
}
\begin{document}
    \begin{tabular}{r|l}        
        \ingredient[\multicolumn{2}{l}{Head} \\]{test1}{test2}
        \ingredient[test3]{test4}{test5}
        \ingredient{test6}{test7}
    \end{tabular}
\end{document}

What's wrong with this code? I get the following error message:

! Misplaced \omit.
\multispan ->\omit 
                   \@multispan 
l.7 ...[\multicolumn{2}{l}{Head} \\]{test1}{test2}
user202729
  • 7,143
causa prima
  • 359
  • 3
  • 10

3 Answers3

16

Tabular material is really picky about what is allowed to go "before" a line. In particular, it has to be fully expandable.

Hence, even the assignment which \ingredient needs to do to check for its optional argument is enough to start the line, and then \multicolumn is no longer allowed to appear.

The easiest way to remedy this is to make the first argument of \ingredient mandatory:

\documentclass{scrartcl}
\newcommand{\ingredient}[3]{
    #1 #2 & #3 \\
}
\begin{document}
    \begin{tabular}{r|l}        
        \ingredient{\multicolumn{2}{l}{Head} \\}{test1}{test2}
        \ingredient{test3}{test4}{test5}
        \ingredient{}{test6}{test7}
    \end{tabular}
\end{document}
David Carlisle
  • 757,742
  • Thank you for a working example, but as this "headline" is really seldomly used it would be much more convenient to have it as an optional parameter. Is there no way to make it work as an optional parameter? Ideally I could also get rid of the "\multicolum{2}{1}{VARIABLE} \"-stuff. – causa prima Aug 31 '12 at 21:34
  • 1
    Nope. You could make two commands, one with two and one with three arguments. – Stephan Lehmke Aug 31 '12 at 21:36
  • Thank you. I found a solution by adding a new command just like you proposed. – causa prima Aug 31 '12 at 21:48
10

You can retain your original syntax and have a single macro with an optional parameter if you use \DeclareExpandableDocumentCommand from the xparse package.

Code:

\documentclass{scrartcl}
\usepackage{xparse}

\DeclareExpandableDocumentCommand{\ingredient}{O{} m m}{% #1 #2 & #3 \% }%

\begin{document} \begin{tabular}{r|l}
\ingredient[\multicolumn{2}{l}{Head} \]{test1}{test2} \ingredient[test3]{test4}{test5} \ingredient{test6}{test7} \end{tabular} \end{document}

user202729
  • 7,143
Peter Grill
  • 223,288
0

You can "creatively" use noalign to implement the functionality. In the following code, I define a function \NewDocumentCommandOptionalInTabular that works similar to that of \NewDocumentCommand except that you can use optional argument (or star) as you want.

\documentclass{scrartcl}

% ======== copy paste this part ======== \ExplSyntaxOn \cs_new_protected:Npn \NewDocumentCommandOptionalInTabular #1 #2 #3 { \NewDocumentCommandOptionalInTabular_aux:xnnn {\exp_not:c{\cs_to_str:N #1-aux}} #1 {#2} {#3} }

\cs_new_protected:Npn \NewDocumentCommandOptionalInTabular_aux:nnnn #1 #2 #3 #4 { \cs_new:Npn #2 { \noalign \bgroup #1 } \NewDocumentCommand #1 {#3} { \egroup #4 } } \cs_generate_variant:Nn \NewDocumentCommandOptionalInTabular_aux:nnnn {x} \ExplSyntaxOff % ======== end ========

% then you can just use \NewDocumentCommandOptionalInTabular to replace \NewDocumentCommand \NewDocumentCommandOptionalInTabular \ingredient {O{} m m}{ #1 #2 & #3 \ }

\begin{document} \begin{tabular}{r|l}
\ingredient[\multicolumn{2}{l}{Head} \]{test1}{test2} \ingredient[test3]{test4}{test5} \ingredient{test6}{test7} \end{tabular} \end{document}

Inspired by egreg's answer.

user202729
  • 7,143