% !TEX program  = pdflatex
% 
% This is a test file demonstrating the keys3 experimental LaTeX3 
% package. This file illustrates the methods made available by keys3
% for managing key-value input. It also acts as a check, as almost all
% of the keys3 methods are used (with known output) and because a number
% of errors are deliberately raised.

\documentclass{article}
\usepackage{keys3,xparse}
\usepackage[parfill]{parskip}

% The document commands for using keys is very simple.

\ExplSyntaxOn
\DeclareDocumentCommand \SetModuleKeys { m } {
  \keys_set:nn { module } {#1}
}
\ExplSyntaxOff

\begin{document}

% Each test starts with a short piece of text explaining the property
% being used. Under this, the expected output is given, followed
% if relevant by the text of any error messages expected.

% Test one: Simply creating a key with one argument and then using it.
% Notice that the text length determines the limits of the argument: 
% spaces at either end are ignored. Literal spaces between text are 
% counted, as are those enclosed in braces.
% ----------------------------------------------------------------------
%   You said: `Hello World'
%   You said: ` Hello World '
%   You said: `'
% ----------------------------------------------------------------------
\ExplSyntaxOn
\keys_show:nn { module } {unknown}
\keys_set:nn { module } {
  clive = india
}
\keys_define:nn { module } {
  key .code:n = {You~said:~`#1'\\}
}
\ExplSyntaxOff

\SetModuleKeys{
  key = Hello World ,
  key = { Hello World },
  key 
}

% Test two: Creating a multiple-argument key. Here, the arguments
% given need to be at least as many as those required by the code!
% ----------------------------------------------------------------------
%   You said: `A', `B', `C', D'.
%   You said: `AAA', `BBB', `CCC', ` DDD'.
% ----------------------------------------------------------------------
\ExplSyntaxOn
\keys_define:nn { module } {
  key .code:Nn = 4 {You said:~`#1',~`#2',~`#3',~`#4'.\\},
}
\ExplSyntaxOff

\SetModuleKeys{
  key = ABCD,
  key = {AAA}{BBB} {CCC} { DDD}
}

% Test three: Variants of .code:n and .code:Nn exist which carry out a
% full expansion on code definition. First the :x variant is tested.
% ----------------------------------------------------------------------
%   Temp holds: ABC
%   Temp hold: 123
% ----------------------------------------------------------------------
\newcommand*{\temp}{123}

\ExplSyntaxOn
\keys_define:nn { module } {
  key-one .code:n = Temp~holds:~\temp\\,
  key-two .code:x = Temp~holds:~\temp,
}
\ExplSyntaxOff

\renewcommand*{\temp}{ABC}

\SetModuleKeys{
  key-one,
  key-two
}

% Now the :Nx version
% ----------------------------------------------------------------------
%   Arguments: A, B. Temp holds: ABC
%   Arguments: 1, 2. Temp hold: 123
% ----------------------------------------------------------------------
\renewcommand*{\temp}{123}

