1

I have created a class that does the standard things: declares and processes options, loads a base class (article), loads other packages, defines variables, defines a custom fancy header and footer, and, uses the AtBeginDocument and AtEndDocument hooks to set the style and form layout using the variables defined above for customization.

My question is: How can I redefine variables in the main.tex file before \begin{document} that override the default class variables used in AtEndDocument? Currently, setting a variable in main does not override the default value. Here is the functionality I would like to achieve with this class (form customization):

\documentclass[color, 10pt, letterpaper]{coverletter}

\fromname{Bobby Digital}
\fromtitle{Futurist}

\toname{Duncan Merryweather}
\totitle{Knower of Things}
\tostreet{221b Baker Street}

\begin{document}

    The text here \ldots

\end{document}

And the form would, in theory, update the fields and display correctly. Here is the current cls file:

%% Identification
%% The class identifies itself and the LaTeX version needed
\NeedsTeXFormat{LaTeX2e}

\ProvidesClass{coverletter}[2018/01/03 Cover Letter by Adam Erickson]

%% Preliminary definitions needed by options

% For defining official university colors
\RequirePackage[dvinames]{xcolor}

%% Declare options
\DeclareOption{draft}{\OptionNotUsed}
\DeclareOption{landscape}{\OptionNotUsed}
\DeclareOption{titlepage}{\OptionNotUsed}

\DeclareOption{color}{
  \definecolor{color1}{RGB}{152,30,50}
  \definecolor{gray}{RGB}{94,106,113} % {HTML}{5e6a71}
}

\DeclareOption{bw}{
  \definecolor{color1}{RGB}{0,0,0}
  \definecolor{gray}{RGB}{94,106,113} % {HTML}{5e6a71}
}

\DeclareOption*{
  \ClassWarning{coverletter}{Unknown option '\CurrentOption'}
}

%\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}

\ExecuteOptions{color}

\ProcessOptions{\relax}

%% Load parent class with options
\LoadClassWithOptions{article}

%% Load packages

% UTF-8 input encoding
\RequirePackage[utf8]{inputenc}

% Measurements from university guide
\RequirePackage[top=2in, left=1.5in, bottom=0.5in, right=0.625in]{geometry}
\RequirePackage{graphicx}
\RequirePackage[colorlinks=false, pdfborder={0 0 0},]{hyperref}
\RequirePackage[absolute]{textpos}
\RequirePackage{ifthen}
\RequirePackage{soul}

% For placement of the horizontal line
\RequirePackage{tikz}

% A nice serif font (palatino), but not the prescribed nonfree ITC stone
\RequirePackage[sc,osf]{mathpazo}

% Header and footer formatting
\RequirePackage{fancyhdr}

