Folks,
I’ve been following the code changes here, and I’ve asked two
questions on this topic on TeX.SE (“Generate l3keys meta key from
subkey” <http://tex.stackexchange.com/q/120102/2966> and “Can I refer
to key value in general code?”
<http://tex.stackexchange.com/q/120258/2966>), but I think I need some
direction on this.
Here‘s my use-case: I’ve got a résumé class with a set of pre-defined
layout options. For example, for Constantia I want
\DeclareDocumentCommand \& {} { \textit { \jcsres_ampersand: } }
while for Fontin I’ve decided on
\DeclareDocumentCommand \& {} { \textsc { \jcsres_ampersand: } }
instead. Packages need to be included. And so on and so forth; there
are between three and fifteen lines of code for each font-set option.
Based on egreg’s suggestion
(http://tex.stackexchange.com/a/120275/2966), my code looks something
like this (or will, when the new Expl3 updates become available):
\bool_if:nTF { \xetex_if_engine_p: || \luatex_if_engine_p: }
{ \clist_const:Nn \c_jcs_fonts_clist { fontin, constantia, lmodern } }
{ \clist_const:Nn \c_jcs_fonts_clist { kpfonts, lmodern } }
\clist_get:NN \c_jcs_fonts_clist \c_jcs_default_font_tl
\keys_define:nn { jcsres }
{
font .choices:Vn = \c_jcs_fonts_clist
{ \tl_gset:NV \g_jcs_font_option_tl \l_keys_choice_tl },
font .initial:V = \c_jcs_default_font_tl,
font .value_required,
font / unknown .code:n =
{ \msg_warning:nnn { jcsres } { unknown-font-option } { #1 } }
}
\msg_new:nnn { jcsres } { unknown-font-option }
{ unknown~font~option~`#1';~using~`\c_jcs_default_font_tl'~instead }
\clist_map_inline:Nn \c_jcs_fonts_clist
{
\keys_define:nn { jcsres }
{ #1 .meta:n = { font = #1 }, #1 .value_forbidden: }
}
% Somewhere later in the code...
\ProcessKeysOptions { jcsres }
% Somewhere later yet...
\str_case:VnF \g_jcs_font_option_tl
{
{ fontin } { … }
{ constantia } { … }
{ lmodern } { … }
{ kpfonts } { … }
}
{ \msg_error:nnn { jcsres } { still-unknown-font-option } { #1 } }
\msg_new:nnn { jcsres } { still-unknown-font-option }
{ can't~happen:~unknown~font~option~`#1'. }
This all works, but there’s a fair amount of repetition of information.
Bruno has suggested (http://tex.stackexchange.com/a/123201/2966) using
property lists instead. This feels like a more natural fit for the
problem, and here’s the code I’ve come up with:
\prop_new:N \g_jcs_fontcode_prop
\prop_gput:Nnn \g_jcs_fontcode_prop { lmodern } { … }
\bool_if:nT { \xetex_if_engine_p: || \luatex_if_engine_p: }
{ \prop_gput:Nnn \g_jcs_fontcode_prop { fontin } { … } }
\bool_if:nT { \xetex_if_engine_p: || \luatex_if_engine_p: }
{ \prop_gput:Nnn \g_jcs_fontcode_prop { constantia } { … } }
\bool_if:nF { \xetex_if_engine_p: || \luatex_if_engine_p: }
{ \prop_gput:Nnn \g_jcs_fontcode_prop { kpfonts } { … } }
\tl_const:Nx \c_jcs_default_font_tl
{
\bool_if:nTF { \xetex_if_engine_p: || \luatex_if_engine_p: }
{ fontin } { kpfonts }
}
\tl_new:N \l_jcs_fontcode_tl
\keys_define:nn { jcsres }
{
font .code:n =
{
\prop_get:NnNTF \g_jcs_fontcode_prop {#1} \l_jcs_fontcode_tl
{ \tl_gset_eq:NN \g_jcs_fontcode_tl \l_jcs_fontcode_tl }
{
\msg_warning:nnn { jcsres } { unknown-font-option } { #1 }
\prop_get:NVN \g_jcs_fontcode_prop \c_jcs_default_font_tl
\l_jcs_fontcode_tl
\tl_gset_eq:NN \g_jcs_fontcode_tl \l_jcs_fontcode_tl
}
},
font .value_required:,
font .initial:V = \c_jcs_default_font_tl
}
\prop_map_inline:Nn \g_jcs_fontcode_prop
{
\keys_define:nn { jcsres }
{ #1 .meta:n = { font = #1 }, #1 .value_forbidden: }
}
% Somewhere later in the code...
\ProcessKeysOptions { jcsres }
\tl_use:N \g_jcs_fontcode_tl
The trick with copying the code sequence (rather than executing it
within the call to \keys_define) is needed so the default code isn’t
run if an option is supplied, or in case the user writes
\usepackage[font=fontin, font=constantia]{jcsres}
to execute both conflicting options.
Does this begin to sound like the way forward?
—Joel
|