12

I want to create a style file capturing my layout for theorem environments. In particular, I would like to pass an option to the package specifying the level of the theorem counter. So here is a minimal working example:

The style file:

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{mytheorem}

\RequirePackage{amsthm}
\newcommand{\level}{}

\DeclareOption{section}{\renewcommand{\level}{section}}
\DeclareOption{chapter}{\renewcommand{\level}{chapter}}
\ProcessOptions\relax

\theoremstyle{plain}
\newtheorem{theorem}{Theorem}[\level]
\newtheorem{corollary}[\level]{Corollary}

The document:

\documentclass{book}
\usepackage[section]{mytheorem}
\begin{document}
    \begin{corollary}
        Inhalt...
    \end{corollary}
\end{document}

However it would be nice to specify the option via a key-value syntax like so:

\usepackage[theoremlevel=section]{mytheorem}

How can this be done?

2 Answers 2

11

With xkeyval it is very simple to provide key values to packages, using \DeclareOptionX and \ProcessOptionsX, parsing the keys and doing the relevant options/redefinitions.

In order to preset some default values, use \ExecuteOptionsX{theoremlevel=section}, for example.

\DeclareOptionsX* is meant for processing unknown options.

Package file:

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{mytheorem}

\RequirePackage{amsthm}
\RequirePackage{xkeyval}

\newcommand{\level}{}

