Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I have to execute a macro a number of times, and would like to provide a list of the parameters to be executed. So, instead of

\FormatLinks*[Main Search Site]{Google}{http://www.google.com}
\FormatLinks[]{Google}{http://www.google.com}
\FormatLinks{Yahoo}{http://www.yahoo.com}

I would prefer to simply set a list:

\DefineMyFormatLinkParameters{%
    *[Main Search Site]{Google}{http://www.google.com},
    []{Google}{http://www.google.com},
    {Yahoo}{http://www.yahoo.com},
}

and then execute the \FormatLinks macro \foreach each element of this list. I think this is probably some expansion related issue, but I was not able to get it to work. Currently, the output is:

enter image description here

Code:

\documentclass{article}
\usepackage{url}
\usepackage{pgffor}
\usepackage{xparse}
\usepackage{xstring}
\usepackage[colorlinks=true]{hyperref}

\NewDocumentCommand{\FormatLinks}{%
    s%   #1 =* not used yet
    O{}% #2 = optional title
    m%   #3 = Mandatory title
    m%   #4 = URL Link
}{%
    \par
    \IfStrEq{#2}{}{%
        \hspace*{1.0cm}\href{#4}{#3}%
    }{%
        \hspace*{1.0cm}\href{#4}{#3~(#2)}%
    }%
}%

\newcommand*{\MyFormatLinkParameters}{}% Initialize
\newcommand*{\DefineMyFormatLinkParameters}[1]{%
    \edef\MyFormatLinkParameters{#1}%
}%

\begin{document}
\FormatLinks*[Main Search Site]{Google}{http://www.google.com}
\FormatLinks[]{Google}{http://www.google.com}
\FormatLinks{Yahoo}{http://www.yahoo.com}

% Would prefer to define a list, and later execute the list:
\DefineMyFormatLinkParameters{%
    *[Main Search Site]{Google}{http://www.google.com},
    []{Google}{http://www.google.com},
    {Yahoo}{http://www.yahoo.com},
}

\bigskip% 
Following should produce same results as above:\medskip\par
\foreach \x in \MyFormatLinkParameters {%
    \typeout{DEBUG: "\x"}
    \FormatLinks{\x}
}

\end{document}
share|improve this question

2 Answers 2

up vote 4 down vote accepted

Two things are wrong here:

  1. Expansion of \x should be done and not passed as a single argument to \FormatLinks.

    So, instead of

    \FormatLinks{\x}
    

    use

    \expandafter\FormatLinks\x
    

    since this will leave an expanded \x in the input stream for \FormatLinks to gobble up.

  2. You have an empty item in the list (the last item);

    The empty list item implies that when you're passing \x to \FormatLinks it is expecting at least two arguments yet it receives none. So it gobbles whatever comes along and obviously does the wrong thing.

enter image description here

\documentclass{article}
\usepackage{url}
\usepackage{pgffor}
\usepackage{xparse}
\usepackage{xstring}
\usepackage[colorlinks=true]{hyperref}

\NewDocumentCommand{\FormatLinks}{%
    s%   #1 =* not used yet
    O{}% #2 = optional title
    m%   #3 = Mandatory title
    m%   #4 = URL Link
}{%
    \par
    \IfStrEq{#2}{}{%
        \hspace*{1.0cm}\href{#4}{#3}%
    }{%
        \hspace*{1.0cm}\href{#4}{#3~(#2)}%
    }%
}%

\newcommand*{\MyFormatLinkParameters}{}% Initialize
\newcommand*{\DefineMyFormatLinkParameters}[1]{%
    \edef\MyFormatLinkParameters{#1}%
}%

\begin{document}
\FormatLinks*[Main Search Site]{Google}{http://www.google.com}
\FormatLinks[]{Google}{http://www.google.com}
\FormatLinks{Yahoo}{http://www.yahoo.com}

% Would prefer to define a list, and later execute the list:
\DefineMyFormatLinkParameters{%
    *[Main Search Site]{Google}{http://www.google.com},
    []{Google}{http://www.google.com},
    {Yahoo}{http://www.yahoo.com}
}

\bigskip% 
Following should produce same results as above:\medskip\par
\foreach \x in \MyFormatLinkParameters {%
    \typeout{DEBUG: "\x"}
    \expandafter\FormatLinks\x
}

\end{document}
share|improve this answer
    
Thanks. I had tried \expandafter\FormatLinks{\x}, but did not try \expandafter\FormatLinks\x. –  Peter Grill yesterday

Why the mysterious \IfStr{#2}{} when xparse already provides the infrastructure?

\NewDocumentCommand{\FormatLinks}{%
    s%   #1 =* not used yet
    o%   #2 = optional title
    m%   #3 = Mandatory title
    m%   #4 = URL Link
}{%
  \par
  \hspace*{1.0cm}\href{#4}{#3\IfValueT{#2}{~#2}}%
}

The problem is that you don't want to do \FormatLinks{\x} but want to expand \x before \FormatLinks sees it; however the braces should not be there. So \expandafter\FormatLinks\x would do.

Better, use a clist and a mapping function.

\documentclass{article}
\usepackage{url}
\usepackage{xparse}
\usepackage[colorlinks=true]{hyperref}

\NewDocumentCommand{\FormatLinks}{%
    s%   #1 =* not used yet
    o%   #2 = optional title
    m%   #3 = Mandatory title
    m%   #4 = URL Link
}{%
  \par
  \hspace*{1.0cm}\href{#4}{#3\IfValueT{#2}{~#2}}%
}

\ExplSyntaxOn
\NewDocumentCommand{\FormatLinksList}{}
 {
  \clist_map_inline:Nn \g_grill_linkparameters_clist { \FormatLinks ##1 }
 }
\NewDocumentCommand{\DefineMyFormatLinkParameters}{m}
 {
  \clist_gset:Nn \g_grill_linkparameters_clist { #1 }
 }
\ExplSyntaxOff

\begin{document}
\FormatLinks*[Main Search Site]{Google}{http://www.google.com}
\FormatLinks[]{Google}{http://www.google.com}
\FormatLinks{Yahoo}{http://www.yahoo.com}

% Would prefer to define a list, and later execute the list:
\DefineMyFormatLinkParameters{
    *[Main Search Site]{Google}{http://www.google.com},
    []{Google}{http://www.google.com},
    {Yahoo}{http://www.yahoo.com},
}

\bigskip

Following should produce same results as above:\medskip\par

\FormatLinksList

\end{document}

enter image description here

share|improve this answer
    
I didn't know that \IfValueT would properly handle the case where the user specified []. That is really helpful to know. –  Peter Grill yesterday
    
@PeterGrill It returns true only if the user specifies [...]. There are also \IfValueF and \IfValueTF; \IfValueT is equivalent to \IfNoValueF, but in this case it's semantically preferable the “positive” one. –  egreg yesterday

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.