Edit: This is a modified answer based on the comments. I've adopted a bunch of suggestions that Andrew Stacey made.
The PGF key facilities are so varied and powerful that it takes a fair amount of effort to figure out how to use them to do what you want! Let me present my solution in pieces and then in full.
\newcommand{\mymacro}[2][elements/.initial = {No elements passed.}]{
Before the elements.
% if the elements key is set and the list is not empty
% extract the members and list them separated by commas...
% else print `No elements passed.'
{\pgfkeys{/mymacro/.cd, #1, print}}
#2
}
Here is how you should define \mymacro
. You must call \pgfkeys
on your optional argument, in order that the keys you want to use actually be processed. Note that it's necessary to give your keys a "directory" in the path tree of all PGF keys, and it seems like good form to make your own, which I've called /mymacro
(like a UNIX directory).
The way things will work is that elements
will process the value it is given and then print
will output the result, or the error message if no elements were specified. I handle this by having the default argument for \mymacro
simply set the value of elements
directly, without any processing.
I am also careful to put the call to \pgfkeys
in a group, since the action of elements
doesn't initialize its value and subsequent calls of \mymacro
could interfere with each other.
\pgfkeys{/mymacro/.cd,
print/.code = {\pgfkeysvalueof{/mymacro/elements}},
elements/.code = {%
\pgfkeys{/mymacro/.cd,
list/.list = {#1},
elements/.add={\{}{\}}
}%
},
list/.code = {\pgfkeys{/mymacro/elements/.append = (#1)}}
}
Now we have to define the action of these keys. As I see it, your elements
key is a storage bin, and whatever is in it will get printed by print
. However, it also processes the value it receives when it is called as elements = {a, b, ...}
, using the .code
subkey ("handler") I define for it. This thing calls the list
key's .list
handler (which requires the pgffor
package if you are just loading pgfkeys
on its own rather than through tikz
), which just loops over whatever comma-separated list it is given, applying list/.code
to each item. As an uncreative example, I have this just put parentheses around the items. Afterwards, you can also have elements/.code
postprocess the result, for example by pre- and app-ending braces.
This trick of having a key act both as storage for a value and code to act on that value is quite useful. At the very least it allows you to write semantically appealing statements like elements = {a,b,c}
without worrying whether that is really an assignment, since it can be both code and a subsequent assignment of the processed result.
It is probably possible to set things up more cleverly so that fewer keys are used, but that would be confusing in this example. Here is the full LaTeX file:
\documentclass{article}
\usepackage{pgfkeys,pgffor}
\newcommand{\mymacro}[2][elements/.initial = {No elements passed.}]{
Before the elements.
% if the elements key is set and the list is not empty
% extract the members and list them separated by commas...
% else print `No elements passed.'
{\pgfkeys{/mymacro/.cd, #1, print}}
#2
}
\pgfkeys{/mymacro/.cd,
print/.code = {\pgfkeysvalueof{/mymacro/elements}},
elements/.code = {%
\pgfkeys{/mymacro/.cd,
list/.list = {#1},
elements/.add={\{}{\}}
}%
},
list/.code = {\pgfkeys{/mymacro/elements/.append = (#1)}}
}
\begin{document}
\mymacro[elements = {a,b,c}]{Foo}
\mymacro{Bar}
\mymacro[elements = {1,2,3}]{Baz}
\mymacro{Quh}
\end{document}