%% Command definitions
\renewcommand{\date}[1][\today]{#1}

% Sender information
\newcommand{\fromname}[1][Bill Smith]{#1}
\newcommand{\fromtitle}[1][Researcher]{#1}
\newcommand{\fromdegree}[1][Ph.D.]{#1}
\newcommand{\fromdept}[1][Department of Bills]{#1}
\newcommand{\fromuni}[1][Bob University]{#1}
\newcommand{\fromstreet}[1][100 Bill Ave.]{#1}
\newcommand{\fromcity}[1][Miami, FL, 33101]{#1}
\newcommand{\fromcountry}[1][USA]{#1}
\newcommand{\fromtel}[1][(800) 123-4567]{#1}
\newcommand{\fromfax}[1]{#1}
\newcommand{\fromemail}[1][\url{bill.smith@bob.edu}]{#1}
\newcommand{\fromweb}[1][\url{https://www.bob.edu/smithlab/}]{#1}

% Recipient information
\newcommand{\toname}[1][Recipient]{#1}
\newcommand{\totitle}[1][Title]{#1}
\newcommand{\todept}[1][Department of \ldots]{#1}
\newcommand{\touni}[1][University of \ldots]{#1}
\newcommand{\tostreet}[1][Street]{#1}
\newcommand{\tocity}[1][City, State/Province, ZIP]{#1}
\newcommand{\tocountry}[1][Country]{#1}

% Opening and closing phrases
\newcommand{\opening}[1][Dear]{#1 \toname,}
\newcommand{\closing}[1][Sincerely]{#1,}

% Linked files
\newcommand{\signaturefile}{} % your signature
\newcommand{\logofile}{logo.eps} % university logo
\newcommand{\enclosure}{} % any enclosures

%% Body of the class, most of the declarations appear here

% Horizontal line, font, and header/footer style
\usetikzlibrary{calc}
\linespread{1.05}
%\pagestyle{fancy}

% Remove paragraph indentation
\setlength{\parindent}{0pt}
\setlength{\parskip}{0.8\baselineskip}
\raggedright

% Set the URL style
\urlstyle{sf}

% Ensure consistency of the footer
\fancypagestyle{main}{%
    \fancyhf{} % clear the existing header and footer
    % define the header
    \fancyhead[L]{%
        \begin{textblock*}{2in}[0.3066,0.39](1.5in,1.33in)
            \includegraphics[width=2in]{\logofile}
        \end{textblock*}
        \begin{textblock*}{6.375in}(1.5in,1.4in) % 6.375 = 8.5-1.5-0.625
            \sffamily
            \hfill \color{gray} \fromdept
            \\ \hfill \fromname, \fromdegree
        \end{textblock*}
        \begin{tikzpicture}[remember picture,overlay]
            \draw[color=color1,line width=0.7pt] (current page.north west)+(1.5in,-1.33in) -- ($(-0.625in,-1.33in)+(current page.north east)$);
        \end{tikzpicture}
    }
    % define the footer
    \fancyfoot[L]{%
        {\footnotesize \color{gray} \sffamily
        \fromstreet, \fromcity \\
        [-0.1\baselineskip]
        \fromtel\ \textbullet\ Fax: \fromfax\ \textbullet\ \fromemail\ \textbullet\ \fromweb} \color{black}
    }
    % define the line thickness
    \renewcommand{\headrulewidth}{0pt}
    \renewcommand{\footrulewidth}{0pt}
}

\AtBeginDocument{% Text lines should be less than 6in long
    \pagestyle{main} % fancy page style
    \newgeometry{top=2in,left=1.5in,bottom=1.2in,right=1in}
    \date \\ \bigskip
    \toname\ifthenelse{\equal{\toname}{}}{}{\\}
    \todept \\
    \touni \\
    \tostreet \\
    \tocity \\
    \tocountry \\
    \bigskip
    \opening\par
}

\AtEndDocument{%
    \par\vspace{2ex}
    \closing\par
    \ifthenelse{\equal{\signaturefile}{}}{\bigskip\bigskip}{\includegraphics[width=1.2in]{\signaturefile}\\[-0.2\baselineskip]}
    \ifthenelse{\equal{\fromdegree}{Ph.D.}}{Dr.~\fromname}{\fromname} \\
    \fromtitle\ifthenelse{\equal{\fromtitle}{}}{}{\\}
    \enclosure
}

\endinput

Again, the main.text file is as above.

5
  • 1
    Redefinition can be done in main.tex with \AtBeginDocument as well. The macro glues all \AtBeginDocument content together. The last effective statement will be done last. But why are you storing again in \AtEndDocument? Are those values saved to the .aux file? – user31729 Jan 4 '19 at 20:14
  • As long as there is no working document with the code of coverletter class provided, the question remains a little bit unclear – user31729 Jan 4 '19 at 20:16
  • from your description (if the commands are not used until end document) you should be able to redefine them anywhere, why do definitions in the document not work? You have provided no example code so it is hard to guess. – David Carlisle Jan 4 '19 at 20:36
  • Thank you for your quick comments. I have added code for the class. – Adam Erickson Jan 4 '19 at 20:44
  • \fromname etc. are defined to print out the argument -- this will fail in the preamble of the document and is most likely not what you want directly in document body. You have to distinguish between a storage macro and a typesetting macro – user31729 Jan 4 '19 at 20:49
3

enter image description here

I suggest to use the traditional \@author etc. approach that is used in \maketitle, i.e. defining storage macros \fromname, that set \@fromname, which is used in the letter header etc.

Example:

\def\@fromname{Bill Smith}% Default value. 

\newcommand{\fromname}[1]{%
   \gdef\@fromname{#1}%
}

Class code (Portions commented out)

%% Identification
%% The class identifies itself and the LaTeX version needed
\NeedsTeXFormat{LaTeX2e}

\ProvidesClass{coverletter}[2018/01/03 Cover Letter by Adam Erickson]

%% Preliminary definitions needed by options

% For defining official university colors
\RequirePackage[dvinames]{xcolor}

%% Declare options
\DeclareOption{draft}{\OptionNotUsed}
\DeclareOption{landscape}{\OptionNotUsed}
\DeclareOption{titlepage}{\OptionNotUsed}

\DeclareOption{color}{
  \definecolor{color1}{RGB}{152,30,50}
  \definecolor{gray}{RGB}{94,106,113} % {HTML}{5e6a71}
}

\DeclareOption{bw}{
  \definecolor{color1}{RGB}{0,0,0}
  \definecolor{gray}{RGB}{94,106,113} % {HTML}{5e6a71}
}

\DeclareOption*{
  \ClassWarning{coverletter}{Unknown option '\CurrentOption'}
}

%\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}

\ExecuteOptions{color}

\ProcessOptions{\relax}

%% Load parent class with options
\LoadClassWithOptions{article}

%% Load packages

% UTF-8 input encoding
\RequirePackage[utf8]{inputenc}

% Measurements from university guide
\RequirePackage[top=2in, left=1.5in, bottom=0.5in, right=0.625in]{geometry}
\RequirePackage{graphicx}
\RequirePackage[absolute]{textpos}
\RequirePackage{ifthen}
\RequirePackage{soul}

\RequirePackage{etoolbox}
\RequirePackage[colorlinks=false, pdfborder={0 0 0},]{hyperref}

% For placement of the horizontal line
\RequirePackage{tikz}

% A nice serif font (palatino), but not the prescribed nonfree ITC stone
\RequirePackage[sc,osf]{mathpazo}

% Header and footer formatting
\RequirePackage{fancyhdr}

%% Command definitions
\renewcommand{\date}[1][\today]{#1}

% Sender information

\gdef\@fromname{Bill Smith}

\newcommand{\fromname}[1]{%%
  \gdef\@fromname{#1}%
}

\gdef\@toname{Recipient}

\newcommand{\toname}[1]{%
  \gdef\@toname{#1}%
}


% Opening and closing phrases
\newcommand{\opening}[1][Dear]{#1 \@toname,}
\newcommand{\closing}[1][Sincerely]{#1,}

% Linked files
\newcommand{\signaturefile}{} % your signature
\newcommand{\logofile}{ente} % university logo

%\newcommand{\logofile}{logo.eps} % university logo
\newcommand{\enclosure}{} % any enclosures

%% Body of the class, most of the declarations appear here

% Horizontal line, font, and header/footer style
\usetikzlibrary{calc}
\linespread{1.05}
%\pagestyle{fancy}

% Remove paragraph indentation
\setlength{\parindent}{0pt}
\setlength{\parskip}{0.8\baselineskip}
\raggedright

% Set the URL style
\urlstyle{sf}

% Ensure consistency of the footer
\fancypagestyle{main}{%
    \fancyhf{} % clear the existing header and footer
    % define the header
    \fancyhead[L]{%
        \begin{textblock*}{2in}[0.3066,0.39](1.5in,1.33in)
            \includegraphics[width=2in]{\logofile}
        \end{textblock*}
        \begin{textblock*}{6.375in}(1.5in,1.4in) % 6.375 = 8.5-1.5-0.625
            \sffamily
            \hfill \color{gray} %\fromdept
            \\ \hfill %\@fromname, %\fromdegree
        \end{textblock*}
        \begin{tikzpicture}[remember picture,overlay]
            \draw[color=color1,line width=0.7pt] (current page.north west)+(1.5in,-1.33in) -- ($(-0.625in,-1.33in)+(current page.north east)$);
        \end{tikzpicture}
    }
    % define the footer
%    \fancyfoot[L]{%
%      {\footnotesize \color{gray} \sffamily
%          % \fromstreet, \fromcity 
%        \\[-0.1\baselineskip]
%        \fromtel\ \textbullet\ Fax: \fromfax\ \textbullet\ \fromemail\ \textbullet\ \fromweb} \color{black}
%    }
    % define the line thickness
    \renewcommand{\headrulewidth}{0pt}
    \renewcommand{\footrulewidth}{0pt}
}

\AtBeginDocument{% Text lines should be less than 6in long
    \pagestyle{main} % fancy page style
    \newgeometry{top=2in,left=1.5in,bottom=1.2in,right=1in}
    \date \\ \bigskip
    %\toname\ifthenelse{\equal{\toname}{}}{}{\\}
    %\todept \\
    %\touni \\
    %\tostreet \\
    %\tocity \\
    %\tocountry \\
    \bigskip
    \opening\par
}

\AtEndDocument{%
    \par\vspace{2ex}
    \closing\par
    \ifthenelse{\equal{\signaturefile}{}}{\bigskip\bigskip}{\includegraphics[width=1.2in]{\signaturefile}\\[-0.2\baselineskip]}
%    \ifthenelse{\equal{\fromdegree}{Ph.D.}}{Dr.~\fromname}{\fromname} \\
%    \fromtitle\ifthenelse{\equal{\fromtitle}{}}{}{\\}
    \enclosure
}

\endinput

Main driver:

\documentclass[color, 10pt, letterpaper]{coverletter}

\fromname{Bobby Digital}
\toname{Duncan Merryweather}
%\fromtitle{Futurist}

%\totitle{Knower of Things}
%\tostreet{221b Baker Street}

\begin{document}

    The text here \ldots

\end{document}

**Update with l3keys ** interface

    \documentclass[color, 10pt, letterpaper]{coverletter}


    \SetLetterData{fromname={Bobby Digital},
      fromtitle={Futurist},
      toname={Duncan Merryweather},
      totitle={Knower of Things},
      tostreet={221b Baker Street}
    }

    \begin{document}

        The text here \ldots

    \end{document}

New class code:

%% Identification
%% The class identifies itself and the LaTeX version needed
\NeedsTeXFormat{LaTeX2e}

\ProvidesClass{coverletter}[2018/01/03 Cover Letter by Adam Erickson]

%% Preliminary definitions needed by options

% For defining official university colors
\RequirePackage[dvinames]{xcolor}

%% Declare options
\DeclareOption{draft}{\OptionNotUsed}
\DeclareOption{landscape}{\OptionNotUsed}
\DeclareOption{titlepage}{\OptionNotUsed}

\DeclareOption{color}{
  \definecolor{color1}{RGB}{152,30,50}
  \definecolor{gray}{RGB}{94,106,113} % {HTML}{5e6a71}
}

\DeclareOption{bw}{
  \definecolor{color1}{RGB}{0,0,0}
  \definecolor{gray}{RGB}{94,106,113} % {HTML}{5e6a71}
}

\DeclareOption*{
  \ClassWarning{coverletter}{Unknown option '\CurrentOption'}
}

%\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}

\ExecuteOptions{color}

\ProcessOptions{\relax}

%% Load parent class with options
\LoadClassWithOptions{article}

%% Load packages

% UTF-8 input encoding
\RequirePackage[utf8]{inputenc}

% Measurements from university guide
\RequirePackage[top=2in, left=1.5in, bottom=0.5in, right=0.625in]{geometry}
\RequirePackage{graphicx}
\RequirePackage[absolute]{textpos}
\RequirePackage{ifthen}
\RequirePackage{soul}

\RequirePackage{etoolbox}
\RequirePackage[colorlinks=false, pdfborder={0 0 0},]{hyperref}

% For placement of the horizontal line
\RequirePackage{tikz}

% A nice serif font (palatino), but not the prescribed nonfree ITC stone
\RequirePackage[sc,osf]{mathpazo}

% Header and footer formatting
\RequirePackage{fancyhdr}

%% Command definitions
\renewcommand{\date}[1][\today]{#1}

\usepackage{xparse} 


\ExplSyntaxOn 

\prop_new:N \l_coverletter_data_prop

\keys_define:nn {coverletter} {%
  fromname .code:n={ \prop_put:Nnn \l_coverletter_data_prop {fromname} {#1} },
  fromtitle .code:n={ \prop_put:Nnn \l_coverletter_data_prop {fromtitle} {#1} },
  fromdegree .code:n={ \prop_put:Nnn \l_coverletter_data_prop {fromdegree} {#1} },
  fromdept .code:n={ \prop_put:Nnn \l_coverletter_data_prop {fromdept} {#1} },
  fromuni .code:n={ \prop_put:Nnn \l_coverletter_data_prop {fromuni} {#1} },
  fromcity .code:n={ \prop_put:Nnn \l_coverletter_data_prop {fromcity} {#1} },
  fromstreet .code:n={ \prop_put:Nnn \l_coverletter_data_prop {fromstreet} {#1} },
  fromtel .code:n={ \prop_put:Nnn \l_coverletter_data_prop {fromtel} {#1} },
  fromcountry .code:n={ \prop_put:Nnn \l_coverletter_data_prop {fromcountry} {#1} },
  fromfax .code:n={ \prop_put:Nnn \l_coverletter_data_prop {fromfax} {#1} },
  fromemail .code:n={ \prop_put:Nnn \l_coverletter_data_prop {fromemail} {#1} },
  fromweb .code:n={ \prop_put:Nnn \l_coverletter_data_prop {fromweb} {#1} },
  %%% More to follow here
  % Now the to - stuff
  toname .code:n={ \prop_put:Nnn \l_coverletter_data_prop {toname} {#1} },
  totitle .code:n={ \prop_put:Nnn \l_coverletter_data_prop {totitle} {#1} },
  todept .code:n={ \prop_put:Nnn \l_coverletter_data_prop {todept} {#1} },
  touni .code:n={ \prop_put:Nnn \l_coverletter_data_prop {touni} {#1} },
  tocity .code:n={ \prop_put:Nnn \l_coverletter_data_prop {tocity} {#1} },
  tostreet .code:n={ \prop_put:Nnn \l_coverletter_data_prop {toreet} {#1} },
  tocountry .code:n={ \prop_put:Nnn \l_coverletter_data_prop {tocountry} {#1} },
}


\NewDocumentCommand{\SetLetterData}{+m}{%
  \keys_set:nn {coverletter} {#1}%
}

\cs_new:Npn \GetLetterData#1{%
  \prop_item:Nn \l_coverletter_data_prop {#1}
}
\ExplSyntaxOff

% Set some default data
\SetLetterData{fromname=Bill Smith, 
  fromtitle={Researcher},
  fromdegree={Ph.D}, 
  fromdept={Department of Bills},
  fromuni={Bob University},
  fromcity={Miami, FL, 33101},
  fromstreet={100 Bill Ave.},
  fromcountry={USA},
  fromtel={(800) 123-4567},
  fromfax={},
  fromemail={\url{bill.smith@bob.edu}},
  fromweb={\url{https://www.bob.edu/smithlab/}},
  toname={Recipient},
  totitle={Title},
  todept={Department of Idiots},
  touni={University of Fools},
  tostreet={3 Stooges Avenue},
  tocity={City, State/Province, ZIP},
  tocountry={Country}
}



% Opening and closing phrases
\newcommand{\opening}[1][Dear]{#1 \GetLetterData{toname},}
\newcommand{\closing}[1][Sincerely]{#1,}

% Linked files
\newcommand{\signaturefile}{} % your signature
\newcommand{\logofile}{ente} % university logo

%\newcommand{\logofile}{logo.eps} % university logo
\newcommand{\enclosure}{} % any enclosures

%% Body of the class, most of the declarations appear here

% Horizontal line, font, and header/footer style
\usetikzlibrary{calc}
\linespread{1.05}
%\pagestyle{fancy}

% Remove paragraph indentation
\setlength{\parindent}{0pt}
\setlength{\parskip}{0.8\baselineskip}
\raggedright

% Set the URL style
\urlstyle{sf}

% Ensure consistency of the footer
\fancypagestyle{main}{%
    \fancyhf{} % clear the existing header and footer
    % define the header
    \fancyhead[L]{%
        \begin{textblock*}{2in}[0.3066,0.39](1.5in,1.33in)
            \includegraphics[width=2in]{\logofile}
        \end{textblock*}
        \begin{textblock*}{6.375in}(1.5in,1.4in) % 6.375 = 8.5-1.5-0.625
            \sffamily
            \hfill \color{gray} \GetLetterData{fromdept}
            \\  \hfill \GetLetterData{fromname}, \GetLetterData{fromdegree}
        \end{textblock*}
        \begin{tikzpicture}[remember picture,overlay]
            \draw[color=color1,line width=0.7pt] (current page.north west)+(1.5in,-1.33in) -- ($(-0.625in,-1.33in)+(current page.north east)$);
        \end{tikzpicture}
    }
    % define the footer
    \fancyfoot[L]{%
      {\footnotesize \color{gray} \sffamily
           \GetLetterData{fromstreet}, \GetLetterData{fromcity} \\[-0.1\baselineskip]
           \GetLetterData{fromtel}\ \textbullet\ Fax: \GetLetterData{fromfax}\ \textbullet\ \GetLetterData{fromemail}\ \textbullet\ \GetLetterData{fromweb}} \color{black}
    }
    % define the line thickness
    \renewcommand{\headrulewidth}{0pt}
    \renewcommand{\footrulewidth}{0pt}
}

\AtBeginDocument{% Text lines should be less than 6in long
    \pagestyle{main} % fancy page style
    \newgeometry{top=2in,left=1.5in,bottom=1.2in,right=1in}
    \date 

    \bigskip
    \GetLetterData{toname}\ifthenelse{\equal{\GetLetterData{toname}}{}}{}{\\}

    \GetLetterData{todept} 

    \GetLetterData{touni} 

    \GetLetterData{tostreet} 

    \GetLetterData{tocity} 

    \GetLetterData{tocountry} 

    \bigskip
    \opening\par
}

\AtEndDocument{%
    \par\vspace{2ex}
    \closing\par
    \ifthenelse{\equal{\signaturefile}{}}{\bigskip\bigskip}{\includegraphics[width=1.2in]{\signaturefile}\\[-0.2\baselineskip]}
    \ifthenelse{\equal{\GetLetterData{fromdegree}}{Ph.D.}}{Dr.~\GetLetterData{fromname}}{\GetLetterData{fromname}} \\
    \GetLetterData{fromtitle}\ifthenelse{\equal{\GetLetterData{fromtitle}}{}}{}{\\}
    \enclosure
}

\endinput

Explanation:

The new LaTeX3 features a nice key-value - interface with \keys_define:nn and \keys_set:nn.

For each of the relevant letter data fields I have defined a equally named key, i.e. fromname etc.

Those keys are stored in a property list name \l_coverletter_data_prop, which is something like a hash - table.

\SetLetterData{....} sets the keys and \GetLetterData{} extracts the key value. If the key value is empty, nothing is returned, but using \SetLetterData{} with some default values inside of the class code, this can't happen (unless some keyname has been forgotten)

10
  • 1
    Vielen Dank, Christian! As clsguide says that (LaTeX) \newcommand should always be preferred to (TeX) \def, what would the LaTeX equivalent of \gdef be? Perhaps \global\newcommand? – Adam Erickson Jan 4 '19 at 21:26
  • 1
    @AdamErickson: The standard classes use \gdef as well. Don't worry about that as long as it done in a concise manner and occurs within the class only – user31729 Jan 4 '19 at 21:30
  • That is good to know. I had heard that most classes use TeX, but that LaTeX is best for forward compatibility. Probably, it does not matter so much in this case, as there is no clear LaTeX equivalent anyway. – Adam Erickson Jan 4 '19 at 21:39
  • Also, that is verbose/repetitive enough that it would be ideal to implement with a separate macro. – Adam Erickson Jan 4 '19 at 21:45
  • 1
    @AdamErickson: Nope, not with xkeyval, but with LaTeX3 and its \keys_define etc. It's much easier. The order of specification of the keys is totally arbritary and you don't have to fiddle with \toname and \fromdegree etc.. It would be even possible to use those keys as class options, but I don't recommend it in case your letter class shall produce more than one letter in the same file – user31729 Jan 4 '19 at 22:10

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.