はじめに
LaTeX 命令の一般的な書式では,通常の引数はブレース{}
,オプション引数はブラケット[]
で囲って表現されます.
\command[〈オプション引数〉]{〈引数1〉}{〈引数2〉}
この方針はシンプルですが,引数の数が増えると「何番目の引数に何を書けばいいのか」ということがわかりにくくなってしまうという欠点があります.
一方,graphicx や TikZ といったパッケージを利用したことのある方であれば,〈キー〉=〈値〉
のカンマ区切りリスト(key-value リスト)を使用したことがあるのではないでしょうか.
% graphicx における例
\includegraphics[width=5cm, angle=30]{sushi.png}
% TikZ における例
\begin{tikzpicture}[x=1cm, y=1cm, line width=2pt]
\input{snowman.tex}
\end{tikzpicture}
【注意】key-value リストでは先頭・末尾およびカンマと等号の前後の空白はすべて無視されます.これは重要なことなので是非覚えておいてください.また key-value リストの〈値〉
の中で,
や=
を使いたい場合は〈値〉
全体をブレースで囲って,例えばkey={x=1, y=2}
のようにする必要があることも記憶に値するでしょう.
この key-value リストを扱う命令の実装は,最初に紹介したシンプルな形式の引数をとる命令よりも多少煩雑にはなります.しかし key-value リストを利用することには
- 引数の順番が自由かつ意味が明示的なので書式を覚えやすい
- グローバルな設定とローカルな設定を分けて実装しやすい
- 後方互換性を崩さずに機能拡張するのが容易
など多くのメリットがあります.本稿では,そんな key-value リストを扱う命令の作成を支援する xkeyval パッケージの基本的な使い方を解説していきます1.
対象読者と記事の方針
本稿の目的は「LaTeX でキーワード引数を使えるようにするための技術について解説すること」ですが,本稿の内容には TeX 言語的要素が多分に含まれます.したがって,本稿の対象読者は基本的には TeX 言語の基礎的な事項を習得している方,中でも LaTeX パッケージを制作する意欲のある方2です.
また,本稿では原則として「まず抽象的な説明を行ってから,具体例を示す」という形をとっています.key-value リストに関わる概念には少々複雑なものもあるので,抽象的な説明が理解できない場合でも立ち止まらずに読み進め,具体例をじっくり眺めるようにするといいかもしれません.
xkeyval パッケージについて
背景
LaTeX でキーワード引数を扱うためのパッケージとして最も基本的なものに keyval があります.これは元々 graphicx の内部で利用するために開発されたもののようですが,現在は LaTeX 必須パッケージ の1つである latex-graphics の一部として,LaTeX プロジェクトチームによって管理されています.そのため今日では keyval は様々なパッケージで内部的に利用されています.
この keyval パッケージは極めて簡素なものであるため,基本的な使い方を覚えるのは容易であり,さらに色々と工夫さえすればかなり凝った仕様のキーワード引数を実装することも可能です.一方で,keyval パッケージは少々素朴過ぎる嫌いがあり,ちょっと複雑なキーワード引数を実現しようとするとすぐにコードが冗長かつ複雑なものになってしまいます.
そうした欠点を補うため,keyval パッケージを機能拡張したものが xkeyval です.xkeyval は内部的に keyval を読み込んでおり,keyval に対して上位互換です.さらに xkeyval では,通常の命令だけでなくクラスやパッケージのオプションにも key-value リストを利用できるようにするためのしくみが追加されているほか,名前空間の分離をより徹底して行うための工夫等もなされています.
読み込み方法
LaTeX コード中で xkeyval パッケージを利用するためには,\usepackage
または\RequirePackage
命令を用いて xkeyval を読み込む必要があります.パッケージオプションは存在しません.
% 文書ファイル(.tex)等で使用する場合
\usepacakge{xkeyval}
% パッケージファイル(.sty)等で使用する場合
\RequirePacakge{xkeyval}
基本的な考え方
keyval や xkeyval パッケージにおいてキーワード引数を実装するための大まかな流れをまとめると次のようになります.
- キーを定義する
- キーを設定する
- 目的の処理を実行する
はじめのキーを定義するというのは,基本的な key-value リストの構成要素 〈キー〉=〈値〉
における〈キー〉
の文字列を予め定めておくということです.ここで,次のキーを設定するという操作が行われた際の処理も合わせて記述しておきます.具体的なキーの定義方法については次節にて詳述します.
次にキーを設定するという操作ですが,これが「実際に key-value リストを読み込む」段階にあたります.すなわち,リストから〈値〉
を受け取り,その情報を利用してキーの定義時に〈キー〉
と対応付けられた処理を行います.この処理はすべて\setkeys
命令によって行われます.
そして,ここまでに行われた前処理の情報を利用して目的の処理を実行するというのが一般的な流れです3.
キーの定義
汎用キー定義命令
最初に\define@key
命令について説明します.xkeyval パッケージの公式ドキュメントでは「通常キー(ordinary keys)の定義命令」と呼称されていますが,この命令がこれから紹介するすべてのキー定義命令の基本形であり,その気になればこの命令1つでさまざまな種類のキーを実装することが可能なので,本稿では汎用キー定義命令と呼ぶことにします4.
以下に示すのが\define@key
命令の完全な書式です5.
\define@key[〈接頭辞〉]{〈ファミリー〉}{〈キー〉}[〈デフォルト値〉]{〈処理〉}
オプション引数については後述することにして,先に必須の引数について説明します.1つ目の引数には定義する〈キー〉
の属する〈ファミリー〉
を指定するものです.のちに\setkeys
命令を用いて定義したキーの設定を行う際にも,同じ〈ファミリー〉
を指定する必要があります.すなわち〈ファミリー〉
は名前空間をつくるためのしくみで,役割上関連のある〈キー〉
を1つのファミリーにまとめるといいでしょう.
2つ目の引数には定義する〈キー〉
を記入します.この〈キー〉
にはかなり多くの文字種を使うことができますが,特に理由がない限り英数字(および半角スペース)のみからなる文字列にすることを推奨します6.
そして3つ目の引数には〈キー〉
に紐付けられる〈処理〉
,つまり\setkeys
命令でキーの設定を行う際に実行されるコードを記述します.この〈処理〉
の中で#1
を書くと,その部分は key-value リストで記述した〈値〉
に置き換えられます.なお,オプション引数として〈デフォルト値〉
を設定しておくと,=〈値〉
の部分を省略したとしても#1
が〈デフォルト値〉
に置換されます.この〈デフォルト値〉
に関してはプリセットキーに関する節でまた説明します.
通常キーの実装例
ここでは汎用キー定義命令\define@key
を用いた通常キーの実装例を示します.その他の種類のキーの実装例については,次節以降でそれぞれ専用の定義命令の使い方を説明するときに合わせて提示することにします.
さっそくdepend
という通常キーをもつ\myare
命令を定義してみます.なお,以降本稿に掲載するすべてのコード例では,@
が制御綴中で使用できる状況(@
のカテゴリーコードが11)であることを仮定しています.
% スイッチの宣言
\newif\ifdepend@exist
% キーの定義
\define@key{are}{depend}{\def\are@depend{#1}\depend@existtrue}
% \myare 命令の定義
\def\myare#1#2{%
% 初期化:\ifdepend@exist スイッチを OFF
\depend@existfalse
% キーを設定
\setkeys{are}{#2}%
% アレな内容の出力
#1%
\ifdepend@exist
\space\textsc{on}\space\are@depend はもっと
\else
は%
\fi アレ}
上で定義した\myare
命令は2つの省略不能な引数をもちます.1つ目の引数には「〇〇はアレ」というフレーズの〇〇に入れたい文字列を指定します.2つ目の引数はキーワード引数のリストを渡すところですが,上の例ではキーがdepend
しか定義されていないので何も書き込まないかdepend=〈値〉
を書き込むかの2択ということになります.
それでは実際に\myare
命令を使ってみます.
\myare{\TeX}{}\par
\myare{\TeX}{depend=\LaTeX}
\define@key
と\setkeys
の内部動作
\define@key
は内部的に\KV@〈ファミリー〉@〈キー〉
という引数を1つとるマクロを定義します.このマクロがとる引数というのが key-value リストの形で与えられた〈値〉
です.また,\define@key
に与えた〈処理〉
がこのマクロの定義内容となります.すなわち\myare
命令の例では,\define@key
によって次のような定義がなされたことになります.
% \define@key{myare}{depend}{\def\are@depend{#1}\depend@existtrue} の内部動作
\def\KV@myare@depend#1{\def\are@depend{#1}\depend@existtrue}
一方の\setkeys
命令は,与えられた key-value リストをもとに上記のマクロを呼び出します.
% \setkeys{myare}{depend=\LaTeX} の内部動作
\KV@myare@depend{\LaTeX}
これにより,\ifdepend@exist
スイッチが ON になり,さらに\are@depend
が\def\are@depend{\LaTeX}
のように定義されアレな内容が出力される準備が整うというわけです.
ところで,\define@key
によって内部的に定義されるマクロの接頭辞はKV
となっていますが,これは keyval パッケージで定義される\define@key
との互換性を維持するための仕様です.xkeyval の\define@key
がとる最初のオプション引数で〈接頭辞〉
を指定すると,これをKV
以外の文字列に置き換えることも可能です.ただし,その場合は\setkeys
でキーの設定を行う際にも同じ〈接頭辞〉
を指定する必要があります.
% 〈接頭辞〉を指定してキーの定義(内部的に \my@are@depend が定義される)
\define@key[my]{are}{depend}{\def\are@depend{#1}\depend@existtrue}
% 同じ〈接頭辞〉を指定してキーを設定(内部的に \my@are@depend{\LaTeX} が実行される)
\setkeys[my]{are}{depend=\LaTeX}
プリアンブル等でマクロを定義する場合はそれほど気にする必要はないですが,xkeyval を用いてパッケージを開発するというような場合には,接頭辞に KV
を用いると他のパッケージとファミリー名およびキーが被ってしまった際に衝突を起こす可能性があります.そのため〈接頭辞〉にはパッケージ名に因んだ文字列を指定するなどして衝突のリスクを下げるようにするといいでしょう.
コマンドキー定義命令
key-value リストで受け取った〈値〉
はしばしば一旦制御綴に格納されて,あとから参照されます.このように,受け取った値を何らかの制御綴に格納するタイプのキーを xkeyval の用語でコマンドキー(command keys)といいます.
さきほどの\myare
命令におけるdepend
キーは受け取った〈値〉
を\are@depend
に格納しているのでコマンドキーの1種とみなすことができます.すなわちコマンドキーは〈処理〉
に\def
命令を用いたマクロ定義を明示的に記入することによって\define@key
命令を用いて実装することが可能です.しかし,xkeyval パッケージにはより簡潔にコマンドキーを定義できる\define@cmdkey
という専用の命令が用意されています.
\define@cmdkey[〈接頭辞〉]{〈ファミリー〉}[〈マクロ接頭辞〉]{〈キー〉}[〈デフォルト値〉]{〈処理〉}
\define@cmdkey
でも〈ファミリー〉
や〈キー〉
,〈デフォルト値〉
の取り扱い方は\define@key
とまったく同様です.一方で,\define@cmdkey
を使用した場合は〈処理〉
に何も記述しなくても以下のようなマクロ定義が自動的に行われます7.
\def\cmdKV@〈ファミリー〉@〈キー〉{#1} % '#1' は〈値〉(または〈デフォルト値〉)に置換される
ただし〈マクロ接頭辞〉
を指定した場合,自動的に定義されるマクロの形が以下のように変化します.
\def\〈マクロ接頭辞〉〈キー〉{#1} % 〈マクロ接頭辞〉と〈キー〉の間に @ がない点に注意
\define@cmdkey
命令を用いた場合,\myare
のdepend
キーは次のように実装することができます.
% \define@cmdkey 命令による depend キーの実装
\define@cmdkey{myare}[are@]{depend}{\depend@existtrue}
これだけではあまり恩恵が感じられませんが,実際のコマンドキーではマクロに〈値〉
を代入する以外の〈処理〉
が必要ないというケースも多々あります8.こうした場合,\define@cmdkeys
命令を使うことで複数のコマンドキーを簡潔な記述で定義することが可能です.
\define@cmdkeys[〈接頭辞〉]{〈ファミリー〉}[〈マクロ接頭辞〉]{〈キーのリスト〉}[〈デフォルト値〉]
\define@cmdkeys
命令では〈値〉
をマクロに代入する以外の処理をキーと紐付けることはできませんが,大量のシンプルなコマンドキーを定義する場合にその威力を発揮します.
% \define@cmdkeys 命令の使用例
\define@cmdkeys{example}[exp@]{first, second, third}
% 上記を \define@key 命令で実装した場合
\define@key{example}{first}{\def\exp@first{#1}}
\define@key{example}{second}{\def\exp@second{#1}}
\define@key{example}{third}{\def\exp@third{#1}}
選択キー定義命令
これまでに紹介したキーはいずれもユーザが入力した任意の文字列を値として利用するタイプのものでしたが,そうではないキーというものも考えることができます.その1つが選択キーで,これは予め定められたいくつかの選択肢の中から,ユーザが1つを選択して値として指定するというものです.
xkeyval パッケージでこの選択キーを実装するために用意されているコマンドが\define@choicekey
です.
\define@choicekey[〈接頭辞〉]{〈ファミリー〉}{〈キー〉}[〈保存用制御綴〉]{〈選択肢〉}[〈デフォルト値〉]{〈処理〉}
上記書式のうち〈接頭辞〉
,〈ファミリー〉
,〈キー〉
,〈デフォルト値〉
の取り扱いについてはこれまでの場合と同様なので説明を省略します.
残りの必須引数のうち〈選択肢〉
にはユーザが指定することのできる選択肢をカンマ区切りのリストで列挙します.オプション引数〈保存用制御綴〉
には1つまたは2つの制御綴(マクロ)を記入することができます.このうち1つ目の制御綴にはユーザが指定した文字列そのものが格納されます.そして,2つ目の制御綴には,ユーザの指定した文字列が〈選択肢〉
中の $n$ 番目の選択肢と一致するとき $n-1$ の値が保存されます(どの選択肢とも一致しない場合は $-1$ が格納されます).
さて,最後の引数〈処理〉
では,これまで同様#1
を書き込むとユーザの入力そのものを受け取ることが可能ですが,選択キーを実装するにあたっては,この入力そのものを利用するよりも,〈保存用制御綴〉
で2つ目に指定した制御綴を利用して\ifcase
による条件分岐を行う方が簡単です.
なお,この\define@choicekey
にはいくつかバリエーションが存在します.
1つは後ろに*
オプションをつけた形の\define@choicekey*
で,この場合〈保存用制御綴〉
に指定した1つ目の制御綴へのユーザ入力の保存や,2つ目の制御綴に格納する数字の決定を行う際の判定が,ユーザ入力の文字列をすべて小文字化してから行われるようになります.
もう1つは後ろに+
オプションを付けた形の\define@choicekey+
で,この場合は〈処理〉
が2つに分かれて次のような書式となります.
\define@choicekey+[〈接頭辞〉]{〈ファミリー〉}{〈キー〉}[〈保存用制御綴〉]{〈選択肢〉}[〈デフォルト値〉]{〈処理1〉}{〈処理2〉}
ここで〈処理1〉
はユーザ入力が選択肢中に存在する(正しい)場合に実行され,〈処理2〉
はユーザ入力が選択肢中に存在しない(不正な)場合に実行されます.\define@choicekey
命令は*
オプションと+
オプションを同時に指定する\define@choicekey*+
の形でも使用可能です.
% 選択キーの定義
\define@choicekey*+{choice}{are}[\val\nr]{tex,latex,tikz}{%
\ifcase\nr\relax
\TeX
\or
\LaTeX
\or
Ti\textit{k}Z
\fi
はアレ}{\val はアレではありません}
% \myarechoice 命令の定義
\def\myarechoice#1{\setkeys{choice}{are=#1}}
% \myarechoice 命令の使用
\myarechoice{TeX}\par
\myarechoice{ROFF}
真偽キー定義命令
選択キーの特殊なものとして真偽キーというものが考えられます.すなわち選択キーのうち選択肢がtrue
とfalse
の2択である場合,これを真偽キーと呼ぶことにします.xkeyval パッケージではこの真偽キーを定義するために\define@boolkey
というコマンドがあります.
\define@boolkey[〈接頭辞〉]{〈ファミリー〉}[〈マクロ接頭辞〉]{〈キー〉}[〈デフォルト値〉]{〈処理〉}
\define@boolkey
命令では,ユーザの入力は常にすべて小文字化してからtrue
またはfalse
と一致しているかの判定が行われます.
\define@boolkey
を使用すると,\if〈接頭辞〉@〈ファミリー〉@〈キー〉
という形のスイッチが作成されます.そして,\setkeys
命令の実行時にtrue
が指定されていた場合には\iftrue
が,false
が指定されていた場合には\iffalse
が代入された状態になります.ただし,〈マクロ接頭辞〉
が指定されている場合,定義されるスイッチは\if〈マクロ接頭辞〉〈キー〉
の形となります.
ところで,\define@boolkey
ではユーザの入力がtrue
ともfalse
とも一致しない場合には〈処理〉
は実行されず,当該キーは単に無視されます.一方,\define@boolkey
にも\define@choicekey
のように+
オプションが存在し,その場合には書式が以下のように変化して,ユーザ入力がtrue
またはfalse
と一致する場合は〈処理1〉
,そうでない場合は〈処理2〉
が実行されることになります.
\define@boolkey+[〈接頭辞〉]{〈ファミリー〉}[〈マクロ接頭辞〉]{〈キー〉}[〈デフォルト値〉]{〈処理1〉}{〈処理2〉}
また,\define@boolkeys
命令を使用すると,一度に複数の真偽キーを定義することが可能です.
\define@boolkeys[〈接頭辞〉]{〈ファミリー〉}[〈マクロ接頭辞〉]{〈キー〉}[〈デフォルト値〉]
キーのチェックと無効化
キーが存在するかチェックする
\key@ifundefined
命令を用いると,特定のキーが定義されているかどうかチェックすることができます.
\key@ifundefined[〈接頭辞〉]{〈ファミリーのリスト〉}{〈キー〉}{〈未定義の場合の処理〉}{〈定義済みの場合の処理〉}
〈ファミリーのリスト〉
には複数のファミリーをカンマ区切りで指定することができます.指定した〈キー〉
が〈ファミリーのリスト〉
に与えたファミリーのいずれかに存在する場合は〈定義済みの場合の処理〉
として指定した処理が実行され,そうでない場合には〈未定義の場合の処理〉
が実行されます.
キーの無効化
一度定義したキーは,\disable@keys
命令を用いると無効化することが可能です.
\disable@keys[〈接頭辞〉]{〈ファミリー〉}{〈キーのリスト〉}
これにより,以降では指定したキーが使用できなくなります.なお〈キーのリスト〉
には無効化したいキーをカンマ区切りで複数指定することができます.
\setkeys
命令の詳細
\setkeys
命令については既に簡単な説明をしてありますが,ここでさらに詳細な事柄について述べておきます.まず,\setkeys
命令の完全な書式を紹介します.
\setkeys[〈接頭辞〉]{〈ファミリーのリスト〉}[〈処理しないキーのリスト〉]{〈key-value リスト〉}
\setkeys
命令は〈key-value リスト〉
で指定された〈キー〉
のうち
-
〈ファミリーのリスト〉
中のいずれかの〈ファミリー〉
で定義されている -
〈処理しないキーのリスト〉
に含まれていない
ものについてそのキーの設定を行います(つまり\〈接頭辞〉@〈ファミリー〉@〈キー〉
が実行されます).
ここで〈key-value リスト〉
に〈ファミリーのリスト〉
中のどの〈ファミリー〉
でも未定義の〈キー〉
があるとエラーが発生しますが,*
オプション付きの\setkeys*
を用いるとそのような場合でもエラーを起こさないようにすることができます9.
一方,指定された〈キー〉
が〈ファミリーのリスト〉
中の複数の〈ファミリー〉
で定義されている場合には1つ目の〈ファミリー〉
についてこの処理が行われます(したがって〈ファミリーのリスト〉
中の記述順序には意味があります).この挙動は+
オプション付きの\setkeys+
を用いると〈ファミリーのリスト〉
中のすべての〈ファミリー〉
で定義されている〈キー〉
の設定を行うように変更することも可能です.
また,例によって*
オプションと+
オプションは\setkeys*+
のように併用することも可能です.
ポインタ
xkeyval には一度指定された〈値〉
を保存して別のキーへの値として再利用するためのポインタというしくみがあります.これは,素朴には\setkeys
に与える key-value リストの中で\savevalue
命令によって値を保存し,\usevalue
命令によってその値を呼び出す機能です.以下に具体例を示します.
% キーの定義
\define@cmdkeys{ltx}[ltx@]{format, old, new}
% キーの設定
\setkeys{ltx}{
\savevalue{format}=\LaTeX,
old=\usevalue{format} 2.09,
new=\usevalue{format}3}
% 新旧 LaTeX の出力
古い\ltx@old と新しい\ltx@new
ここで\savevalue
および\usevalue
は\setkeys
命令の中でしか使用できません.\usevalue
の引数に指定した〈key〉
に値が保存されていない場合はエラーとなるので注意してください.
さて,上記の例をマクロの形にしなかったのは,この機能を単純に\savevalue
と\usevalue
によって使用する機会はあまりないと思われるからです.もっと実用的なポインタのインターフェースとして,xkeyval には\savevalue
による値の保存操作を自動化する機能が用意されています.
\savekeys[〈接頭辞〉]{〈ファミリー〉}{〈キーのリスト〉}
この\savekeys
命令によって指定した〈キー〉
は,使用する度に\savevalue
を明示的に書かなくても値が保存されるようになります.
また\savekeys
によって値を保存するように指定した〈キー〉
は,\delsavekeys
命令によって値を保存しないように戻すことが可能です.
\delsavekeys[〈接頭辞〉]{〈ファミリー〉}{〈キーのリスト〉}
さらに\unsavekeys
命令を用いると,キーを1つ1つ指定するのではなくファミリーに属するキー全体に対して一括でこの無効化を行うこともできます.
\unsavekeys[〈接頭辞〉]{〈ファミリー〉}
プリセットキー
\define@key
命令などで〈デフォルト値〉
が指定されている場合,キーの使用時に=〈値〉
の記入を省略することができます.具体例として,次のような命令を考えてみます.
% キーの定義
\define@key{trio}{engine}[\TeX]{\def\are@engine{#1}}
\define@key{trio}{format}[\LaTeX]{\def\are@format{#1}}
\define@key{trio}{package}[Ti\textit{k}Z]{\def\are@package{#1}}
% \myaretrio 命令の定義
\def\myaretrio#1{%
% キーを設定
\setkeys{trio}{#1}%
% アレな内容の出力
\are@engine と\are@format と\are@package はアレ}
\myaretrio
命令における3つのキー(engine
, format
, package
)にはすべて〈デフォルト値〉
が設定されているので,それぞれ値を省略して使うことが可能です.
% すべてデフォルト値を利用する場合
\myaretrio{engine, format, package}
% 一部のキーについてのみ値を指定する場合
\myaretrio{engine, format={plain \TeX}, package}
〈デフォルト値〉
を設定しておくと多少労力の節約につながりますが,上記\myaretrio
命令の3キーワード引数などは明らかに常に指定しなければならないものです10.この場合〈デフォルト値〉
を利用する場合には〈キー〉
すら記入せずともキーの設定が行われるようにしたいところです.
xkeyval では,そのような要望に応えるためにプリセットキー(Presetting keys)というしくみが用意されています.すなわちプリセットキーとは\setkeys
によるキー設定時に key-value リストに〈キー〉
が記述されるか否かを問わず常に設定が行われるキーを指します.
既存のキーをプリセットキーとして扱えるようにするには\presetkeys
命令を使用します.
\presetkeys[〈接頭辞〉]{〈ファミリー〉}{〈前処理する key-value リスト〉}{〈後処理する key-value リスト〉}
これにより\setkeys
で〈ファミリー〉
に属するキーの設定を行う際,ユーザが\setkeys
の引数に入力した key-value リストよりも前に〈前処理する key-value リスト〉
が処理され,さらにユーザ入力の key-value リストの処理後に〈後処理する key-value リスト〉
が処理されます.
したがって先の例では
% プリセットキーの設定
\presetkeys{trio}{engine, format, package}{}
のようにプリセットキーを設定しておけば
% すべてデフォルト値を利用する場合
\myaretrio{}
% 一部のキーについてのみ値を指定する場合
\myaretrio{format={plain \TeX}}
でまったく同じ出力を得ることができるようになります.
なお\presetkeys
命令を同じ〈ファミリー〉
について複数回実行した場合には設定は順次更新されていきます.
また,一度\presetkeys
でプリセットキーに指定した〈キー〉
を普通の(プリセットキーでない)キーに戻すには\delpresetkeys
を使用します.
\delpresetkeys[〈接頭辞〉]{〈ファミリー〉}{〈前処理キーのリスト〉}{〈後処理キーのリスト〉}
さらに\unpresetkeys
命令を用いると,キーを1つ1つ指定するのではなくファミリーに属するキー全体に対して一括でこの無効化を行うこともできます.
\unpresetkeys[〈接頭辞〉]{〈ファミリー〉}
パッケージオプション
xkeyval パッケージには通常のマクロだけでなくクラスやパッケージのオプションでも key-value リストを利用できるようにするためのしくみがあります11.元々,パッケージオプションを扱うためのしくみと key-value リストを扱うためのしくみはかなり似ているので,「普通のパッケージオプション」を実装したことのある人ならばその方法の習得は容易でしょう.ただし,ここでは念のため普通のパッケージオプションの実装方法も簡単に復習しておきます.
普通のパッケージオプション
クラスやパッケージで使用可能なオプションは,まず LaTeX の\DeclareOption
命令によって宣言されている必要があります.この命令の書式は次の通りです.
\DeclareOption[〈オプション〉]{〈処理〉}
このマクロによって〈オプション〉
に対して〈処理〉
が関連付けられます.その上で,ここで関連付けられた〈処理〉
を実際の実行に移します.これは多くの場合2段階に分けて行われます.具体的には,まず\ExecuteOptions
命令によって先に “デフォルト” のオプションを実行します.
\ExecuteOptions{〈オプションのリスト〉}
この命令は〈オプションのリスト〉
に直接記述した〈オプション〉
に関連付けられている〈処理〉
を実行するので,結果として〈オプションのリスト〉
に書かれたオプションがデフォルトとして適用された状態になります.
そして最後に\ProcessOptions
命令によって\usepackage
のオプション引数等でユーザが指定したオプションの〈処理〉
を実行する,というのが一連の流れです12.
\ProcessOptions\relax
key-value リストのパッケージオプション
key-value リストを扱うパッケージオプションを作る方法も基本的には「普通のパッケージオプション」と変わりません.ただし,命令はすべて末尾にX
の付くもの(\DeclareOptionX
, \ExecuteOptionsX
, \ProcessOptionsX
)を用います.
オプションの宣言
key-value リスト式のパッケージオプションを宣言するには\DeclareOptionX
命令を使用します.もう察しがついていることと思いますが,この命令は\define@key
と\DeclareOption
の機能を併せ持つような命令で,次のようなちょっと変わった書式をもちます.
\DeclareOptionX[〈接頭辞〉]<〈ファミリー〉>{〈キー〉}[〈デフォルト値〉]{〈処理〉}
それぞれの引数の意味や取り扱いは,基本的に\define@key
と同様です.ここで〈キー〉
はパッケージオプションとして使えるもので,〈処理〉
中において記述される#1
は当該キーに〈キー〉=〈値〉
として与えられた値に置換されます.
なお\DeclareOptionX
における<〈ファミリー〉>
は変則的な形をしていますが省略可能なオプション引数です.この〈ファミリー〉
はパッケージオプションと共通の〈キー〉
を通常のマクロや環境でも利用したい場合に指定します.それ以外の場合は特に記入しなくていいでしょう(その場合は自動的にデフォルトのファミリー名が割り当てられます).
オプションの処理
一方 key-value 式のパッケージオプションは\ExecuteOptionsX
と\ProcessOptionsX
によって処理されます.まず一般的には\ExecuteOptionsX
によってデフォルトのオプションの設定が行われます.この命令はもちろん\setkeys
と\ExecuteOptions
の間の子のような機能を持ちます.
\ExecuteOptions[〈接頭辞〉]<〈ファミリーのリスト〉>[〈処理しないキーのリスト〉]{〈key-value リスト〉}
今度の<〈ファミリーのリスト〉>
も省略可能なオプション引数です.\setkeys
と同じ要領で〈key-value リスト〉
に含まれる〈キー〉
が処理されて,デフォルトオプションとして設定されます.
最後にユーザが指定したオプションを\ProcessOptionsX
で処理すれば key-value リストを使用したパッケージオプションの設定は完了です.
\ProcessOptionsX[〈接頭辞〉]<〈ファミリーのリスト〉>[〈処理しないキーのリスト〉]
おわりに
xkeyval パッケージの豊富な機能の中でも,特に有用と思われる部分を厳選して解説したつもりでしたが,思った以上にボリュームのある記事になってしまいました.これはそれだけ xkeyval が機能豊富なパッケージであるということの証左でもあります.
皆さんも是非,この強力な xkeyval パッケージを利用して key-value リストを扱うステキな LaTeX マクロを作ってみてください.
-
本稿は2016年11月現在最新の xkeyval v2.7a のドキュメントに基づいて執筆されています. ↩
-
LaTeX のパッケージ制作に必要な基本的な知識については TeX ユーザの集い2016の一般講演『パッケージ制作のすゝめ』の発表資料にまとめてあります. ↩
-
後述するようにキーに紐付けられる処理は様々なので,必ずキーの設定を行ってから目的の命令が実行されるというわけではありません.キーの設定と目的の処理の実行が同時である場合や,処理の一部が実行されてからキーが設定されるようなケースも考えられます. ↩
-
実際,keyval パッケージにはキー定義命令はこの1種しか存在しないため,変種を含むすべてのキーワード引数を
\define@key
で実装する必要があります. ↩ -
keyval パッケージの
\define@key
命令には1つ目のオプション引数[〈接頭辞〉]
は存在しません. ↩ -
特に
@
を含めると xkeyval の実装上本来であれば名前空間の分離されている(〈接頭辞〉
または〈ファミリー〉
の異なる)キーと衝突を起こすリスクを生じるので,極力避けるべきです. ↩ -
これは
〈接頭辞〉
が指定されていない場合の形です.〈接頭辞〉
を指定した場合KV
の部分は指定した〈接頭辞〉
に置換されます. ↩ -
\myare
命令のdepend
キーも予め\def\are@depend{}
のように初期化しておき,キーの設定後に\ifx\are@depend\@empty
を用いて条件分岐を行うなどの工夫をすることで\ifdepend@exist
スイッチを利用せずに実装することが可能です. ↩ -
このとき未定義の
〈キー〉
(およびそれに与えられた〈値〉
)は単に無視されるのではなく,それらを集めた key-value リストが\XKV@rm
という制御綴の中に格納されます.この key-value リストは\setrmkeys
命令によってさらに処理を行うことも可能です. ↩ -
前述の
\myaretrio
命令の定義では,キーの指定を省略するとそれが初回使用時である場合には\are@engine
等の命令が未定義で使用されるためエラーとなり,2回目以降の使用である場合には前回使用した値が引き継がれるという非常に厄介な挙動を示すことになります. ↩ -
話を単純化するため,本稿ではクラスオプションを扱う話は省略します. ↩
-
\ProcessOptions
は*
オプション付きで\ProcessOptions*
という形で使用することも可能なので(オプションの処理順が異なるようです)*
がないことを明示するためには\relax
命令を後置して使うのが一般的です. ↩