4

I'm writing a handbook for my students and I want to create a command which should draw a task definition, its type and possible features, like source and link to the solution on YouTube.

In my plan all of these definitions should work (of course I use pseudo syntax here on purpose, just to show you my intention):

  • \task{definition=$x=3$}
  • \task{definition=$x=3$, source='ABC'}
  • \task{definition=$x=3$, link='https://youtube.ru'}
  • \task{definition=$x=3$, source='ABC', link='https://youtube.ru'}

But I cannot find any tool similar to optional and named arguments.

Ingmar
  • 6,690
  • 5
  • 26
  • 47
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – Community Aug 16 '23 at 00:32
  • 4
  • 5
    Welcome to TeX.SE. Ignore the Community Bot. Sometimes it doesn't know what it's talking about. – Teepeemm Aug 16 '23 at 01:08
  • Welcome. // Using the keyvalue approach is certainly the most flexible. If you want to stick with the standard \newcommand, you may want to provide default values. See e.g. here: https://en.wikibooks.org/wiki/LaTeX/Macros#New_commands . // Hint: you may also find the column to the right helpful (Linked, Related) – MS-SPO Aug 16 '23 at 06:49
  • 4
    @campa I wouldn't have deleted your answer! (voted to undelete) – David Carlisle Aug 16 '23 at 09:18
  • 1
    Seconding @DavidCarlisle's undelete. Aside from anything else, keyval has backwards compatibility with older LaTeX in its favour. – cfr Aug 16 '23 at 13:02
  • 1
    @campa My comment was not meant as criticism, but merely as a discussion about the best solutions in 2023, and the pros and cons of pre-expl3 packages such as keyval. I certainly didn’t intend for you to delete the answer. – Gaussler Aug 16 '23 at 13:22
  • 2
    @Gaussler The advantage of pre-expl3 packages is that I understand them (Grumpy Old Man talking here ;-)) – campa Aug 16 '23 at 15:44

3 Answers3

10

Classically the LaTeX2e solution was the keyval package (as used by \includegraphics[height=2cm, scale=3]{...}) but recent LaTeX releases include a keyval parser built in, based on l3keys.

@Campa's example modified to use the newer system:

\documentclass{article}

\makeatletter \DeclareKeys[task]{ definition .store = \task@definition, source .store = \task@source, link .store = \task@link }

