莫看,莫看,莫看。重要的事说三遍,浪费时间我无论。
文化编程(Literate Programming)由计算机学界名宿 Donald Knuth 所创。其名,大陆译为「文学编程」,甚缪。将程序视为蛮夷,以文教化,Literate Programming 之意大抵如是。git
文化,其目的在于实现人与人的沟通交流。假若这世上只有一人,文化是多余的。同理,假若世上只有一个编程者,文化编程也是多余的。程序的属性分为两部分,一是供机器执行,二是供人类阅读。程序能正确被机器执行,这是第一性,但程序要继续维护下去,其代码更易于为他人理解,这是第二性,两者缺一不可。因此,程序要有文化。github
Knuth 创立文化编程,江湖传言,是报 E. W. Dijkstra 的一箭之仇。 Dijkstra 也是计算机学界名宿。当年,他提出告终构化编程,指出应当像设计机器那样编写程序,而 Knuth 写的程序不够结构化,或许为此而不快。创立文化编程以后,Knuth 就能够说 Dijkstra 没文化,固然他不会这样说。编程
江湖恩仇,儿女情长,这些事,提及来没完没了,到此为止。这篇文章,真正的主角是我。segmentfault
Knuth 虽然提出了文化编程,惋惜的是,他创造的文化编程工具 CWEB 有历史局限性,如今不是很好用。这能够理解,毕竟这个工具最初是他自用,而且在写这个工具之时,也只有美国人有更多的机会使用计算机。工具
好在这种工具实现起来也不太难,去年过年的那段时间,我写了一个相似的工具,名曰 orez,意思是 zero 翻转。为了防止百年以后有人再乱翻译,我先将它翻译为逆零 :)ui
orez 基本上遵循 CWEB 的思路——程序的代码与文档,彼此独立,但又混而为一。若以泡茶为喻,则代码之于茶叶,文档之于水,而 orez 之于茶壶。代码与文档的混合体,可称之为有文化的代码。翻译
代码与文档的混合须要借助一组简单的标记方能实现。下面,以一组五言诗句(姑且当其是)为代码,以诗句解析做为文档,演示这些标记的用法。这组诗句很直白,是一位无名氏,于一次磨刀以后随手而做,记录了磨刀的过程,赞美了磨过以后刀如何锋利,最后感慨真正锋利的刀无人赏识而隐没于陋鞘。设计
代码与文档皆以段落的形式出现,而且老是以 @
符号领起。例如:code
@ 一位侠士用水浸泡砥石,准备亲手去磨已钝了的未名刀: @ 准备 # 沧浪三瓢水 砥石浴盆中 侠士自磨刀 霜刃名未名
两者的区别是,代码段落有名字,即 @
与 #
之间的文字,例如「准备
」。代码段落的名字可根据实际状况而取,此处仅仅是追求足够简单。文档
假若有文化的代码是以文档开始,那么首个文档段落的领起符号可省略。例如:
侠士用水浸泡砥石,准备亲手去磨已钝了的未名刀: @ 准备 # 沧浪三瓢水 砥石浴盆中 侠士自磨刀 霜刃名未名
若假设代码段落以后总存在一个文档段落,哪怕这个段落没有任何内容,那么文档段落的领起符即可以在形式上做为代码段落的终止符。虽然没必要非如此不可,可是在以文档段落开始的状况下,我更喜欢这种形式。例如:
侠士用水浸泡砥石,准备亲手去磨已钝了的未名刀: @ 准备 # 沧浪三瓢水 砥石浴盆中 侠士自磨刀 霜刃名未名 @
这样一来,若代码段落后面是文档段落,那么该文档段落领起符已存在。若代码段落后面依然是代码段落,那么两者之间会夹杂一个内容为空的文档段落,无碍。
接下来再继续增长文档段落与代码段落:
磨刀,主要是靠腰部力量,手起到固定刀片倾斜角度的做用: @ 姿式 # 力从足下起 腰旋若扭松 双手互犄角 刃行掠风轻 @ 刀片在砥石上的前进方向老是与锋线垂直,而且须要时不时用手试 一下刀锋是否已磨到卷边的程度: @ 技巧 # 锋线有曲直 法向自无知 进退两茫然 探手试微疵 @
假设全部的文档段落与代码段落皆已写出,那么最后可经过代码段落的引用标记,将全部已给出的代码段落汇总到一块儿。例如:
@ 磨刀歌 # # 准备 @ # 姿式 @ # 技巧 @ ... ... @
形如 # ... @
这样的结构,即是已给出的代码段落的引用,亦即所引用的代码段落的内容最终会嵌入到被引用处。同一个代码段落,可于多处被引用。
假若不想为每一个代码段落都取个名字,毕竟取名字很烦人,能够考虑使用同名代码段,运算符 +
用于标记同名代码段落内容链接起来,表示一个完整的代码段落。
例如:
侠士用水浸泡砥石,准备亲手去磨已钝了的未名刀: @ 磨刀歌 # 沧浪三瓢水 砥石浴盆中 侠士自磨刀 霜刃名未名 @ 磨刀,主要是靠腰部力量,手起到固定刀片倾斜角度的做用: @ 磨刀歌 # + 力从足下起 腰旋若扭松 双手互犄角 刃行掠风轻 @ 刀片在砥石上的前进方向老是与锋线垂直,而且须要时不时用手试 一下刀锋是否已磨到卷边的程度: @ 磨刀歌 # + 锋线有曲直 法向自无知 进退两茫然 探手试微疵 @
上述三个代码段落,虽然分散各处,但它们其实是由两个 +
运算符链接而成的一个总体:
@ 磨刀歌 # 沧浪三瓢水 砥石浴盆中 侠士自磨刀 霜刃名未名 力从足下起 腰旋若扭松 双手互犄角 刃行掠风轻 锋线有曲直 法向自无知 进退两茫然 探手试微疵 @
+
运算符表示自上而下顺次链接同名的代码段落,其逆运算符 ^+
则表示自下而上链接同名的代码段落。例如:
@ 磨刀歌 # ^+ 磨刀歌 无名氏 @
这时,完整的代码段落以下:
@ 磨刀歌 # 磨刀歌 无名氏 沧浪三瓢水 砥石浴盆中 侠士自磨刀 霜刃名未名 力从足下起 腰旋若扭松 双手互犄角 刃行掠风轻 锋线有曲直 法向自无知 进退两茫然 探手试微疵 @
有时,须要将一个代码段落链接到某个特定的同名代码段落以前或以后,这时须要借助标签。
首先须要在目标段落上放一个标签。例如:
@ 磨刀歌 # <第一节> 沧浪三瓢水 砥石浴盆中 侠士自磨刀 霜刃名未名 @
<第一节>
即标签。标签必须置于代码段落标题行的下一行,且独占一行。
在源段落中,将目标段落标签与 +
或 ^+
运算符组合起来,即可将源段落与目标段落链接起来。例如:
@ 磨刀歌 # <第一节> ^+ 磨刀歌 无名氏 @
结果依然是:
@ 磨刀歌 # 磨刀歌 无名氏 沧浪三瓢水 砥石浴盆中 ... ... @
假设程序代码与文档内容混合体——有文化的代码,存于文本文件 foo.orz。如今,若从中导出给人看的文档——可喻为倒茶喝,只需使用如下命令:
$ orez -w foo.orz -o foo.yml
生成的 foo.yml 是一份带有排版信息的中间文件,它最终能转化为何文件,这取决于程序代码与文档内容是基于何种排版语言混而为一。假若是基于 Markdown 语言,即可使用 orez-md 工具,将 foo.yml 转换为 foo.md 文件(Markdown 文件),而后,再用其余工具将 foo.md 文件转化为网页或其余形式的文档形式。
在 Linux 系统(或类 Unix 系统)中,从 foo.orz 到 foo.md 的整个过程,可浓缩为一条命令:
$ orez -w foo.orz | orez-md > foo.md
foo.md 就是从 orez 这个茶壶嘴里流出的茶水。
一壶茶喝到了没滋味的时候,又该怎样倒出茶叶呢?打开壶盖,倒出来。不过,为了更贴近 orez 的逻辑,须要将茶叶视为袋泡茶,揪住袋上棉线,将茶叶从茶壶中拎出来。例如:
$ orez -t -e "磨刀歌" foo.orz -o mdg.txt
最后所得 mdg.txt 文件即是以 磨刀歌
为棉线而拎出的袋泡茶。
更多细节见 《orez 的故事》。之因此又重写一篇简略介绍,是由于之后要用 orez 的一些标记。