l3keys の紹介
これは、TeX & LaTeX Advent Calendar 2021 の 18 日目の記事です。昨日は mattskala さんの「MakeでLaTeX言語のビルドしましょう」でした。明日は hid_alma1026 さんの「Speedata Publisherのマークアップ」です。
l3keys とは、expl3 のモジュールで、keyval リストのインターフェイスを実現します。keyval リストとは、カンマ区切りで <キー>=<値>
が連なるリストのことで、graphicx パッケージのオプション指定がそれです。
\includegraphics[width=2cm,height=3cm]{sample.pdf}
同じ目的のパッケージとして、他に keyval や xkeyval がありますが、l3keys はキーの定義も keyval リストなため、それと比べて大変使いやすいものになっています。
この記事では、2021-06-18 リリースの expl3 を基に解説します。公式のリファレンスは interface3.pdf
で、この記事の情報も全てこれによるものです。
前提知識
この記事では、expl3 についての説明は行いません。解説としては、以下の記事が大変分かりやすいです。
- TeX 言語者のための expl3 入門
- 講演『expl3 入門』の補足
- expl3 の標準データ構造 (1) seq
- expl3 の標準データ構造 (2) prop, clist
- LaTeX3: Programming in LaTeX with Ease
基本的な使い方
以下、特に説明がない限り、\ExplSyntaxOn
\ExplSyntaxOff
が適切に行われた状態であると仮定します。
l3keys では、\keys_define:nn
命令を使って、モジュールごとにキーを定義します。例えば、
\keys_define:nn { example }{
name .code:n = \hoge{ #1 },
police .int_set:N = \l_tmpa_int
}
のようにすると、example
モジュールに対して、
- キーが指定された時に
\hoge { #1 }
が実行される(#1
はキーに指定された値が入る)name
キー - 指定された値が
\l_tmpa_int
に代入される、police
キー
の 2 つのキーが定義されます。
キーを使用するには、\keys_set:nn
命令を使います。
\keys_set:nn { example }{
name = tokyo, % => \hoge{ tokyo } が実行される
police = 1000 % => \l_tmpa_int に 1000 が代入される
}
実際にパッケージの機能として提供する場合は、xparse パッケージなどを用いて、
\NewDocumentCommand{ \my }{ m }{
\keys_set:nn { example }{ #1 }
}
のように使う事が出来ます。
キーの定義
前述の例で見たように、<モジュール>
に対して、
\keys_define:nn { <モジュール> }{
<キー> <プロパティ> = <値>,
...
}
の形で定義します。キーは必ずプロパティを持ち、プロパティは <値>
を引数として取ります
(例外あり)。キー名に使える文字の制限はありません。なお、キーは記述された順序で定義されるため、重複・矛盾する定義は後のものに上書きされます。
プロパティには、主なものとして、
- 変数に値を代入するプロパティ(
.tl_set:N
など) - 関数を定義するプロパティ(
.cs_set:Np
など) - 選択キーを定義するプロパティ(
.choice:
など)
があります。
1. 変数に値を代入するプロパティ
<キー> <プロパティ> = <変数>
<キー>
に指定された値を <変数>
に代入します。<プロパティ>
は基本的に通常の変数代入の命令と同じ名前です。変数が定義されていない場合、グローバルに定義されます。
\keys_define:nn { example }{
bool .bool_set:N = \l_tmpa_bool,
clist .clist_set:N = \l_tmpa_clist,
dim .dim_set:N = \l_tmpa_dim,
fp .fp_set:N = \l_tmpa_fp,
int .int_set:N = \l_tmpa_int,
muskip .muskip_set:N = \l_tmpa_muskip,
prop .prop_put:N = \l_tmpa_prop,
skip .skip_set:N = \l_tmpa_skip,
tl .tl_set:N = \l_tmpa_tl
}
2. 関数を定義するプロパティ
<キー> <プロパティ> = <関数>
<キー>
に指定された値(コード)が <関数>
の定義になります。<関数>
が定義されていない場合、グローバルに定義されます。下の例の場合、\__tmpa_fn:n
が こんにちは、#1さん
として定義されます(関数などの定義中で用いる場合は、#
を必要なだけ重ねる必要があります)。
\keys_define:nn { example }{
key .cs_set:Np = \__tempa_fn:n #1
}
\keys_set:nn { example }{
key = こんにちは、#1さん
}
\__tmpa_fn:n { 山田 } % => こんにちは、山田さん
また、.cs_set:cp
を使う場合は、
\keys_define:nn { example }{
key .cs_set:cp = { __tempa_fn:n } #1
}
のようにします。
3. 選択キーを定義するプロパティ
選択キーとは、キーに指定する値が選択肢として事前に用意されたキーのことです。例えば、jlreq クラスの paper
キーは、a4
や b4
などの選択肢が事前に用意されており、用意されていないものを指定するとエラーが出ます。
\documentclass[paper=b4]{jlreq}
\documentclass[paper=x3]{jlreq} % => ! Class jlreq Error: The paper x3 is unknown.
選択キーを定義する方法は 3 つあります。.choice:
又は .choices:nn
は 1 つだけキーを指定するタイプで、.multichoices:nn
は複数のキーを指定するタイプです。
.choice:
プロパティ
<キー> .choice:,
<キー> / <サブキー> <プロパティ> = <値>
.choice:
プロパティは <キー>
を選択キーとして定義し、<値>
を取りません。選択肢となるキーは、サブキーによって作られます。<サブキー>
は <キー>/<サブキー>
とすることで定義出来ます。
下の例では、key
が選択キーとして、a
b
c
が key
のサブキーとして定義され、a
b
c
を key
の選択肢として指定できます。
\keys_define:nn { example }{
key .choice:,
key / a .code:n = キー「a」が選択されました,
key / b .code:n = キー「b」が選択されました,
key / c .code:n = キー「c」が選択されました
}
\keys_set:nn { example }{
key = b % => キー「b」が選択されました
}
.choices:nn
プロパティ
機能としては、.choice:
と同じです。
<キー> .choices:nn = { <キーの選択肢> }{ <コード> }
インデックス[1]が \l_keys_choice_int
に、キー名が \l_keys_choice_tl
に代入され、<コード>
で使用できます。
下の例では、1番目の「a」が選択されました。
と出力されます。
\keys_define:nn { example }{
key .choices:nn = { a, b, c }{
\int_use:N\l_keys_choice_int 番目の
「\tl_use:N\l_keys_choice_tl」が選択されました。
}
}
\keys_set:nn { example }{
key = a % => 1番目の「a」が選択されました。
}
.multichoices:nn
プロパティ
.choice:
や .choices:nn
では 1 つのキーしか選べませんが、.multichoices:nn
では複数のキーを選べます。書式は、.choices:nn
と全く同じで、
<キー> .multichoices:nn = { <キーの選択肢> }{ <コード> }
です。<コード>
はキーごとに実行されます。インデックス[1:1]やキー名も同様に使用できます。
以下の例では、1番目の「a」が選択されました。3番目の「c」が選択されました。
と出力されます。
\keys_define:nn { example }{
key .multichoices:nn = { a, b, c }{
\int_use:N\l_keys_choice_int 番目の
「\tl_use:N\l_keys_choice_tl」が選択されました。
}
}
\keys_set:nn { example }{
key = { a, c }
% 又は
% key = a,
% key = c
}
その他のプロパティ
この記事で扱わなかったプロパティのうち、便利なものを簡単に紹介します。他にも多くの機能があるので、interface3.pdf
をぜひ見てください。
プロパティ | 指定する値 | 説明 |
---|---|---|
.default:n |
デフォルト値 | デフォルト値を設定する |
.value_forhidden:n |
真偽値 |
<値> を隠し、キーだけで指定できるようにする |
.value_required:n |
真偽値 |
<値> が指定されていない時に、エラーが出るようにする |
.code:n |
コード | キーが指定された時にコードを実行する。指定した値は #1 に入れられる |
Discussion