\NewDocumentCommand\task{m}{% \begingroup \SetKeys[task]{#1}% This is a task with definition \task@definition.% \ifx\task@source@empty\else\space You can find its source in \task@source.\fi \ifx\task@link@empty\else\space (See \task@link)\fi \endgroup } \makeatother

\begin{document} \parindent0pt \task{definition={$x=3$}}\par % you must "hide" the = \task{definition={$x=3$}, source=ABC}\par \task{definition={$x=3$}, link=https://youtube.ru}\par \task{definition={$x=3$}, source=ABC, link=https://youtube.ru} \task{definition={$x=3$}} % you must "hide" the = \end{document}

Skillmon
  • 60,462
David Carlisle
  • 757,742
4

This might be a start using keyval

\documentclass{article}

\usepackage{keyval} \makeatletter \newcommand{\task@definition}{} \newcommand{\task@source}{} \newcommand{\task@link}{} \define@key{task}{definition}{\def\task@definition{#1}} \define@key{task}{source}{\def\task@source{#1}} \define@key{task}{link}{\def\task@link{#1}} \newcommand{\task}[1]{% \begingroup \setkeys{task}{#1}% This is a task with definition \task@definition.% \ifx\task@source@empty\else\space You can find its source in \task@source.\fi \ifx\task@link@empty\else\space (See \task@link)\fi \endgroup } \makeatother

\begin{document} \parindent0pt \task{definition={$x=3$}}\par % you must "hide" the = \task{definition={$x=3$}, source=ABC}\par \task{definition={$x=3$}, link=https://youtube.ru}\par \task{definition={$x=3$}, source=ABC, link=https://youtube.ru} \task{definition={$x=3$}} % you must "hide" the = \end{document}

enter image description here

campa
  • 31,130
4

For a simple task, imho1, nothing beats the simplicity of expkv-cs and \ekvcSplit (this only works for up to 9 keys, for more it's most likely better to use methods from expkv-def which work similar to \DeclareKeys -- or another key=value implementation like the one built into LaTeX).

1I'm the author of expkv and family.

To have an easy way to add formatting instructions and extra text to a key one can use a front facing key that decorates some internal key. So every time you say link = www.example.com this becomes link-internal={ (See www.example.com)}.

Also in expkv you don't have to hide an additional =, but you'd have to hide a ,.

This borrows the example created by @campa and modifies it to use expkv-cs:

\documentclass{article}

\usepackage{expkv-cs}

\ekvcSplit\task { % set up primary keys, all defaulting to an empty value definition = {} ,source-internal = {} ,link-internal = {} } {This is a task with definition #1.#2#3} % set up decorators \ekvcSecondaryKeys\task { meta source = {source-internal = { You can find its source in #1.}} ,meta link = {link-internal = { (See #1)}} }

\begin{document} \parindent0pt \task{definition=$x=3$}\par \task{definition=$x=3$, source=ABC}\par \task{definition=$x=3$, link=https://youtube.ru}\par \task{definition=$x=3$, source=ABC, link=https://youtube.ru} \task{definition=$x=3$} \end{document}


Alternatively to the \ekvcSplit version, you could also use the \ekvcHash version, in which you can access the key-values by name (the entire list will be forwarded inside of #1, and \ekvcValue can be used to access items from that list -- this works for arbitrary many keys).

\documentclass{article}

\usepackage{expkv-cs}

\ekvcHash\task { % set up primary keys, all defaulting to an empty value definition = {} ,source-internal = {} ,link-internal = {} } {% This is a task with definition \ekvcValue{definition}{#1}.% \ekvcValue{source-internal}{#1}% \ekvcValue{link-internal}{#1}% } % set up decorators \ekvcSecondaryKeys\task { meta source = {source-internal = { You can find its source in #1.}} ,meta link = {link-internal = { (See #1)}} }

\begin{document} \parindent0pt \task{definition=$x=3$}\par \task{definition=$x=3$, source=ABC}\par \task{definition=$x=3$, link=https://youtube.ru}\par \task{definition=$x=3$, source=ABC, link=https://youtube.ru} \task{definition=$x=3$} \end{document}


If you want an interface closer to the one provided by \DeclareKeys you could use expkv-def. In addition to a store-handler it also provides dataT. The instruction dataT link = \taskLink will define \taskLink such that by default it'll gobble the next token or brace-group, but if the key was used it'll put the value as {<value>} behind the next token or brace-group (and would strip the braces from that following brace-group).

\documentclass{article}

\usepackage{expkv-def}

\ekvdefinekeys{task} { store definition = \taskDefinition ,dataT source = \taskSource ,dataT link = \taskLink } \newcommand\taskSourceFormatter[1]{ You can find its source in #1.} \newcommand\taskLinkFormatter[1]{ (See #1)}

\newcommand\task[1] {% \begingroup \ekvset{task}{#1}% This is a task with definition \taskDefinition.% \taskSource\taskSourceFormatter \taskLink\taskLinkFormatter \endgroup }

\begin{document} \parindent0pt \task{definition=$x=3$}\par \task{definition=$x=3$, source=ABC}\par \task{definition=$x=3$, link=https://youtube.ru}\par \task{definition=$x=3$, source=ABC, link=https://youtube.ru} \task{definition=$x=3$} \end{document}


And if you really want to, you could use basically the same syntax as for keyval by using the basic expkv without any of the extension packages:

\documentclass{article}

\usepackage{expkv}

\newcommand\taskDefinition{} \newcommand\taskSource{} \newcommand*\taskLink{} \ekvdef{task}{definition}{\def\taskDefinition{#1}} \ekvdef{task}{source}{\def\taskSource{#1}} \ekvdef{task}{link}{\def\taskLink{#1}}

\newcommand\task[1] {% \begingroup \ekvset{task}{#1}% This is a task with definition \taskDefinition.% \ifx\taskSource\empty\else\space You can find its source in \taskSource.\fi \ifx\taskLink\empty\else\space (See \taskLink)\fi \endgroup }

\begin{document} \parindent0pt \task{definition=$x=3$}\par \task{definition=$x=3$, source=ABC}\par \task{definition=$x=3$, link=https://youtube.ru}\par \task{definition=$x=3$, source=ABC, link=https://youtube.ru} \task{definition=$x=3$} \end{document}


Result of all code blocks:

enter image description here

Skillmon
  • 60,462