2

I believe I am looking for a LaTeX3 type syntax solution to more appropriately detect a missing argument. To me I would have expected key={} to be a valueless, blank, or empty argument key. After searching through questions I expected \tl_if_blank:nF and IfNoValueF to be my best bet, but either my key variable is not a compatible argument for these functions, or the key has to fail to be produced in order to return a TRUE on these functions. In the MWE below, I can tell it is still being executed because of the extra lines that get included.

I know it would be better if I could avoid including the keys when blank, but at the moment this is out of my control as someone else is responsible for the script that is parsing a database into the content filled syntax block simulated below in \SampleBlock. So I am trying to detect an empty key value but it's not working as I expected.

MWE:

\documentclass[10pt]{article}

\usepackage{xparse}

%--------------------New Commands for consistent formatting ---------------
\ExplSyntaxOn

% define the variable before using it:
\tl_new:N \l_heading_tl
\tl_new:N \l_subheading_tl
\tl_new:N \l_paragraph_tl

% define key:    
\keys_define:nn { Sample }
{
    key-heading                 .tl_set:N = \l_heading_tl
,   key-subheading              .tl_set:N = \l_subheading_tl
,   key-paragraph               .tl_set:N = \l_paragraph_tl
}


\DeclareDocumentCommand{\SampleBlock}{ o }
{
    %TODO some residual debugging may be needed for omitted keys
    \group_begin:% start a group to keep key setting local:
    % set keys if optional argument #1 is given:
    \IfNoValueF {#1} { \keys_set:nn {Sample} {#1} }

    \IfNoValueF{\l_heading_tl}{\noindent\textbf{\l_heading_tl} \\} 
    \IfNoValueF{\l_subheading_tl}{\emph{\l_subheading_tl} \\}    

    \tl_if_blank:nF{\l_paragraph_tl}{\l_paragraph_tl}

    \group_end:
}

\ExplSyntaxOff

%--------------------BEGIN DOCUMENT----------------------
\begin{document}

\SampleBlock[%
key-heading={Title here},
key-subheading={Sub Heading here},
key-paragraph={A paragraph of text will go here.  Maybe I will say hello world, maybe I will describe how the quick brown fox jumped over the lazy brown dog.  Really, the possibilities are endless.  Oh wait, I could have used lipsum.  Doh!}]   

\medskip \medskip\medskip \medskip\medskip \medskip

\SampleBlock[%
key-heading={No subheading but there will still be a space for it on the next line...},
key-subheading={},
key-paragraph={A paragraph of text will go here.  Maybe I will say hello world, maybe I will describe how the quick brown fox jumped over the lazy brown dog.  Really, the possibilities are endless.  Oh wait, I could have used lipsum.  Doh!}]   

\end{document}
EngBIRD
  • 3,985

1 Answers1

2

\IfNoValue(TF) is used to test the presence or absence of an o argument. It has nothing to do with checking the emptiness of a token list variable, for which you have to use \tl_if_blank:V(TF). The notation (TF) means you can use TF, T or F (or nothing at all, in some cases, not this one).

Note that \tl_if_blank:nTF { \l_tmpa_tl } would always return false, because the given token list is not blank, as it contains a non space token. When you do

\tl_clear:Nn \l_tmpa_tl
\tl_if_blank:VTF \l_tmpa_tl {TRUE} {FALSE}

would return true.

\documentclass[10pt]{article}

\usepackage{xparse}

%--------------------New Commands for consistent formatting ---------------
\ExplSyntaxOn

% define the variable before using it (not really necessary)
%\tl_new:N \l_engbird_heading_tl
%\tl_new:N \l_engbird_subheading_tl
%\tl_new:N \l_engbird_paragraph_tl

% define key:    
\keys_define:nn { Sample }
 {
  key-heading    .tl_set:N = \l_engbird_heading_tl,
  key-subheading .tl_set:N = \l_engbird_subheading_tl,
  key-paragraph  .tl_set:N = \l_engbird_paragraph_tl,
}

\DeclareDocumentCommand{\SampleBlock}{ O{} }
 {
  %TODO some residual debugging may be needed for omitted keys
  \group_begin:% start a group to keep key setting local:
  % set keys if optional argument #1 is given:
  \keys_set:nn {Sample} {#1}

  \tl_if_blank:VF \l_engbird_heading_tl {\noindent\textbf{\l_engbird_heading_tl} \\} 
  \tl_if_blank:VF \l_engbird_subheading_tl {\emph{\l_engbird_subheading_tl} \\}    

  \tl_if_blank:VF \l_engbird_paragraph_tl {\l_engbird_paragraph_tl}

  \group_end:
 }

\ExplSyntaxOff

%--------------------BEGIN DOCUMENT----------------------
\begin{document}

\SampleBlock[%
key-heading={Title here},
key-subheading={Sub Heading here},
key-paragraph={A paragraph of text will go here.  Maybe I will say hello world, maybe I will describe 
how the quick brown fox jumped over the lazy brown dog.  Really, the possibilities are endless.  Oh 
wait, I could have used lipsum.  Doh!}]

\bigskip

\SampleBlock[%
key-heading={No subheading but there will still be a space for it on the next line...},
key-subheading={},
key-paragraph={A paragraph of text will go here.  Maybe I will say hello world, maybe I will describe 
how the quick brown fox jumped over the lazy brown dog.  Really, the possibilities are endless.  Oh 
wait, I could have used lipsum.  Doh!}]

\end{document}

Note that \IfNoValueF{#1} for setting keys is redundant: setting no key is as good as doing nothing.


Further notes

You can have three cases for a key, let's call it foo at point of use:

  1. The key is not specified
  2. You specify foo
  3. You specify foo=...

For simplicity, let's assume you always set keys in a group, like in your example. When you define the key with

foo .tl_set:N = \l_whatever_foo_tl,

(or another key definition command), you can add also

foo .initial:n = INITIAL~VALUE,
foo .default:n = DEFAULT~VALUE,

The right-hand sides are empty by default. What's the difference?

  1. The key foo is not set at point of use: the value used for \l_whatever_foo_tl will be INITIAL~VALUE.

  2. The key foo appears without an equals sign: the value used for \l_whatever_foo_tl will be DEFAULT~VALUE.

  3. The user does foo=Something: the value used for \l_whatever_foo_tl will be Something.

Another thing to note: when you have

foo .tl_set:N = \l_whatever_foo_tl,

in \keys_define:nn, the variable in the right-hand side is automatically declared, so it's not necessary to have a \tl_new:N declaration beforehand (but it doesn't harm either).

egreg
  • 1,121,712
  • Perhaps note that key = {} is not the same as just key? – Joseph Wright Nov 26 '15 at 09:06
  • @JosephWright There is no key without an equals sign in the example. The key-subheading={} bit can be omitted, as the corresponding token list is empty by default. – egreg Nov 26 '15 at 09:58
  • Yes I know, but the OP is suggesting that key = {} means that no value has been given, whereas it has (an empty value). – Joseph Wright Nov 26 '15 at 10:06