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

a user-defined class:

\ProvidesClass{preview}[2012/12/15 v 0.01 class for creating a tight PSTricks diagram]
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}
\ProcessOptions\relax
\RequirePackage{pstricks}
\RequirePackage[tightpage,active]{preview}
\PreviewEnvironment{pspicture}
\endinput


consumer's input file:

\documentclass[PreviewBorder=12pt]{preview}% the option will set \PreviewBorder=12pt.

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


How to write a class that accepts an optional key-value pair to set PreviewBorder as shown in the code snippet? Note: Its default value of the key is 0pt.

## The reason I don't accept the existing answer:

Because the default value does not work as expected. Please make a try the following code and see there is still a thin white padding (CSS terminology) around the red rectangle.

\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
% preview package!
\fi{\setlength{\PreviewBorder}{#1}}%
}
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}
\FamilyProcessOptions{preview}
\RequirePackage{pstricks}
\RequirePackage[tightpage,active]{preview}
\PreviewEnvironment{pspicture}
\endinput
\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}


In other words, I want both

\documentclass{preview}


and

\documentclass[PreviewBorder=0pt]{preview}


to produce the same result without border.

-
The following post should be helpful: A big list of every keyval package –  Marco Daniel Dec 15 '11 at 10:04
One example is given here: Pass keyval string option to babel Other examples can be found via the search function. –  Marco Daniel Dec 15 '11 at 10:32
IMHO optional arguments is the wrong term here. You should simply define a border=<value> option. Also your consumer file looks a lot like a usecase of the standalone class. \documentclass[border=12pt,preview,multi=pspicture]{standalone} will do most of what you have above. (The multi option will be ignored by v0.x, which is currently the official release. Please find v1.0beta at bitbucket.org/martin_scharrer/standalone/downloads. –  Martin Scharrer Dec 15 '11 at 10:42
Packages and classes are very similar in this respect, so perhaps How can I make a package that accepts an optional argument? is worth reading –  Joseph Wright Dec 15 '11 at 11:00

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*
\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.

-
Please uncomment the first \documentclass and comment the second one. Do you get the expected result? I don't. –  cyanide-based food Dec 20 '11 at 19:57
@CounterTerrorist Oops, a typo: I had the option name wrong. I've edited to correct this. I do get the same result for both cases. –  Joseph Wright Dec 20 '11 at 20:12
I've also added an optional \showthe line which you can use to see that the value for the border is the same in both cases. –  Joseph Wright Dec 20 '11 at 20:13
Unfortunately, nothing changes. I don't get a tight output without border when uncommenting the first one. –  cyanide-based food Dec 20 '11 at 20:14
@CounterTerrorist Are you deleting your preview.cls file between runs, as it will only be generated if it is not there. To check, try changing the version number and make sure in the log file that this also changes. If that fails, could you send me the two .tex files and matching logs: joseph.wright@morningstar2.co.uk? –  Joseph Wright Dec 20 '11 at 20:20

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
% preview package!
\fi{\setlength{\PreviewBorder}{#1}}%
}
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}
\FamilyProcessOptions{preview}
\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 would split the code into two blocks and remove the filecontents environment. Using it just to have one example file is more confusing for some users than helpful. –  Martin Scharrer Dec 15 '11 at 10:45
@Schweinebacke: Please see my last update. The optional default value does not work when I ignore it. –  cyanide-based food Dec 15 '11 at 16:08

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}
\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}

-