我正在尝试为简历文档创建一个类。作为该文档的一部分,将有一个包含所有教育信息的表格。我试图实现的是拥有某种模板来指定这些信息块之一是什么样子,然后拥有一个宏来使用相关数据实例化其中一个块。我目前的尝试是尝试使用它来处理将数据pgfkeys
传递到宏中。该类的精简版本如下所示:
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{cv}
\LoadClass[10pt,a4paper]{article}
\RequirePackage{tabularx}
\RequirePackage{calc}
\RequirePackage{xparse}
\makeatletter
\protected\def\z#1{\pdfsavepos\write\@auxout{\gdef\string\tpos#1{\the\pdflastxpos}}}%
\def\foo#1#2{\ifcsname tpos#1\endcsname\the\dimexpr\csname tpos#2\endcsname sp -\dimexpr\csname tpos#1\endcsname sp\relax\fi}
\makeatother
\RequirePackage{pgfkeys}
\pgfkeys{
/education/.is family, /education,
title/.estore in=\educationtitle,
programme/.estore in=\educationprogramme,
notes/.estore in=\educationnotes,
notes/.default={},
institute/.estore in=\educationinstitute,
thesisheader/.estore in=\educationthesisheader,
thesisheader/.default=Thesis:,
thesistitle/.estore in=\educationthesistitle,
selectedcourses/.estore in=\educationselectedcourses,
selectedcourses/.default={},
dates/.estore in=\educationdates,
}
\newenvironment{education}{
\setlength{\tabcolsep}{5pt}
\setlength{\extrarowheight}{0pt}
\begin{tabular}{!{\z{a}}r!{\z{b}}p{(\textwidth-\foo{a}{b})-\tabcolsep}}
}{
\end{tabular}
}
\NewDocumentCommand{\educationitem}{o}{
\pgfkeys{/education,notes,selectedcourses,thesisheader,#1}
\educationdates{} & \textbf{\educationtitle{}} \\
& \educationprogramme{} \\
& \educationnotes{} \\
& \textit{\educationinstitute{}} \\
\educationthesisheader{} & \educationthesistitle{} \\
Selected courses: & \educationselectedcourses{} \\
}
(列的宽度有一些特殊之处,例如第二列填充了剩余的可用宽度。这是我前段时间从这里的其他答案中得到的。)
理想情况下我会使用如下类:
\documentclass{cv}
\begin{document}
\begin{education}
\educationitem[
title={Master of Science},
programme={Some programme},
notes={Some notes about the degree},
institute={Some institute},
dates={2014--2017},
thesistitle={The title of the thesis},
selectedcourses={Some list of courses that might get pretty long, filling out the usable space of the row.},
]{}
\educationitem[
title={Bachelor of Science},
programme={Some other programme},
notes={Some more notes about the degree},
institute={Some other institute},
dates={2011--2014},
thesisheader={Honours thesis:},
thesistitle={The title of the thesis},
selectedcourses={Some list of courses that might get pretty long, filling out the usable space of the row.},
]{}
\end{education}
\end{document}
这有望产生如下所示的表格:
不幸的是,我得到了一个Undefined control sequence
关于宏使用的错误\educationitem
。我刚刚问一个问题关于这一点,但我把情况简化了太多,导致答案不符合我的实际意图。(XY问题再次出现......)
所以这是我真正的问题:我如何构造一个可以大致如上所述使用的宏来得到我想要的结果?使用的解决方案pgfkeys
略有优势,但我对目前拥有的解决方案并不特别在意。希望这次我提供了正确数量的信息!
答案1
您可以
参数转发
使用 PGFkeys 也是如此。
我也更喜欢值键,即直接存储值的键。这意味着,/path/to/key
可以通过以下方式轻松检索键的值
\pgfkeysvalueof{/path/to/key}
代替
\macroForKey
(在内部,这当然也只是一个宏,即\pgfk@/path/to/key
。)
PGFkeys 已经使用宏来表示键如何处理其值,为什么不使用 PGFkeys 来存储实际值呢?
安装此类密钥的处理程序是.initial
您还可以声明其初始值。这种类型的键还允许我们使用/.add
,/.prefix
和/.append
我们可以用它在键中放入“更多”的值。
我也在使用
\pgfqkeys{/education}{<kv>}
这是稍快一点的版本
\pgfkeys{/education/.cd,<kv>}
在 的定义中\educationset
。
然后,在定义中我们在每个单元格中与路径结合\educationitem
使用。#1
\pgfkeys
/education
这意味着,对于每个单元格,所有的值都会被一遍又一遍地设置(并且忘记了通过单元格末尾的 TeX 来检索),并且实际上只检索到一个 - 我们在该单元格中需要的那个。
PGFkeys 还附带一个密钥过滤机制,我们可以在这里使用它(参见下面代码中的选项 A),但我怀疑我们是否能从中获得什么,因为我们的所有密钥都只是设置一个值。(如果密钥可以进行复杂的计算和赋值等,我们当然不想这样做九次。)
我不太熟悉,xparse
这就是我使用普通 LaTeX2e 的原因\providecommand
。
cv.cls
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{cv}
\LoadClass[10pt,a4paper]{article}
\RequirePackage{tabularx}
\RequirePackage{pgfkeys}
\providecommand\educationvaluefilter[2]{%
% Option A: with a filter, discards all other keys
% probably quicker when there's much more
% to do than just setting a value
% \pgfkeys{/pgf/key filters/equals/.install key filter=/education/#2}%
% \pgfqkeysfiltered{/education}{#1}%
% Option B: just setting all values
\educationset{#1}%
% and then type it:
\pgfkeysvalueof{/education/#2}}
\providecommand*\educationset{\pgfqkeys{/education}}
\educationset{
title/.initial=,
programme/.initial=,
notes/.initial=,
institute/.initial=,
thesisheader/.initial=Thesis:,
thesistitle/.initial=,
selectedcourses/.initial=,
dates/.initial=,
}
\newenvironment{education}{
\setlength{\tabcolsep}{5pt}%
\setlength{\extrarowheight}{0pt}%
\tabularx{\linewidth}{rX}
}{
\endtabularx
}
\providecommand{\educationitem}[1][]{
\educationvaluefilter{#1}{dates} & \textbf{\educationvaluefilter{#1}{title}} \\
& \educationvaluefilter{#1}{programme} \\
& \educationvaluefilter{#1}{notes} \\
& \textit{\educationvaluefilter{#1}{institute}} \\
\educationvaluefilter{#1}{thesisheader} & \educationvaluefilter{#1}{thesistitle} \\
Selected courses: & \educationvaluefilter{#1}{selectedcourses} \\
}
答案2
您的问题是每个单元格内部都形成一个组,因此由于仅提供本地分配,因此在第一个之后tabular
您的宏定义就会丢失。&
\educationitem
pgfkeys
下面使用另一个 key=value 包,即expkv-cs
,它不必面对这个限制,因为它通过参数转发而不是分配来工作,从而使表构建变得更加容易(尽管与中的众多不同键处理程序相比,界面有些有限pgfkeys
,但对于简单地收集和重新排序值来说已经足够了)。
我也使用过tabularx
你的education
表格,这似乎比使用的方法简单得多\pdfsavepos
。另外,在你的类中定义诸如\z
或之类的宏\foo
来执行非常具体的事情是个坏主意(定义单字母宏大多数时候也是一个坏主意)。
title
此外,如果省略、institute
或,则会引发错误thesistitle
,并且如果非强制键为空,则不会打印空行。
cv.cls
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{cv}
\LoadClass[10pt,a4paper]{article}
\RequirePackage{tabularx}
\RequirePackage{xparse}
\RequirePackage{expkv-cs}
% to grab an optional argument
\NewDocumentCommand\educationitem{O{}}{\educationitem@kv{#1}}
\newcommand\educationitem@ifnotempty[2]
{%
\if\relax\detokenize\expanded{{\ekvcValue{#1}{#2}}}\relax
\expandafter\@gobbletwo
\fi
\@firstofone
}
\newcommand*\educationitem@required[1]
{\ClassError{cv}{The `#1' key is required}{}}
\ekvcHash\educationitem@kv
{% list of default values, you could later change them using
% \ekvcChange\educationitem@kv{<key>=<value>-list}
title = \educationitem@required{title}
,programme = {}
,notes = {}
,institute = \educationitem@required{institute}
,thesisheader = Thesis:
,thesistitle = \educationitem@required{thesistitle}
,selectedcourses = {}
,dates = {}
}
{% to be used inside a tabular(x), so no need to pay attention for stray
% spaces
\ekvcValue{dates}{#1} & \ekvcValue{title}{#1} \\
\educationitem@ifnotempty{programme}{#1}{& \ekvcValue{programme}{#1} \\}
\educationitem@ifnotempty{notes}{#1}{& \ekvcValue{notes}{#1} \\}
& \textit{\ekvcValue{institute}{#1}} \\
\ekvcValue{thesisheader}{#1} & \ekvcValue{thesistitle}{#1} \\
\educationitem@ifnotempty{selectedcourses}{#1}
{Selected courses: & \ekvcValue{selectedcourses}{#1} \\}
}
\NewDocumentEnvironment{education}{+b}
{%
\setlength{\tabcolsep}{5pt}%
\setlength{\extrarowheight}{0pt}%
\par\noindent
\begin{tabularx}{\linewidth}{rX}%
#1%
\end{tabularx}%
}{}
main.tex
\documentclass{cv}
\begin{document}
\begin{education}
\educationitem[
title={Master of Science},
programme={Some programme},
notes={Some notes about the degree},
institute={Some institute},
dates={2014--2017},
thesistitle={The title of the thesis},
selectedcourses={Some list of courses that might get pretty long, filling out the usable space of the row.},
]
\educationitem[
title={Bachelor of Science},
programme={Some other programme},
notes={Some more notes about the degree},
institute={Some other institute},
dates={2011--2014},
thesisheader={Honours thesis:},
thesistitle={The title of the thesis},
selectedcourses={Some list of courses that might get pretty long, filling out the usable space of the row.},
]
\end{education}
\end{document}
结果
答案3
的问题在于\educationitem
它是在表格单元格内执行的,而表格单元格构成局部范围。因此,在.estore
第一个之后,所有的局部定义都消失了&
。您可以使用\expanded
- -trickery 在-environment“看到”\unexpanded
之前获取所有临时宏的顶层扩展——通常不需要,但我看到了激活的代码,所以……tabular
&
\noexpand
&
&
\documentclass[10pt,a4paper]{article}
\RequirePackage{tabularx}
\RequirePackage{calc}
\RequirePackage{xparse}
\makeatletter
\protected\def\z#1{\pdfsavepos\write\@auxout{\gdef\string\tpos#1{\the\pdflastxpos}}}%
\def\foo#1#2{\ifcsname tpos#1\endcsname\the\dimexpr\csname tpos#2\endcsname sp -\dimexpr\csname tpos#1\endcsname sp\relax\fi}
\makeatother
\RequirePackage{pgfkeys}
% Empty defaults in case keys for defining the macros are not used at all:
\newcommand*\educationtitle{}%
\newcommand*\educationprogramme{}%
\newcommand*\educationnotes{}%
\newcommand*\educationinstitute{}%
\newcommand*\educationthesisheader{}%
\newcommand*\educationthesistitle{}%
\newcommand*\educationselectedcourses{}%
\newcommand*\educationdates{}%
\pgfkeys{
/education/.is family, /education,
title/.estore in=\educationtitle,
programme/.estore in=\educationprogramme,
notes/.estore in=\educationnotes,
notes/.default={},
institute/.estore in=\educationinstitute,
thesisheader/.estore in=\educationthesisheader,
thesisheader/.default=Thesis:,
thesistitle/.estore in=\educationthesistitle,
selectedcourses/.estore in=\educationselectedcourses,
selectedcourses/.default={},
dates/.estore in=\educationdates,
}
\newenvironment{education}{%
\setlength{\tabcolsep}{5pt}%
\setlength{\extrarowheight}{0pt}%
\begin{tabular}{!{\z{a}}r!{\z{b}}p{(\textwidth-\foo{a}{b})-\tabcolsep}}%
}{%
\end{tabular}%
}
\NewDocumentCommand{\educationitem}{o}{%
%\begingroup
\pgfkeys{/education,notes,selectedcourses,thesisheader,#1}%%%%%%%%
\expanded{%
%\endgroup
\unexpanded\expandafter{\educationdates}\noexpand&\noexpand\textbf{\unexpanded\expandafter{\educationtitle}}\noexpand\\
\noexpand&\unexpanded\expandafter{\educationprogramme}\noexpand\\
\noexpand&\unexpanded\expandafter{\educationnotes}\noexpand\\
\noexpand&\noexpand\textit{\unexpanded\expandafter{\educationinstitute}}\noexpand\\
\unexpanded\expandafter{\educationthesisheader}\noexpand&\unexpanded\expandafter{\educationthesistitle}\noexpand\\
\unexpanded{Selected courses:}\noexpand&\unexpanded\expandafter{\educationselectedcourses}\noexpand\\
}%
}
\begin{document}
\begin{education}
\educationitem[
title={Master of Science},
programme={Some programme},
notes={Some notes about the degree},
institute={Some institute},
dates={2014--2017},
thesistitle={The title of the thesis},
selectedcourses={Some list of courses that might get pretty long, filling out the usable space of the row.},
]
\\
\educationitem[
title={Bachelor of Science},
programme={Some other programme},
notes={Some more notes about the degree},
institute={Some other institute},
dates={2011--2014},
thesisheader={Honours thesis:},
thesistitle={The title of the thesis},
selectedcourses={Some list of courses that might get pretty long, filling out the usable space of the row.},
]
\end{education}
\end{document}