pgfkeys: .store in constructed macro
New solution
Another, more flexible approach is to extend the handlers \pgfkeys
accepts by a new one .store in cs
which does basically the same as .store in
, but doesn't take a complete control sequence name as value but a list of characters from that the final control sequence is built. So the following calls would be equal:
foo/.store in=\mymacro
foo/.store in cs=mymacro
The full example then looks like
\documentclass{article}
\RequirePackage{pgfkeys}
\newcommand\zkeys[1]{\pgfkeys{/prefix/.cd,#1}}
\pgfkeys{/handlers/.store in cs/.code=\pgfkeysalso{%
\pgfkeyscurrentpath/.code=\expandafter\def\csname#1\endcsname{##1}}%
}
\newcommand\zsetup[2]{%
\zkeys{
#1/.store in cs=z#2,
}%
}
\zsetup{keya}{storagea}
\zsetup{keyb}{storageb}
\zkeys{
keya=test,
}
\begin{document}
\zstoragea % Undefined control sequence.
\end{document}
Old solution
When you type \z#2
, TeX parses this as the command name \z
followed by the tokens inserted from the second argument. If you want to build a new control sequence from a series of characters/tokens, you have to use the sequence \csname ...\endcsname
, where ...
would be z#2
in this case.
However, in this specific situation store in=\csname z#2\endcsname
wouldn't work, because the \csname
call must be expanded exactly once to build the actual new control sequence from the characters, but not more than once, otherwise the built macro would be tried to expanded itself.
A possible solution is to wrap the whole key definitions into an \edef
, prefix all commands in it by \noexpand
, and use \unexpanded\expandafter{...}
in each place, we want exactly one expansion step:
\newcommand\zsetup[2]{
\edef\temp{%
\noexpand\zkeys{
#1/.store in=\unexpanded\expandafter{\csname z#2\endcsname},
}%
}\temp
}
\zstoragea
will then expand to test
.
Here are two solutions. They both take care not to expand the first argument of \zsetup
before passing it to \zkeys
, nor to define or overwrite any macro in the current group as a side effect.
First solution
\documentclass{article}
\usepackage{pgfkeys}
\newcommand{\zkeys}[1]{\pgfkeys{/prefix/.cd,#1}}
\newcommand*{\zsetup}[2]{%
\begingroup
\edef\arg{\unexpanded{#1/.store in=}%
\expandafter\noexpand\csname z#2\endcsname}%
\expandafter
\endgroup
\expandafter\zkeys\expandafter{\arg}%
}
\zsetup{keya}{storagea}
\zsetup{keyb}{storageb}
\zkeys{
keya=test,
}
\begin{document}
\zstoragea % Print 'test'
\end{document}
Second solution
Same code, except for the definition of \zsetup
:
\newcommand*{\zsetup}[2]{%
\begingroup
\def\tmp##1{\zkeys{#1/.store in=##1}}%
\expandafter\expandafter\expandafter
\endgroup
\expandafter\tmp\csname z#2\endcsname
}