\DeclareOptionX{theoremlevel}{\renewcommand{\level}{#1}}
\DeclareOptionX*{\PackageWarning{mytheorem}{`\CurrentOption' ignored}}% For unknown options
\ExecuteOptionsX{theoremlevel=section}% Preset keys, 'section' being the default here

\ProcessOptionsX\relax

\theoremstyle{plain}
\newtheorem{theorem}{Theorem}[\level]
\newtheorem{corollary}[\level]{Corollary}

\endinput

Driver file:

\documentclass{book}
\usepackage[theoremlevel=chapter,foo]{mytheorem}% foo should provide a warning!
\begin{document}
    \begin{corollary}
        Inhalt...
    \end{corollary}
\end{document}
1
  • Of course, there other ways, with pgfkeys, keyval, kvoptions, l3keys2e etc.
    – user31729
    Feb 28, 2018 at 9:29
11

A few examples for different packages

All of the following package examples work with the following document when saved as mytheorem.sty.

\documentclass[]{report}

\usepackage[level=chapter, foo, bar=baz]{mytheorem}

\begin{document}
\begin{corollary}
  Inhalt
\end{corollary}
\end{document}

expkv family

Disclaimer: I'm the package author.

In the expkv family the package expkv-opt allows to parse package and class options with expkv sets. The main macros you can use for this are \ekvoProcessGlobalOptions (which will parse the options provided to \documentclass) and \ekvoProcessLocalOptions (which will parse the options directly provided to the current class/package).

You can conveniently define common key types using expkv-def. It provides the macro \ekvdefinekeys that will parse a key=value list to define new keys (a similar approach is also taken by other packages like l3keys, pgfkeys, or options).

The package file

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{mytheorem}

\RequirePackage{amsthm}
\RequirePackage{expkv-opt,expkv-def}

\ekvdefinekeys{mytheorem}
  {
     store   level = \mytheorem@level
    ,initial level = section
    % specify what happens for unknown keys
    ,unknown code  =
      \PackageWarning{mytheorem}
        {Unknown option `\detokenize{#1}' received `\detokenize{#2}'}
    ,unknown noval =
      \PackageWarning{mytheorem}{Unknown option `\detokenize{#1}'}
  }

% process options given to \documentclass
\ekvoProcessGlobalOptions{mytheorem}
% for the next ekvoProcess... use the unknown handlers like defined for the set
\ekvoUseUnknownHandlers*
% process options given to this package
\ekvoProcessLocalOptions{mytheorem}

\theoremstyle{plain}
\newtheorem{theorem}{Theorem}[\mytheorem@level]
\newtheorem{corollary}[\mytheorem@level]{Corollary}

LaTeX-kernel

This requires no packages at all. Recent kernels have this functionality built in. The only two solutions in this list that support LaTeX's new mechanism for options passed to a package when it was loaded beyond the first time (as of writing this) are this one and expkv-opt (with \ekvoProcessFutureOptions). Under the hood the key=value system used is the same as l3keys (see the next example).

The package file

\NeedsTeXFormat{LaTeX2e}
\ProvidesExplPackage{mytheorem}{}{}{}

\RequirePackage{amsthm}

\DeclareKeys
  {
     level   .tl_set:N         = \l__mytheorem_level_tl
    ,level   .initial:n        = section
    ,level   .value_required:n = true
    ,unknown .code:n           =
      \PackageWarning{mytheorem}{Unknown~ option~ `\l_keys_key_str'}
  }

\ProcessKeyOptions

\theoremstyle{plain}
\newtheorem{theorem}{Theorem}[\l__mytheorem_level_tl]
\newtheorem{corollary}[\l__mytheorem_level_tl]{Corollary}

Or if you prefer, using only LaTeX2e syntax (almost only, afaik, there is currently no 2e-name for .value_required:n):

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{mytheorem}

\RequirePackage{amsthm}

\DeclareKeys
  {
     level   .store            = \mytheorem@level
    ,level   .value_required:n = true
  }
\SetKeys{level=section}
\DeclareUnknownKeyHandler{\PackageWarning{mytheorem}{Unknown~ option~ `#1'}}

\ProcessKeyOptions

\theoremstyle{plain}
\newtheorem{theorem}{Theorem}[\mytheorem@level]
\newtheorem{corollary}[\mytheorem@level]{Corollary}

l3keys

The l3keys package provides a very stable and well thought out key=value solution. It is using the expl3 programming conventions. Support for package and class options in recent versions of LaTeX is available out of the box with \ProcessKeyOptions (see the section LaTeX-kernel above), for older LaTeX versions the functionality is added by the l3keys2e package which provides the macro \ProcessKeysOptions.

Keys are defined using \keys_define:nn with a key=value interface.

The package file

\NeedsTeXFormat{LaTeX2e}
\ProvidesExplPackage{mytheorem}{}{}{}

\RequirePackage{amsthm}
\RequirePackage{l3keys2e}

\keys_define:nn { mytheorem }
  {
     level   .tl_set:N         = \l__mytheorem_level_tl
    ,level   .initial:n        = section
    ,level   .value_required:n = true
    ,unknown .code:n           =
      \PackageWarning{mytheorem}{Unknown~ option~ `\l_keys_key_str'}
  }

\ProcessKeysOptions { mytheorem }

\theoremstyle{plain}
\newtheorem{theorem}{Theorem}[\l__mytheorem_level_tl]
\newtheorem{corollary}[\l__mytheorem_level_tl]{Corollary}

pgfkeys

Is part of pgf & TikZ. It is probably one of the most used key=value solutions and had a major influence on packages like l3keys and options. Support for class and packages options is added by the pgfopts package via the macro \ProcessPgfOptions. Keys are defined using \pgfkeys or \pgfqkeys with a key=value interface.

The package file

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{mytheorem}

\RequirePackage{amsthm}
\RequirePackage{pgfopts}

\pgfqkeys{/mytheorem}
  {
    .is family
    ,level/.store in = \mytheorem@level
    ,level/.initial  = section
    ,.unknown/.code  =
      \PackageWarning{mytheorem}{Unknown option `\pgfkeyscurrentname'}
  }

\ProcessPgfOptions{/mytheorem}

\theoremstyle{plain}
\newtheorem{theorem}{Theorem}[\mytheorem@level]
\newtheorem{corollary}[\mytheorem@level]{Corollary}

options

options is a seldom used package heavily inspired by pgfkeys. It comes with support for package options out of the box. Defining new keys looks pretty similar to pgfkeys.

The package file

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{mytheorem}

\RequirePackage{amsthm}
\RequirePackage{options}

\newcommand*\mytheorem@level{section}

\options
  {
    /mytheorem/.new family, /mytheorem/.cd
    ,level/.is def = \mytheorem@level
    ,@unknown/.new cmd 2 = \PackageWarning{mytheorem}{Unknown option `#1'}
  }

\options@ProcessOptions{/mytheorem}

\theoremstyle{plain}
\newtheorem{theorem}{Theorem}[\mytheorem@level]
\newtheorem{corollary}[\mytheorem@level]{Corollary}

You must log in to answer this question.