stone-zeng / fduthesis

LaTeX thesis template for Fudan University
LaTeX Project Public License v1.3c
829 stars 208 forks source link

关于简化 `xtemplate` 用法的一些想法 #235

Open atxy-blip opened 2 years ago

atxy-blip commented 2 years ago

这两天在重新拜读关于封面部分的代码。fduthesis 使用了 xtemplate 进行此部分的实现,但在实际阅读代码的时候,我并没有感到抽象化起到了简化的作用,反而是大量的嵌套导致直观上艰深难懂(也有很大可能是因为我菜)。仔细阅读这一宏包的使用手册后我发现了一个华点,简言之就是:Instance 不应当是对整个页面内容的描述,而是对单个页面部件的描述。

原文是这样写的:

There are three distinct layers in the definition of “a document” at this level

  1. semantic elements such as the ideas of sections and lists;
  2. a set of design solutions for representing these elements visually;
  3. 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}
stone-zeng commented 2 years ago

使用 xtemplate 最初的目的是为了能够支持不同样式的封面,因为我们很多院系没有按照学校的模板,而是另起炉灶各搞各的(尤其是本科,比如我们物理系的就不长这样,所以才会有 phys 分支)。但在相当的时间内这个模板的用户并不多,而且往往只需要应付学校的模板,所以这个需求实际上就变成了伪需求。

atxy-blip commented 2 years ago

支持不同样式的封面

原来如此……你南情况也差不多,研究生院给了个语焉不详的 Word 材料包,然后说具体规定听院系的(苦笑)。

请允许我重复一下此处的观点:xtemplate 本不应该写得像当前这般复杂。面向对象本来就是要找尽可能多的共通属性,因此对于封面页,它的共同属性其实是包含页面部件,是页面的 Instance 套着页面部件的 Instance。这是我理解到的优势。

今天上午我把这个想法成功套到了 njuthesis 上面,不如我晚上加班,明天提个 PR 看看效果?

stone-zeng commented 2 years ago

这种比较大的重构暂时不太想做,issue 先放着,之后再说吧(

zepinglee commented 2 years ago

我之前看了 xtemplate 的文档,但是一直没搞懂用在什么场景下最合适。刚刚看完这篇分析后,我的理解是像 tuna/thuthesis/thuthesis.dtx#L4483-L4535 比较适合用 xtemplate,其主要优势在于 key-value 的接口比较清晰?

atxy-blip commented 2 years ago

@stone-zeng 这种比较大的重构暂时不太想做

我重构完了(捂脸)目前正在补说明文字。

@zepinglee 主要优势在于 key-value 的接口比较清晰?

对!这样子就可以很方便地创建具有相似外观的组件;更广义地,是可以创建具有相似行为的组件。我还没仔细研究过 thuthesis ,但已经保上你校了,之后有很多机会看(

zepinglee commented 2 years ago

对!这样子就可以很方便地创建具有_相似外观_的组件;更广义地,是可以创建具有_相似行为_的组件。

嗯,所以这个 issue 的改进主要是在 page-element 这样更细的粒度上进行封装。

但已经保上你校了

欢迎欢迎!