4

I try to make just a very minimalist example of pgfkeys — or other keystyle parameters package —, with a command like this one:

\mycommand{title="The new book", author="John Doe"}

to get a behavior like this:

Writer John Doe

Title The new book

And, possibly, if on key is missing, it line will not appear. For example, the command

\mycommand{title="The new book"}

Will only print:

Title The new book

I check in the web and also StackExchange but I only find very complicated examples including so much other things not directly related to key-value syntax.

So, how can I just put such a minimal key-value command?

  • well this is not really a "minimal" command. Beside setting up the keyval syntax you also need code to test for empty values, and to store the fix words (Writer, Title). Beside this your question is missing where you want to use this command, if the formatting should use a description list or something else and if there will be more keys ... – Ulrike Fischer May 12 '20 at 12:57
  • What is the expected behavior if one of the keys is empty (ex: \mycommand{title=The new book,author=}? What if both are missing or empty (ex: \mycommand{})? – Paul Gaborit May 12 '20 at 13:40
  • @UlrikeFischer I just try to understand the mechanism of the key-value commands. So yes it’s not too complex example, but a so minimalist example will not be enough instructive. – fauve May 12 '20 at 16:24
4

I'm not sure what you really need. This can be something to start...

Assigning to title or author actually runs the code defined in pgfkeys. Nothing is stored.

\documentclass{article}

\usepackage{pgfkeys}

\pgfkeys{
    /bibliography/.cd, % family
    title/.code = {\ifx#1\empty A\else{\textbf{Title} #1\par}\fi},
    author/.code = {\ifx#1\empty A\else{\textbf{Author} #1\par}\fi},
}

\newcommand{\mycommand}[1]{
    \pgfkeys{
        /bibliography/.cd,
        #1,
    }
    \pgfkeysvalueof{/bibliography/title}
    \pgfkeysvalueof{/bibliography/author}
}
\begin{document}
One:\par
\mycommand{title = {Tikz \& PGF}, author={JD}}

Two:\par
\mycommand{author={JD}}

Three:\par
\mycommand{title = {Tikz \& PGF}}

Four:\par
\mycommand{}

Five:\par
\mycommand{title=, author=}

\end{document}

Edit

Please note that the .code is executed at "parameter time", so \mycommand{author={JD}, title = {Tikz \& PGF}} will print the author before the title.

Edit 2

This version uses \bibtitle and \bibauthor to store the data. As theses macros are global, you have to clear them (set to empty) in each call, otherwise previous values are remembered.

\documentclass{article}

\usepackage{pgfkeys}

\pgfkeys{
    /bibliography/.cd, % family
    title/.store in = \bibtitle,
    author/.store in = \bibauthor,
}

\newcommand{\mycommand}[1]{
    \pgfkeys{
        /bibliography/.cd,
        title = {},  % clear title
        author = {}, % clear author
        #1,
    }
    \ifx\bibtitle\empty\else\textbf{Title:} \bibtitle\par\fi
    \ifx\bibauthor\empty\else\textbf{Author:} \bibauthor\par\fi
}
\begin{document}
One:\par
\mycommand{title = {Tikz \& PGF}, author={JD}}
\mycommand{author={JD}, title = {Tikz \& PGF}}
    
\vspace{2ex}
Two:\par
\mycommand{author={JD}}

\vspace{2ex}
Three:\par
\mycommand{title = {Tikz \& PGF}}

\vspace{2ex}
Four:\par
\mycommand{}

\vspace{2ex}
Five:\par
\mycommand{title=, author=}

\end{document}
  • If I understand /bibliography/ is a variable name you choose. It could be anything else? Is it a kind of namespace? – fauve May 12 '20 at 16:26
  • 1
    @fauve bibliography is called a family and you can name it as you like. Think about it as a directory tree (as the manual says). Therefore you can have a title inside bibliography which is distinct from another title in other branch of the tree. – Jander May 12 '20 at 17:16
  • Additional question: is it possible to force item apparition order? I mean, if I do \mycommand{title="The new book", author="John Doe"} or \mycommand{author="John Doe", title="The new book"} it always give “Writer John Doe Title The new book”. – fauve May 17 '20 at 11:16
  • 1
    @fauve Please see the 'EDIT 2' in my answer. Just realized I inverted the lines, so in my example the title comes first... – Jander Jun 2 '20 at 17:51
1

Here's an implementation with expl3 keys.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

% define the keys
\keys_define:nn { fauve/books }
 {
  title  .tl_set:N = \l__fauve_books_title_tl, % the title
  author .tl_set:N = \l__fauve_books_author_tl, % the author
 }

% formatting
\NewDocumentCommand{\mycommand}{m}
 {
  \group_begin:
  \keys_set:nn { fauve/books } { #1 } % populate the keys

  % format the book
  \par\addvspace{\topsep}
  \fauve_books_author:V \l__fauve_books_author_tl
  \fauve_books_title:V \l__fauve_books_title_tl
  \par\addvspace{\topsep}
  \group_end:
 }

\cs_new_protected:Nn \fauve_books_title:n
 {
  \tl_if_empty:nF { #1 }
   {
    \par\noindent\textbf{Title:}~#1
   }
 }
\cs_new_protected:Nn \fauve_books_author:n
 {
  \tl_if_empty:nF { #1 }
   {
    \par\noindent\textbf{Writer:}~#1
   }
 }
\cs_generate_variant:Nn \fauve_books_title:n  {V}
\cs_generate_variant:Nn \fauve_books_author:n {V}

\ExplSyntaxOff

\begin{document}

\mycommand{title=The new book, author=John Doe}

\mycommand{title=Another book}

\end{document}

I have separated the formatting commands specific for each key, but that's optional.

enter image description here

1

FWIW, I'll show how to write such a macro in ConTeXt. ConTeXt has a few key-value driven interfaces, but for something as simple as this, I would just piggyback oon the \setupvariables[...][..=..] and \getvariable{...}{...}.

\unprotect
\define\mycommand
    {\dosingleargument\mycommand_setup}

\def\mycommand_setup[#1]%
    {\bgroup
     \setvariables[mycommand][#1]%
     \mycommand_process
     \egroup}

\def\mycommand_process
    {\startlines
     \doifsomething{\getvariable{mycommand}{author}}
        {\bold{Writer:} \getvariable{mycommand}{author}\endgraf}%
     \doifsomething{\getvariable{mycommand}{title}}
        {\bold{Title:} \getvariable{mycommand}{title}}%
     \stoplines}
\protect

\starttext
\mycommand[title={The new book}, author={John Doe}]

\mycommand[title={The new book}]
\stoptext

Note that I modified the interface (use \mycommand[...] instead of \mycommand{...}) to match the ConTeXt convention that arguments in square brackets are for options and arguments in curly brackets are for text which is typeset.

0

With expkv-def you can use data and dataT keys.

A data key will store the information you provide in the value in a macro, but this macro also takes two arguments. If the key wasn't used it'd execute its second argument, while if the key was used it'd execute its first argument and append the value given to it in braces (so as an argument to that code).

A dataT key behaves similar, but the macro will only take one argument and would do nothing if the key wasn't used yet, whereas it would execute its argument and append the given value if it was used.

Just storing the value in a variable would be possible with the store key type instead of data.

\documentclass[]{article}

\usepackage{expkv-def}

\makeatletter
\ekvdefinekeys{fauve}
  {
     data  title  = \fauve@title
    ,dataT author = \fauve@author
    ,dataT year   = \fauve@year
  }
\ekvsetdef\fauve@set{fauve}
\newcommand\mycommand[1]
  {%
    \begingroup
      \fauve@set{#1}%
      \fauve@author{\par\noindent\textbf{Writer} }%
      \fauve@title
        {\par\noindent\textbf{Title} }%
        {\par\noindent\emph{No title}}%
      \fauve@year{\par\noindent\textbf{Year} }%
    \endgroup
  }
\makeatother

\begin{document}
\mycommand{title=The new book,author=John Doe}
\bigskip
\mycommand{title=The new book}
\bigskip
\mycommand{title=The new book,year=2020}
\bigskip
\mycommand{author=John Doe,year=2020}
\end{document}

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.