How to write a class that accepts an optional key-value pair?

Here is a small example using scrbase:

\begin{filecontents}{preview.cls}
\ProvidesClass{preview}[2012/12/15 v 0.01 class for creating a tight PSTricks
diagram]
\RequirePackage{scrbase}
\DefineFamily{preview}
\DefineFamilyMember{preview}
\DefineFamilyKey{preview}{PreviewBorder}[0pt]{%
  \if@atdocument% before or after \begin{document}?
    \expandafter\@firstofone% after \begin{document} do it just now
  \else
    \expandafter\AtEndOfClass% \PreviewBorder first defined after loading
                            % preview package!
  \fi{\setlength{\PreviewBorder}{#1}}%
}
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}
\FamilyProcessOptions{preview}
\LoadClass{article}
\RequirePackage{pstricks}
\RequirePackage[tightpage,active]{preview}
\PreviewEnvironment{pspicture}
\endinput
\end{filecontents}

\documentclass[PreviewBorder=12pt,twoside]{preview}

\begin{document}
\begin{pspicture}[showgrid=true](-2,-2)(2,2)
\end{pspicture}

And you may even change the value inside the document:

\FamilyOptions{preview}{PreviewBorder=5cm}
\begin{pspicture}[showgrid=true](-2,-2)(2,2)
\end{pspicture}

\end{document}

I've done so, because you may find a lot of information about using all the other packages, but seldom something about using scrbase.


You need to differential between an initial value (set even if the key is never used) and a default value (used if the key is given with no value). In your example you seem to want an initial value rather than a default. There are several packages which can do what you want: I'd probably use kvoptions for this relatively simple case.

\begin{filecontents}{preview.cls}
\ProvidesClass{preview}[2012/12/15 v 0.01 class for creating a tight PSTricks
diagram]
\RequirePackage{kvoptions}
\DeclareStringOption[0 pt]{PreviewBorder}
\ProcessKeyvalOptions*
\LoadClass{article}
\RequirePackage{pstricks}
\RequirePackage[tightpage,active]{preview}
\PreviewEnvironment{pspicture}
\AtEndOfClass{\setlength{\PreviewBorder}{\preview@PreviewBorder}}
%\AtEndOfClass{\showthe\PreviewBorder}
\end{filecontents}

\documentclass{preview}%default value 0pt does not work!
%\documentclass[PreviewBorder=0pt]{preview}% works as expected.

\begin{document}
    \begin{pspicture}(-2,-2)(2,2)
    \psframe[linecolor=red](-2,-2)(2,2)
    \end{pspicture}
\end{document}

You'll see that I've only set the length once: there does not seem to be a need to set it otherwise.


I don't know where you are using your \PreviewBorder length, but here is what I would do.

\RequirePackage{xkeyval}
\newlength{\preview@border}
\setlength{\preview@border}{0pt}
\DeclareOptionX{PreviewBorder}[0pt]{\setlength{\preview@border}{#1}
\ProcessOptionsX

Use the length \preview@border in your code later. Note that the default value is set in the \setlength macro. The [0pt] used in the option declaration is just the value to give if the user specifies the key with no value.

  • \usepackage{preview} results in a border of 0pt.
  • \usepackage[PreviewBorder]{preview} results in a border of 0pt.
  • \usepackage[PreviewBorder=10pt]{preview} results in a border of 10pt.

Edit. Here is the working example. Thanks for the correction. The class:

\ProvidesClass{p}
\LoadClass{article}
\RequirePackage{xkeyval}
\newlength{\preview@border}
\setlength{\preview@border}{0pt}
\DeclareOptionX{PreviewBorder}[0pt]{\setlength{\preview@border}{#1}}
\ProcessOptionsX

\def\myborder{\the\preview@border}

now, use the class 'p' The LaTeX file:

\documentclass[PreviewBorder=10pt]{p}
\begin{document}
The border is \myborder

\end{document}