fduthesis
fduthesis copied to clipboard
关于简化 `xtemplate` 用法的一些想法
这两天在重新拜读关于封面部分的代码。fduthesis
使用了 xtemplate
进行此部分的实现,但在实际阅读代码的时候,我并没有感到抽象化起到了简化的作用,反而是大量的嵌套导致直观上艰深难懂(也有很大可能是因为我菜)。仔细阅读这一宏包的使用手册后我发现了一个华点,简言之就是:Instance
不应当是对整个页面内容的描述,而是对单个页面部件的描述。
原文是这样写的:
There are three distinct layers in the definition of “a document” at this level
- semantic elements such as the ideas of sections and lists;
- a set of design solutions for representing these elements visually;
- specific variations for these designs that represent the elements in the document.
In the parlance of the template system, these are called object types, templates, and instances
具体来讲:根据我的理解,目前 fduthesis
将整个页面作为一个对象处理,规定了其中各种元素的属性。这就导致 Template
的定义异常复杂,Instance
的定义中各种元素的属性混合在一起。这一切只为创建一个实例,不免有头重脚轻的感觉。
另一方面,当我们把页面部件而不是整个页面考虑为一个对象时,它天然地只具备有限数量的属性:上下边距、对齐方式、字形字号、文字内容等,使得 Template
的定义也是有限的。而具体的页面是这些对象的实例的集合,创建页面只需传入一个列表调用各个 Instance
即可。我个人认为这种做法更符合 xtemplate
的初衷,也能极大优化代码的可读性。
为了更好地说明观点,下面准备了一个 MWE。
其中,由于对齐方式取决于头尾的控制命令,其实也可以不用单独新建控制序列。这也能简化原本复杂的展开控制。
\documentclass{article}
\usepackage{expl3,xtemplate,kantlipsum}
\ExplSyntaxOn
% contents to produce on the page
\cs_new_protected:Npn \__mytest_cover_title:
{ testcovertemplate }
\cs_new_protected:Npn \__mytest_cover_img:
{ \parbox {5cm} { \kant[42][1-3] } }
\tl_new:N \l__mytest_content_tl
\tl_new:N \l__mytest_begin_align_tl
\tl_new:N \l__mytest_end_align_tl
\skip_new:N \l__mytest_top_skip
% creates an object type “nju” XD
\DeclareObjectType { nju } { \c_zero_int }
% defines several properties of a single page element
\DeclareTemplateInterface { nju } { page-element } { \c_zero_int }
{
align : choice { l, r, c, n } = c,
top-skip : skip = \c_zero_skip,
content : tokenlist
}
\DeclareTemplateCode { nju } { page-element } { \c_zero_int }
{
align =
{
l =
{ \tl_set_eq:NN \l__mytest_begin_align_tl \flushleft
\tl_set_eq:NN \l__mytest_end_align_tl \endflushleft },
r =
{ \tl_set_eq:NN \l__mytest_begin_align_tl \flushright
\tl_set_eq:NN \l__mytest_end_align_tl \endflushright },
c =
{ \tl_set_eq:NN \l__mytest_begin_align_tl \center
\tl_set_eq:NN \l__mytest_end_align_tl \endcenter },
n =
{ \tl_clear:N \l__mytest_begin_align_tl
\tl_clear:N \l__mytest_end_align_tl }
},
top-skip = \l__mytest_top_skip,
content = \l__mytest_content_tl
}
{
\AssignTemplateKeys
\null \skip_vertical:N \l__mytest_top_skip
\group_begin:
\l__mytest_begin_align_tl
\l__mytest_content_tl
\l__mytest_end_align_tl
\group_end:
}
% the title example
\DeclareInstance { nju } { cover / title } { page-element }
{
align = r,
top-skip = 5cm,
content = \__mytest_cover_title:
}
% the img example
\DeclareInstance { nju } { cover / img } { page-element }
{
content = \__mytest_cover_img:
}
% user interface
\NewDocumentCommand \MakeTestCover { }
{
\thispagestyle { empty }
\clist_map_inline:nn { title, img }
{ \UseInstance { nju } { cover / ##1 } }
}
\ExplSyntaxOff
\begin{document}
\MakeTestCover
\end{document}
使用 xtemplate
最初的目的是为了能够支持不同样式的封面,因为我们很多院系没有按照学校的模板,而是另起炉灶各搞各的(尤其是本科,比如我们物理系的就不长这样,所以才会有 phys
分支)。但在相当的时间内这个模板的用户并不多,而且往往只需要应付学校的模板,所以这个需求实际上就变成了伪需求。
支持不同样式的封面
原来如此……你南情况也差不多,研究生院给了个语焉不详的 Word 材料包,然后说具体规定听院系的(苦笑)。
请允许我重复一下此处的观点:xtemplate
本不应该写得像当前这般复杂。面向对象本来就是要找尽可能多的共通属性,因此对于封面页,它的共同属性其实是包含页面部件,是页面的 Instance 套着页面部件的 Instance。这是我理解到的优势。
今天上午我把这个想法成功套到了 njuthesis
上面,不如我晚上加班,明天提个 PR 看看效果?
这种比较大的重构暂时不太想做,issue 先放着,之后再说吧(
我之前看了 xtemplate
的文档,但是一直没搞懂用在什么场景下最合适。刚刚看完这篇分析后,我的理解是像 tuna/thuthesis/thuthesis.dtx#L4483-L4535 比较适合用 xtemplate
,其主要优势在于 key-value 的接口比较清晰?
@stone-zeng 这种比较大的重构暂时不太想做
我重构完了(捂脸)目前正在补说明文字。
@zepinglee 主要优势在于 key-value 的接口比较清晰?
对!这样子就可以很方便地创建具有相似外观的组件;更广义地,是可以创建具有相似行为的组件。我还没仔细研究过 thuthesis
,但已经保上你校了,之后有很多机会看(
对!这样子就可以很方便地创建具有_相似外观_的组件;更广义地,是可以创建具有_相似行为_的组件。
嗯,所以这个 issue 的改进主要是在 page-element 这样更细的粒度上进行封装。
但已经保上你校了
欢迎欢迎!