2

I often have a macro defined with with various optional parameters such as

\NewDocumentCommand{\GenericWebSite}{s O{blue} o m e_}{<code>}

and want to define a small variant of this macro, without duplicating all the <code> of the \GenericWebSite macro. So, for instance, I want to define

\NewDocumentCommand{\ImportantWebSite}{s o o m e_}{%
    \fcolorbox{red}{gray!20}{<code>}%
}

The brute force method (illustrated in the MWE below) works fine, but there must be an easier way to do this.

The first line is the output of various uses of \GenericWebSite and the second line is the invocation of \ImportantWebSite passed in with the same parameters.

enter image description here

Notes:

  • This question isn't about the specific functionality of the \GenericWebSite defined in the test case, but how, in general, to define a new xparse macro, \ImportantWebSite in the MWE, so that it can take advantage of an existing macro, \GenericWebSite in this case, that is already defined.
  • One option would be to pass in key-value flags to \GenericWebSite so that the single macro can provide all the functionality. While in this particular example, this is certainly doable, I would prefer to keep separate macros as in may actual use case I need many variants.

References:

Code:

\documentclass{article}

\usepackage{amsmath}
\usepackage{xparse}
\usepackage{xcolor}
\usepackage{hyperref}

\makeatletter
\newcommand*{\@DefaultWebLink}{http://tex.stackexchange.com}
\NewDocumentCommand{\GenericWebSite}{
    s%        * = text in #4 is already a link
    O{blue}% #2 = color to use for text
    o%       #3 = web site to link to (Defaults to \@DefaultWebLink)
    m%       #4 = text to display
    e_%      #5 = optional subscript
}{%
    \begingroup%% Keep \color{} change local 
        \color{#2}%
        \IfBooleanTF{#1}{% no need to link web site as it is already a link
            \textnormal{#4}
        }{%
            \IfNoValueTF{#3}{% web site to link to not provided, so use default
                \href{\@DefaultWebLink}{\textnormal{#4}}%
            }{% web site to link to provided
                \href{#3}{\textnormal{#4}}%
            }%
        }%
        \IfNoValueTF{#5}{}{% Include subscript since it was given
            _{Note:\,#5}
        }%
    \endgroup
}

%% Want to make use of \GenericWebSite with some slight modifications
\NewDocumentCommand{\ImportantWebSite}{
    s%   * = text in #4 is already a link
    o%  #2 = color to use for text <--- NOTE that this does NOT have a default
    o%  #3 = web site to link to (Defaults to \@DefaultWebLink)
    m%  #4 = text to display
    e_% #5 = optional subscript
}{%
    \fcolorbox{red}{gray!20}{$
    \IfBooleanTF{#1}{%
        \IfValueTF{#2}{% #2 given so needs to be passed on
            \IfValueTF{#3}{
                \IfValueTF{#5}{
                    \GenericWebSite*[#2][#3]{#4}_{#5}
                }{
                    \GenericWebSite*[#2][#3]{#4}
                }
            }{
                \IfValueTF{#5}{
                    \GenericWebSite*[#2]{#4}_{#5}
                }{
                    \GenericWebSite*[#2]{#4}
                }
            }
        }{% No #2 given, so same as true case above but without the #2
            \IfValueTF{#3}{
                \IfValueTF{#5}{
                    \GenericWebSite*[#3]{#4}_{#5}
                }{
                    \GenericWebSite*[#3]{#4}
                }
            }{%  No #2 and #3 given, so same as true case above but without the #2 and #3
                \IfValueTF{#5}{
                    \GenericWebSite*{#4}_{#5}
                }{
                    \GenericWebSite*{#4}
                }
            }
        }
    }{%  same as above but without the * option
        \IfValueTF{#2}{% #2 given so needs to be passed on
            \IfValueTF{#3}{
                \IfValueTF{#5}{
                    \GenericWebSite[#2][#3]{#4}_{#5}
                }{
                    \GenericWebSite[#2][#3]{#4}
                }
            }{
                \IfValueTF{#5}{
                    \GenericWebSite[#2]{#4}_{#5}
                }{
                    \GenericWebSite[#2]{#4}
                }
            }
        }{% No #2 given, so same as true case above but without the #2
            \IfValueTF{#3}{
                \IfValueTF{#5}{
                    \GenericWebSite[#3]{#4}_{#5}
                }{
                    \GenericWebSite[#3]{#4}
                }
            }{%  No #2 and #3 given, so same as true case above but without the #2 and #3
                \IfValueTF{#5}{
                    \GenericWebSite{#4}_{#5}
                }{
                    \GenericWebSite{#4}
                }
            }
        }
    }%
    $}%
}
\makeatother


\begin{document}
    %% Testing various uses of \GenericWebSite
    $\GenericWebSite{TeX.SE}$
    $\GenericWebSite[red]{TeX.SE}$
    $\GenericWebSite*[black]{\href{http://www.google.com}{The Google}}_4$

    %% Testing various uses of \ImportantWebSite
    \par\medskip
    $\ImportantWebSite{TeX.SE}$
    $\ImportantWebSite[red]{TeX.SE}$
    $\ImportantWebSite*[black]{\href{http://www.google.com}{The Google}}_4$
\end{document}
  • 1
    you could do something but "the model" is that you do the "brute force" method of redeclaring the command with the extended signature. The ideal is that all the coding is in expl3 (or even, classic latex2e) code and so the xparse declaration should almost always be a single liner, so you shouldn't need to adapt an existing declaration just declare a new command. – David Carlisle Aug 16 '18 at 20:20
  • @DavidCarlisle: Not sure I understand what is meant by "the xparse declaration should almost always be a single liner". Even if it is a single line, why would you want to duplicate the single line in any variants of a macro that you know works fine. If you have hundreds of variants and then decide that you need to change it you have hundreds of places where this needs to be fixed. I can't possibly be the only one that has this issue. What is the "something" you allude to? – Peter Grill Aug 16 '18 at 20:26
  • I just alluded to "something" as xparse is of course only a bunch of tex macros so you can always ---break--- redefine them if you really want to. But by design there is no built in \let or \patchcmnd replacement for xparse declared commands, but what I mean is that you should not have hudreds of places, just one. you make have lots of \DeclareDocumentcommand\doo{sooomo}{..} but they should be calling as single macro with mandatory arguments pg_core_code_layout_thing{1}{b}{c}{d}{e} and if you decide to redefine that to use \fcolorbox then all your variants will use the new code. ... – David Carlisle Aug 16 '18 at 20:39
  • ... The problem only comes if you put lots of programming level code in the xparse declaration as then that separation between programming functionality and declaring the user interface is lost – David Carlisle Aug 16 '18 at 20:41
  • 1
    You might be interested in this (deleted) answer of mine tex.stackexchange.com/a/285586 – Henri Menke Aug 16 '18 at 22:40
5

You should define both commands in terms of an internal one:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xcolor}
\usepackage{xparse}
\usepackage{hyperref}

\ExplSyntaxOn
\NewDocumentCommand{\GenericWebSite}{sO{blue}mO{\c_grill_website_default_tl}e{+}}
 {
  \grill_website:nnnnnN
   { #1 }
   { #2 }
   { #3 }
   { #4 }
   { #5 }
   \grill_website_generic:nn
 }
\NewDocumentCommand{\ImportantWebSite}{sO{}mO{\c_grill_website_default_tl}e{+}}
 {
  \grill_website:nnnnnN
   { #1 }
   { #2 }
   { #3 }
   { #4 }
   { #5 }
   \grill_website_important:nn
 }

\tl_const:Nn \c_grill_website_default_tl { http://tex.stackexchange.com }

\cs_new_protected:Nn \grill_website_generic:nn
 {
  \group_begin:
  \leavevmode
  \color{#1}
  #2
  \group_end:
 }
\cs_new_protected:Nn \grill_website_important:nn
 {
  \fcolorbox{red}{gray!20}
   {
    \tl_if_empty:nF { #1 } { \color{#1} }
    #2
   }
 }

\cs_new_protected:Nn \grill_website:nnnnnN
 {
  % #1 = *
  % #2 = optional color (for generic)
  % #3 = text to display
  % #4 = web site to link 
  % #5 = subscript
  % #6 = wrapper
  #6 { #2 }
   {
    \bool_if:nTF { #1 }
     {% no need to link web site as it is already a link
      \textnormal{#3}
     }
     {
      \href{#4}{\textnormal{#3}}
     }
    \tl_if_novalue:nF { #5 }
     {
      \mode_if_math:TF { \sb } { \textsubscript } {\textnormal{Note: #5}}
     }
   }
 }
\ExplSyntaxOff

\begin{document}

%% Testing various uses of \GenericWebSite
\GenericWebSite{TeX.SE}
\GenericWebSite[red]{TeX.SE}
\GenericWebSite*[black]{\href{http://www.google.com}{The Google}}+4
$\GenericWebSite*[black]{\href{http://www.google.com}{The Google}}+4$

\medskip

%% Testing various uses of \ImportantWebSite
\ImportantWebSite{TeX.SE}
\ImportantWebSite[red]{TeX.SE}
\ImportantWebSite*[black]{\href{http://www.google.com}{The Google}}+4
$\ImportantWebSite*[black]{\href{http://www.google.com}{The Google}}+4$

\end{document}

I changed the place of the second optional argument, because two consecutive ones should depend on one another whilst yours are independent.

The + for the note is just for technical reasons. I'd go with a key-value syntax.

enter image description here

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.