8

I'm writing a bunch of cover letters that are roughly 90% boilerplate and 10% customization. However, the boilerplate contains variables that I need to change each time. Similar to a function, I want to pass arguments to the boilerplate. Unlike previous posts about automation that seek to pass parameters to document structure, my goal is to pass parameters to document content. (My working assumption is that this is a different problem.)

To fix thoughts, here is a MWE of my template cover letter:

\documentclass[letterpaper,10pt]{article}
\begin{document}

Dear So and So, 

\input{boilerplate}

\end{document}

where boilerplate.tex is text with variables:

I am excited to apply for the position of [POSITION] at [PLACE]. Your organization's reputation for rigorous, high-quality programming on topics in align perfectly with my ambitions. I would relish the opportunity to collaborate with top coders on our shared interests in [INTERESTS]. I am committed to excellence in programming and supporting the Chicago Cubs.

and the idea is to pass arguments to [POSITION], [PLACE], and [INTERESTS].

Is it possible to pass parameters to input{}, or can this only be done on the command line?

  • Can't you generate commands like \myName in the preamble of the document? Something like \newcommand{\myName}{Dennis Miller} and then use \myName{} in the boilerplate.tex. I'll show an example as an answer. – Dr. Manuel Kuehner Nov 7 '16 at 20:20
  • all the answers suggest defining the boilerplate separately, then setting the parameter values and processing. but all of them only produce one letter. why not treat this as a form letter, and do a bunch of them at the same time? same principle, just \clearpage between them, reset the values (maybe they don't all need resetting; allow for that), then input the boilerplate again, etc. it really isn't different from passing parameters to document content -- they're all just substitutions for existing command names. – barbara beeton Nov 7 '16 at 21:43
  • @barbarabeeton one reason i find this approach appealing is because I have many small boilerplates for different jobs. given my skills (ahem) it was simply easier for me to make a tex file for each scrap of text and then input as necessary into a shell letter. the advantage to this approach is that I have a tex file for each letter - useful in case I want to say something very specific in a letter. However, i don't think for a minute this approach is the undisputed winner. besides cooking a whole batch of letters at once, are there any organizational advantages to your approach? – invictus Nov 8 '16 at 1:19
  • This sounds a lot like what I was trying to do before: tex.stackexchange.com/questions/89793/… – tpg2114 Nov 8 '16 at 2:08
  • @invictus -- as far as "organizational" is concerned, this approach has been used in production at the ams to prepare "consent to publish: letters for authors. but i'm sure that it's been described elsewhere on this site before, which is why i've commented rather than posting an answer. – barbara beeton Nov 8 '16 at 9:52
6

Using the listofitems package, here is a homemade key-value interface that can handle an arbitrary number of specified values in the \input file. If that is overkill, one of the original approaches that follow should suffice.

\documentclass[letterpaper,10pt]{article}
\usepackage{filecontents,listofitems}
\begin{filecontents*}{boilerplate.tex}
I am excited to apply for the position of [POSITION] at [PLACE]. Your organization's
reputation for rigorous, high-quality programming on topics in align perfectly with 
my ambitions. I would relish the opportunity to collaborate with top coders on our 
shared interests in [INTERESTS]. I am committed to excellence in programming 
and supporting the Chicago Cubs.
\end{filecontents*}
\catcode`[=\active %
\def[#1]{\csname #1\endcsname{}}%
\catcode`[=12 %
\newcommand\myinput[2]{%
  \setsepchar{,}%
  \readlist*\mydata{#2}%
  \foreachitem\myvardef\in\mydata{%
    \setsepchar{=}%
    \readlist*\myvar{\myvardef}%
    \expandafter\edef\csname\myvar[1]\endcsname{\myvar[2]}%
  }%
  \catcode`[=\active %
  \input{#1}%
  \catcode`[=12 %
}
\begin{document}
Dear So and So, 

\myinput{boilerplate}{POSITION=engineer, PLACE=IBM, INTERESTS=omphaloskepsis}
\end{document}

enter image description here


ORIGINAL APPROACHES

\documentclass[letterpaper,10pt]{article}
\usepackage{filecontents}
\begin{filecontents*}{boilerplate.tex}
I am excited to apply for the position of \POSITION{} at \PLACE{}. Your organization's
reputation for rigorous, high-quality programming on topics in align perfectly with 
my ambitions. I would relish the opportunity to collaborate with top coders on our 
shared interests in \INTERESTS{}. I am committed to excellence in programming 
and supporting the Chicago Cubs.
\end{filecontents*}
\newcommand\myinput[4]{%
  \def\POSITION{#2}%
  \def\PLACE{#3}%
  \def\INTERESTS{#4}%
  \input{#1}%
}
\begin{document}

Dear So and So, 

\myinput{boilerplate}{engineer}{IBM}{omphaloskepsis}

\end{document}

enter image description here

And if one really wanted to use bracketed delimiters in the input file, then this works (EDITED to allow arbitrary number of comma separated arguments in #2):

\documentclass[letterpaper,10pt]{article}
\usepackage{filecontents,listofitems}
\begin{filecontents*}{boilerplate.tex}
I am excited to apply for the position of [POSITION] at [PLACE]. Your organization's
reputation for rigorous, high-quality programming on topics in align perfectly with 
my ambitions. I would relish the opportunity to collaborate with top coders on our 
shared interests in [INTERESTS]. I am committed to excellence in programming 
and supporting the Chicago Cubs, [FOUR], [FIVE], [SIX], [SEVEN], [EIGHT], [NINE],
and [TEN].
\end{filecontents*}
\catcode`[=\active %
\def[#1]{\csname #1\endcsname{}}%
\catcode`[=12 %
\newcommand\myinput[2]{%
  \setsepchar{,}%
  \readlist*\mydata{#2}%
  \def\POSITION{\mydata[1]}%
  \def\PLACE{\mydata[2]}%
  \def\INTERESTS{\mydata[3]}%
  \def\FOUR{\mydata[4]}%
  \def\FIVE{\mydata[5]}%
  \def\SIX{\mydata[6]}%
  \def\SEVEN{\mydata[7]}%
  \def\EIGHT{\mydata[8]}%
  \def\NINE{\mydata[9]}%
  \def\TEN{\mydata[10]}%
  \catcode`[=\active %
  \input{#1}%
  \catcode`[=12 %
}
\begin{document}

Dear So and So, 

\myinput{boilerplate}{engineer,IBM,omphaloskepsis, Orioles, Red Sox, Cardinals,
  Phillies, Tigers, Blue Jays, Braves}

\end{document}

enter image description here

| improve this answer | |
  • Good solution. Arent't you here limited to nine parameters maximum? – Dr. Manuel Kuehner Nov 7 '16 at 20:28
  • 1
    @Dr.ManuelKuehner Yes, but that seems to be what the OP asked for. – Steven B. Segletes Nov 7 '16 at 20:32
  • You are right. I assumed that he wanted it somehow more general. – Dr. Manuel Kuehner Nov 7 '16 at 20:40
  • 1
    @Dr.ManuelKuehner My 2nd solution makes it more general – Steven B. Segletes Nov 7 '16 at 20:41
  • 1
    @StevenB.Segletes this is quite extraordinary. given my needs the first of the original approaches did the trick. my only complaint about your answer lies is the second original approach. who would ever hire somebody who supports the cubs and the cardinals. – invictus Nov 8 '16 at 1:21
6
\documentclass[letterpaper,10pt]{article}

% Definition of the variables
\newcommand{\myInterest}{Golf}
\newcommand{\myPosition}{Senior Engineer}
\newcommand{\myPlace}{New York}

\begin{document}

Dear So and So, 

% Use
% \myPlace{}
% \myPosition{}
% \myInterest{}
% in boilerplate.tex

\input{boilerplate.tex}

\end{document}

The {} after the commands are important in order to prevent that LaTeX "eats" the space after the command, see here for example. Consider to use the xspace package if you like my solution.

| improve this answer | |
4

You can hide almost everything in the boilerplate.tex file. The trick is to define the text in a macro that will be called at the end, when the values to the appropriate keys will have been defined.

File boilerplate.tex

% define the text
\newcommand{\boilerplate}{%
I am excited to apply for the position of \use{position} at \use{place}.
Your organization's reputation for rigorous, high-quality programming
on topics in align perfectly with my ambitions. I would relish the
opportunity to collaborate with top coders on our shared interests
in \use{interests}. I am committed to excellence in programming and
supporting the Chicago Cubs.}

% define the infrastructure
\ExplSyntaxOn
\keys_define:nn { boilerplate }
 {
  position  .tl_set:N = \l_invictus_position_tl,
  place     .tl_set:N = \l_invictus_place_tl,
  interests .tl_set:N = \l_invictus_interests_tl,
 }
\cs_new_protected:Nn \invictus_use_boilerplate:n
 {
  \keys_set:nn { boilerplate } { #1 }
  \boilerplate
 }
\cs_set_eq:NN \printboilerplate \invictus_use_boilerplate:n
\cs_new:Nn \invictus_use_variable:n
 {
  \tl_use:c { l_invictus_#1_tl }
 }
\cs_set_eq:NN \use \invictus_use_variable:n
\ExplSyntaxOff

File test.tex

\documentclass{article}
\usepackage{xparse}

\usepackage{parskip} % normal choice for business letters

\input{boilerplate}

\begin{document}

Dear So and So,

\printboilerplate{
  position = pitcher,
  place = Wrigley Field,
  interests = strikeouts,
}

Best regards.

\end{document}

Output

enter image description here

| improve this answer | |

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.