Optional parameters for NewDocumentCommand with if cases

expl3macrosoptional arguments

I have this command, which I would like to take two optional parameters: \pubtitle[title][symbol]{custom}.

Here is the command (MWE):

\documentclass{article}

\usepackage{xcolor}
\usepackage{fontawesome}

\definecolor{icons}{HTML}{46A247}

\ExplSyntaxOn

\cs_new_protected:Nn \pubtitle_symbolheading:nn
 {
  \group_begin:
  {\large\textcolor{icons}{#1}\hspace{10pt}\textbf{#2}}
  \group_end:
 }

\NewDocumentCommand{\pubtitle}{m}
 {
  \pubtitle_pubtitle:n { #1 }
 }

\cs_new_protected:Nn \pubtitle_pubtitle:n
 {
  \str_case:nnF { #1 }
   {
    {book}{\pubtitle_symbolheading:nn{\faBook}{Book}}
    {article}{\pubtitle_symbolheading:nn{\faFileText}{Article}}
    % other cases
   }
   {% none of the above
    \PackageError{pubtitle}
     {
      Unsupported ~ entry ~ field ~ '#1' ~ \MessageBreak for bibliography}
     {
      Perhaps ~ you ~ meant ~ '\string\pubtitle{custom}'
     }
   }
 }

\ExplSyntaxOff

\begin{document}

\pubtitle{book}

\pubtitle{article}

\pubtitle{invalidArgument}

\end{document}

This returns an error for an "unsupported" mandatory parameter. What I would like is to be able to provide two optional parameters (one for each in the \pubtitle_symbolheading:nn command) when the mandatory parameter custom is given. The output of MWE is:

enter image description here

What I want is to be able to change the bold text and symbol in the output with optional parameters (but only if custom is given as the mandatory parameter).

I would like to be able to change the title without the symbol, i.e. \pubtitle[title]{custom}.

Best Answer

The following provides two internally identical solutions with a different document interface. The first, called \pubtitle uses two optional arguments followed by a mandatory one. The second, called \Pubtitle uses the interface you showed in your question with a single optional argument in which the two things are split by a comma.

Also, the third argument will be normalised by \str_foldcase:n.

\documentclass{article}

\usepackage{xcolor}
\usepackage{fontawesome}

\definecolor{icons}{HTML}{46A247}

\ExplSyntaxOn
\msg_new:nnn { pubtitle } { extraneous-optional }
  {
    \exp_not:N \pubtitle
    only~ accepts~ optional~ arguments~ if~ you~ use~ `custom'~ as~ a~
    mandatory~ argument.
  }
\msg_new:nnn { pubtitle } { missing-optional }
  {
    \exp_not:N \pubtitle
    requires~ two~ optional~ arguments~ if~ you~ use~ `custom'~ as~ a~
    mandatory~ argument.
  }
\msg_new:nnnn { pubtitle } { unsupported-argument }
  { Unsupported~ entry~ field~ `#1'~ for~ bibliography. }
  { Perhaps~ you~ meant~ `\token_to_str:N \pubtitle[<icon>][<text>]{custom}'. }

% document interfaces
\NewDocumentCommand \pubtitle { o o m }
  { \pubtitle_pubtitle:nne {#1} {#2} { \str_foldcase:n {#3} } }
\NewDocumentCommand \Pubtitle { >{\SplitArgument{1}{,}}o m }
  {
    % design decision of ltcmd: unused o-args are not processed by argument
    % processors, so we need to add this processing here
    \IfNoValueTF {#1}
      { \pubtitle_pubtitle:nne {#1} {#1} }
      { \pubtitle_pubtitle:nne #1 }
        { \str_foldcase:n {#2} }
  }

% internal code
\cs_new_protected:Npn \pubtitle_pubtitle:nnn #1#2#3
  {
    \str_case:nnTF {#3}
      {
        { book }    { \pubtitle_symbolheading:nn \faBook     { Book } }
        { article } { \pubtitle_symbolheading:nn \faFileText { Article } }
      }
      {
        \bool_lazy_and:nnF
          { \tl_if_novalue_p:n {#1} }
          { \tl_if_novalue_p:n {#2} }
          { \msg_error:nn { pubtitle } { extraneous-optional } }
      }
      {
        \str_if_eq:nnTF {#3} { custom }
          {
            \bool_lazy_or:nnTF
              { \tl_if_novalue_p:n {#1} }
              { \tl_if_novalue_p:n {#2} }
              { \msg_error:nn { pubtitle } { missing-optional } }
              { \pubtitle_symbolheading:nn {#1} {#2} }
          }
          { \msg_error:nnn { pubtitle } { unsupported-argument } {#3} }
      }
  }
\cs_generate_variant:Nn \pubtitle_pubtitle:nnn { nne }
\cs_new_protected:Npn \pubtitle_symbolheading:nn #1#2
  {
    \group_begin:
      \large
      \textcolor { icons } {#1}
      \skip_horizontal:n { 10pt }
      \textbf {#2}
    \group_end:
  }

% just for tests
\NewDocumentCommand \showtest { v }
  {
    \noindent\texttt{#1}:\\
    \tl_rescan:nn {} {#1}
    \par
    \medskip
  }
\ExplSyntaxOff

\begin{document}
\section{Interface \texttt{\protect\string\pubtitle}}
\showtest{\pubtitle{book}}
\showtest{\pubtitle{ArTiClE}}
\showtest{\pubtitle[\faBeer][Beer]{custom}} % thanks Ulrich for the beer

% error cases
%\pubtitle{invalidArgument} % throws an error
%\pubtitle[\faBook]{article} % throws an error
%\pubtitle[\faBook]{custom} % throws an error

\section{Interface \texttt{\protect\string\Pubtitle}}
\showtest{\Pubtitle{book}}
\showtest{\Pubtitle{ArTiClE}}
\showtest{\Pubtitle[\faBeer,Beer]{custom}} % thanks Ulrich for the beer

%\Pubtitle{invalidArgument} % throws an error
%\Pubtitle[\faBook]{article} % throws an error
%\Pubtitle[\faBook]{custom} % throws an error
%\Pubtitle[\faBeer,Beer, and more]{custom} % throws an error
\end{document}

enter image description here


The following uses default values for the title and icon if custom was used. If you specify both optional arguments (or in the variant with a comma the variant with a separation) then the first will be the title and the second the icon. If you specify only one optional argument, if that contains only a single token/braced group that will be used as the icon and the title will be the default one. If you only specify one optional argument and it contains more than a single token/group it'll be the title and the default icon is used.

\documentclass{article}

\usepackage{xcolor}
\usepackage{fontawesome}

\definecolor{icons}{HTML}{46A247}

\ExplSyntaxOn
\msg_new:nnn { pubtitle } { extraneous-optional }
  {
    \exp_not:N \pubtitle
    only~ accepts~ optional~ arguments~ if~ you~ use~ `custom'~ as~ a~
    mandatory~ argument.
  }
\msg_new:nnnn { pubtitle } { unsupported-argument }
  { Unsupported~ entry~ field~ `#1'~ for~ bibliography. }
  { Perhaps~ you~ meant~ `\token_to_str:N \pubtitle[<icon>][<text>]{custom}'. }

% document interfaces
\NewDocumentCommand \pubtitle { o o m }
  { \pubtitle_pubtitle:nne {#1} {#2} { \str_foldcase:n {#3} } }
\NewDocumentCommand \Pubtitle { >{\SplitArgument{1}{,}}o m }
  {
    % design decision of ltcmd: unused o-args are not processed by argument
    % processors, so we need to add this processing here
    \IfNoValueTF {#1}
      { \pubtitle_pubtitle:nne {#1} {#1} }
      { \pubtitle_pubtitle:nne #1 }
        { \str_foldcase:n {#2} }
  }

\tl_new:N \l__pubtitle_default_custom_icon_tl
\tl_new:N \l__pubtitle_default_custom_title_tl
\tl_set:Nn \l__pubtitle_default_custom_icon_tl { \faFileTextO }
\tl_set:Nn \l__pubtitle_default_custom_title_tl { Publication }

% internal code
\cs_new_protected:Npn \pubtitle_pubtitle:nnn #1#2#3
  {
    \str_case:nnTF {#3}
      {
        { book }    { \pubtitle_symbolheading:nn \faBook     { Book } }
        { article } { \pubtitle_symbolheading:nn \faFileText { Article } }
      }
      {
        \tl_if_novalue:nF {#1}
          { \msg_error:nn { pubtitle } { extraneous-optional } }
      }
      {
        \str_if_eq:nnTF {#3} { custom }
          {
            \tl_if_novalue:nTF {#2}
              {
                \tl_if_novalue:nTF {#1}
                  {
                    \pubtitle_symbolheading:nn
                      \l__pubtitle_default_custom_icon_tl
                      \l__pubtitle_default_custom_title_tl
                  }
                  {
                    \tl_if_single:nTF {#1}
                      {
                        \pubtitle_symbolheading:nn
                          #1
                          \l__pubtitle_default_custom_title_tl
                      }
                      {
                        \pubtitle_symbolheading:nn
                          \l__pubtitle_default_custom_icon_tl
                          {#1}
                      }
                  }
              }
              { \pubtitle_symbolheading:nn {#2} {#1} }
          }
          { \msg_error:nnn { pubtitle } { unsupported-argument } {#3} }
      }
  }
\cs_generate_variant:Nn \pubtitle_pubtitle:nnn { nne }
\cs_new_protected:Npn \pubtitle_symbolheading:nn #1#2
  {
    \group_begin:
      \large
      \textcolor { icons } {#1}
      \skip_horizontal:n { 10pt }
      \textbf {#2}
    \group_end:
  }

% just for tests
\NewDocumentCommand \showtest { v }
  {
    \noindent\texttt{#1}:\\
    \tl_rescan:nn {} {#1}
    \par
    \medskip
  }
\ExplSyntaxOff

\begin{document}
\section{Interface \texttt{\protect\string\pubtitle}}
\showtest{\pubtitle{book}}
\showtest{\pubtitle{ArTiClE}}
\showtest{\pubtitle[Beer][\faBeer]{custom}} % thanks Ulrich for the beer
\showtest{\pubtitle[\faBeer]{custom}}
\showtest{\pubtitle[Beer]{custom}}

% error cases
%\pubtitle{invalidArgument} % throws an error
%\pubtitle[\faBook]{article} % throws an error
%\pubtitle[\faBook]{custom} % throws an error

\section{Interface \texttt{\protect\string\Pubtitle}}
\showtest{\Pubtitle{book}}
\showtest{\Pubtitle{ArTiClE}}
\showtest{\Pubtitle[Beer,\faBeer]{custom}} % thanks Ulrich for the beer
\showtest{\Pubtitle[\faBeer]{custom}}
\showtest{\Pubtitle[Beer]{custom}}

%\Pubtitle{invalidArgument} % throws an error
%\Pubtitle[\faBook]{article} % throws an error
%\Pubtitle[\faBook]{custom} % throws an error
%\Pubtitle[\faBeer,Beer, and more]{custom} % throws an error
\end{document}

enter image description here