\ExplSyntaxOn
\keys_define:nn { module } {
  key-one .code:Nn = 2 {Arguments:~#1,~#2.~Temp~holds:~\temp\\},
  key-two .code:Nx = 2 {Arguments:~#1,~#2.~Temp~holds:~\temp},
}
\ExplSyntaxOff

\renewcommand*{\temp}{ABC}
\SetModuleKeys{
  key-one = {A} {B},
  key-two = {1} {2}
}

% Test four: Values can be required and forbidden with the 
% .value_required: and .value_forbidden: properties.
% ----------------------------------------------------------------------
%   All okay
%   All okay
% ----------------------------------------------------------------------
% The key `module/key-one' cannot taken a value:
% the given input `Not allowed' is being ignored.
% 
% The key `module/key-two' requires a value 
% and is being ignored.
% ----------------------------------------------------------------------
\ExplSyntaxOn
\keys_define:nn { module } {
  key-one .code:n = All okay\\,
  key-one .value_forbidden:,
  key-two .code:n = #1,
  key-two .value_required:
}
\ExplSyntaxOff

\SetModuleKeys{
  key-one,
  key-one = Not allowed,
  key-two = All okay,
  key-two
}

% Test five: Keys can be given a default value, to be used if nothing is
% specified by the user. This can be done by name or by value.
% ----------------------------------------------------------------------
%   Default
%   Real
%   Stuff
%   Real
%   Literal
%   Real
% ----------------------------------------------------------------------
\ExplSyntaxOn
\renewcommand*{\temp}{Stuff}
\keys_define:nn { module } {
  key-one .code:n      =  #1\\,
  key-one .default:n   = \temp,
  key-two .code:n      =  #1\\,
  key-two .default:V   = \temp,
  key-three .code:n    =  #1\\,
  key-three .default:n = Literal,
}
\ExplSyntaxOff
\renewcommand*{\temp}{Default}

\SetModuleKeys{
  key-one,
  key-one = Real,
  key-two,
  key-two = Real,
  key-three,
  key-three = Real
}

% Test six: Keys can be created to store data both locally and 
% globally. This is illustrated using token list variables.
% ----------------------------------------------------------------------
%   Some content
%   Outside
%   Some content
%   Some content
% ----------------------------------------------------------------------
\ExplSyntaxOn
\tl_new:Nn \l_temp_tl {Outside}
\tl_new:Nn \g_temp_tl {Outside}
\keys_define:nn { module } {
  key-one .set:N = \l_temp_tl,
  key-two .set:N = \g_temp_tl,
}

\begingroup
\SetModuleKeys{
  key-one = Some~content
}
\l_temp_tl\\
\endgroup
\l_temp_tl\\

\begingroup
\SetModuleKeys{
  key-two = Some~content
}
\g_temp_tl\\
\endgroup
\g_temp_tl\\
\ExplSyntaxOff

% Test seven: An expanded version of .set:N is available.
% ----------------------------------------------------------------------
%   Unexpanded
%   Expanded
% ----------------------------------------------------------------------
\ExplSyntaxOn
\tl_set:Nn \l_temp_tl {Expanded}
\tl_new:N \l_tempa_tl 
\tl_new:N \l_tempb_tl 
\keys_define:nn { module } {
  key-one .set:N   = \l_tempa_tl,
  key-two .set_x:N = \l_tempb_tl,
}

\SetModuleKeys{
  key-one = \l_temp_tl,
  key-two = \l_temp_tl,
}
\tl_set:Nn \l_temp_tl {Unxpanded}
\l_tempa_tl\\
\l_tempb_tl\\

\ExplSyntaxOff

% Test eight: Choices can be created either from a list of options or
% one by one. Both are tested here by creating a list then adding to it
% with an extra key. Unknown choices lead to an error message.
% ----------------------------------------------------------------------
% Choice `a' is number 1
% Choice `b' is number 2
% Choice `c' is number 3
% An extra choice
% ----------------------------------------------------------------------
% Choice `e' unknown for key `module/key':
% the key is being ignored.
% ----------------------------------------------------------------------
\ExplSyntaxOn
\keys_define:nn { module } {
  key .generate_choices:nn = {a,b,c} {
    Choice~`\l_keys_choice_tl'~is~number~\int_use:N \l_keys_choice_int\\
  },
  key/d .code:n = An~extra~choice \\
}
\ExplSyntaxOff

\SetModuleKeys{
  key = a,
  key = b,
  key = c,
  key = d,
  key = e
}

% Test nine: A completely unknown key should cause an error.
% ----------------------------------------------------------------------
% The key `module/unknown key' is unknown and is being ignored.
% ----------------------------------------------------------------------
\SetModuleKeys{
  unknown key = some value
}

% Test ten: If the special `unknown' key has been set up, however,
% unknown input can be re-directed.
% ----------------------------------------------------------------------
% You tried to set key `unknown key' to `some value'
% ----------------------------------------------------------------------
\ExplSyntaxOn
\keys_define:nn { module } {
   unknown .code:n = You~tried~to~set~key~`\l_keys_key_tl'~to~`#1'
}
\ExplSyntaxOff

\SetModuleKeys{
  unknown key = some~value
}


\end{document}

