|
![]() |
|
级别: 初级
颜 林 (yanl@cn.ibm.com), 软件工程师, IBM
2008 年 6 月 26 日
Emacs Muse 是一个可以在 Emacs 中写 Wiki 文档的插件,通过 Emacs Muse,我们可以很容易地编写 Wiki 文档,并生成各种格式的文件。本文介绍了如何扩展使用 Emacs Muse —— 一个 Emacs 编辑器插件来生成精美的测试结果报告。
前言
Emacs 是一个开放源代码的编辑器。由于它使用效率高,可扩展性强,自20世纪70年代诞生以来就一直经久不衰,受到广大开发人员的热烈追捧。关于 Emacs 的各种介绍和使用技巧教程屡见不鲜。而本文所介绍的 Emacs Muse 是 Emacs 的一个扩展插件,它的前身就是 Emacs Wiki。由于 Emacs Wiki Mode 原作者 Michael Olson 需要重新架构代码,才另外创立了一个新的 Emacs Muse 项目。通过该插件,我们可以在 Emacs 中写 Wiki 文档,生成各种格式,包括网页,pdf ,DocBook ,LaTex 等等,并可以直接发布到网络中。
我们在工作过程中,往往需要制作一些结果报告,例如测试结果报告。在一份测试 报告中,需要统计测试结果,并对结果进行一定的分析和总结。如果我们想制作一份精美的报告,包括能对不同的结果着色,自动统计结果,对结果分析能有按照不 同的格式来突出显示,这样的工作完全可以通过 Emacs Muse 来实现。而且 Emacs Muse 可能按照 Wiki 网页的要求来生成 HTML 格式的网页,发布到网络中供人浏览。
![]() ![]() |
![]()
|
Emacs Muse 的安装与配置
从 Emacs Muse 的官方网站上(参考资源)可以下载最新的 Muse 安装包,解压后修改Makefile.defs 文件来设置 Emacs 的安装路径,如清单1所示,该路径是 Mac OS X 平台下 Emacs 的设置,其他平台也可以类似修改。
清单 1 Makefile.defs示例
#设置EMACS的路径 EMACS = emacs SITEFLAG = --no-site-file #设置Muse安装路径 DESTDIR = PREFIX = /Applications/Emacs.app/Contents/Resources ELISPDIR = $(DESTDIR)$(PREFIX)/site-lisp/muse INFODIR = $(DESTDIR)$(PREFIX)/info |
安装路径设置完成后,用 GNU Make 编译安装 Muse ,只需要运行 make install
命令即可。
安装完成后,我们需要修改 Emacs 的配置文件 .emacs 来加载 Muse 包,添加如清单2所示的代码到 .Emacs 文件中。
清单2 .emacs文件配置
(require 'muse-mode) (require 'muse-html) ;添加html格式的支持 (require 'muse-latex) ; 添加latex格式的支持 (require 'muse-texinfo) ; 添加texinfo格式的支持 (require 'muse-docbook) ; 添加docbook格式的支持 (require 'muse-wiki nil t) (require 'muse-project) ; 添加wiki project的支持 ;设置编码方式为utf-8 (setq muse-html-meta-content-type (concat "text/html; charset=utf-8")) ;新建一个wiki工程 (setq muse-project-alist '(("MyWiki" ("~/Documents/wiki" :default "index") (:base "html" :path "~/Document/wiki/publish")))) |
这样就完成了配置,在这个配置文件里创建了我们第一个 wiki 工程 MyWiki。
![]() ![]() |
![]()
|
Emacs Muse的基本操作
配 置完成以后重新启动 Emacs,就已经加载了 Muse。这时所有的以 muse 为扩展名的文件都是 Emacs Muse 的源文件,我们只需要用一些简单的标记来编写 muse 文件,然后用 Emacs 来生成各种格式的输出,下面我们就以生成一个简单的 Wiki 网页为例介绍下 Emacs Muse 的基本操作。
在 Emacs 中按快捷键 Ctrl+x Ctrl+f
,创建文件 ~/Documents/wiki/FirstPage.muse ,输入如清单3所示的内容:
清单3 FirstPage.muse
#title 第一个Wiki页面 * 一级标题需要一个星号开头 ** 二级标题需要两个星号开头 *** 三级标题需要三个星号开头 段落需要两个以上空行 居中一行文字需要以6个以上的空白开头 ---- 示一个横线只需要输入4个以上的“-”标记 这是 *着重* 的文字,这是 **进一步着重** 的文字,这是 ***更进一步的着重*** 的文字 这是 _下划线_ 文字,这是 =等宽verbatim and monospace= 的文字 *** 列表: - 无序列表需要以空格和“-”开头 1. 有序列表需要以空格和数字序号开头 字典 :: 名词定义需要以“::”分隔名词和所定义文字 - 列表也可以嵌套 1. 列表嵌套深度按照开头空格的多少来控制 2. 可以继续嵌套不同类型的列表 - 比如这样 *** 表格: 表格标题 || 用“||”分割 表格内容 | 用“|”分割 表格结尾 ||| 用“|||”分割 |
在 FirstPage.muse 文件输入过程中,Emacs 的 Muse 模式会根据用户的输入,生成不同的显示预览,如图1所示,这样大大方便了我们写 wiki 的效率,在 Emacs 中实现了所见即所得的用户体验。
图 1. Emacs 的 Muse 模式
![Emacs 的 Muse 模式](http://www.ibm.com/developerworks/cn/linux/l-cn-emacsmuse/images/image001.jpg)
输入完成后,按快捷键 Ctrl+c Ctrl+p
,该快捷键用来在当前工程目录下生成 wiki 网页。生成成功后, wiki 网页位于 ~/Documents/wiki/publish/FirstPage.html 。按快捷键 Ctrl+c Ctrl+v
来预览该网页,如图2所示:
图 2. 第一份 wiki 网页
![第一份 wiki 网页](http://www.ibm.com/developerworks/cn/linux/l-cn-emacsmuse/images/image002.jpg)
这 样我们就生成了一份 wiki 网页。在 firstPage.muse 文件中,我们用各种标记符号(*, -, =)来表示网页中的各种元素(标题,加粗,列表),这样就非常简单地生成了一张 wiki 网页,它可以发布到网站中直接供人阅读,非常适用于记录技术文档和笔记。
更为重要的是,Emacs Muse 不仅可以由 wiki 记号生成 HTML 格式,还可以生成 Latex, texinfo, docbook 等等多种格式,这也意味着我们完全可以用 Emacs Muse 来制作各种格式的文档。Emacs Muse 对多种文档格式的支持非常丰富,这在它的官方网站上可以找到完整的支持文档列表。
![]() ![]() |
![]()
|
自定义单元测试报告的样式和自动分析结果
上面内容简单介绍了 Emacs Muse 的基本用法和基本快捷键。由于 Emacs 天生的易于扩展的特点,Emacs Muse 也提供了大量的函数接口来扩展它的功能。扩展 Emacs 所用的 Elisp 语言简洁优美,非常容易学习和编程。
Muse 默认生成的 HTML 格式是非常普通的网页样式,我们可以通过自定义其样式来美化其输出。我们可以根据项目,工作和学习的具体需要,来定义不同需求的格式,使其成为一个多样式 的网页生成工具。下面本文就介绍如何自定义一种简单的单元测试报告的格式,该格式基于 HTML 的输出样式,但自定义了表单样式,同时根据测试结果来生成统计数据。
将 Muse 扩展代码放在 emacs-muse.el 文件中,在 .emacs 文件最后一样加入代码来包括这个文件,如清单4所示,把加载 muse 包的代码以及自定义样式的代码放入到 emacs-muse.el 文件,这样可以方便编写调试,而且还能方便在命令行调用。
清单4 在.emacs文件中包括Muse扩展包加载代码
;; Emacs Muse (load-file "~/emacs-muse.el") |
自定义单元测试样式
Muse 提供了函数 muse-define-style
来自定义格式,还有函数 muse-derive-style
来继承已定义的格式。本文所需输出的测试结果是一种自定义的 HTML 格式,所以只需要函数 muse-derive-style
来继承自 HTML 格式即可,代码如清单5所示,这里我们定义了一个名为 UT 的新格式,它继承自 HTML 格式。
清单5 定义UT样式
(muse-derive-style "ut" "html" :header 'ut-html-header :style-sheet 'ut-style-sheet) |
在该格式中,HTML 文件头由函数 ut-html-header 定义,该函数代码如清单6所示:
清单6 ut-html-header函数定义HTML文件头
(setq ut-html-header "<!DOCTYPE HTML PUBLIC /"-//W3C//DTD HTML 4.0 Transitional//EN/"> <html> <head> <title><lisp> (concat (muse-publishing-directive /"title/") (let ((author (muse-publishing-directive /"author/"))) (if (not (string= author (user-full-name))) (concat /" (by /" author /")/")))) </lisp></title> <meta name=/"generator/" content=/"muse.el/"> <meta http-equiv=/"<lisp>muse-html-meta-http-equiv</lisp>/" content=/"<lisp>muse-html-meta-content-type</lisp>/"> <lisp> (let ((maintainer (muse-style-element :maintainer))) (when maintainer (concat /"<link rev=///"made///" href=///"/" maintainer /"///">/"))) </lisp> <lisp>(muse-style-element :style-sheet muse-publishing-current-style) </lisp> </head> <body> <h1><lisp>(muse-publishing-directive /"title/")</lisp></h1> <p><big><em><lisp>(let ((author (muse-publishing-directive /"author/"))) (if (not (string= author (user-full-name))) (concat /"by /" author )))</lisp></em></big></p> <p><big><em><lisp>(let ((date (muse-publishing-directive /"date/"))) (concat /"Last Modified: /" date ))</lisp></em></big></p> <h2><lisp>(let ((package (muse-publishing-directive /"package/"))) (concat /"Test script Package &mdash/; /" package )) </lisp> </h2> <table class=/"muse-table/" border=/"2/" cellpadding=/"5/"> <tbody><tr><td><span class=/"pass/">PASS</span></td> <td>Passed all test</td></tr><tr><td><span class=/"fail/">FAIL</span></td> <td>Failed for new issue</td></tr><tr><td><span class=/"attempt/">ATTEMPTED</span></td> <td>Tried but there is known issue</td></tr> <tr><td><span class=/"nattempt/">NOT ATTEMPTED</span></td> <td>Not tried</td></tr></tbody></table> <!-- Page published by Emacs Muse begins here -->/n") |
清单6中,定义了 UT 样式中所输出的网页文件的开头部分代码。作为一个简单的单元测试结果报告样式,在该网页的开始部分,说明了报告的标题,测试人员名称,单元测试的代码包。 定义了四种测试结果: PASS, FAIL, ATTEMPTED, NOT ATTEMPTED ,分别表示通过,失败,有已知错误但已运行了单元测试,未测试。这段报告的开头部分所对应的输出网页位置如图4 所示。
为了表示不同样式元素,我们需要有个自定义的样式表嵌入到输出网页中,清单5 的代码中,样式表格式由函数 ut-style-sheet
定义,该函数定义如清单7所示。
清单7 ut-style-sheet函数定义样式表
(setq ut-style-sheet "<style type=/"text/css/"> body { FONT: 14px/1.4 'Trebuchet MS',Verdana, Arial, Helvetica, sans-serif; background:#fff; width: 60em; margin: 0 auto 0; padding: 2em 0 6em 0; text-align: left; } a { font-family: Verdana; text-decoration:none; font-weight:bold; color:#c00; } a:hover { background:#000000; color:#FFFFFF; } h1 a { color:#666;} h2 a { color:#666;} h3 a { color:#666;} h4 a { color:#666;} h1 { font-size: 40px; color:#666; border-bottom: 5px solid #000; padding: 2px; margin: 0px; margin-bottom: 8px; } h2 { color:#666; font-size: 22px; padding: 2px; margin-top: 15px; border-bottom: 2px solid #000000; } h3 { color:#666; font-size: 18px; padding: 2px; margin-top: 5px; } h4 { color:#666; font-size: 18px; padding: 2px; margin-top: 5px; } img { float: right; margin: 10px; border-style:solid; border-width:2px; } #im { clear: right;} pre { border: #777777 1px solid; padding: 0.5em; margin-left: 1em; margin-right: 2em; white-space: pre; background-color: #e6e6e6; color: black; } .pass { color:Green; } .fail { color:Red; font-weight: bold; } .attempt { color:Maroon; font-weight: bold; } .nattempt { color:Silver; } .verse { white-space: pre; margin-left: 1em; } dt { font-weight: bold;} li { margin-bottom: 0.9ex;} blockquote { margin-left: 2em; color: #4444ff; } td { font-size: 13px;} th { background: #d6d6d6; font-size: 14px; } </style>") |
在清单7所示的样式表中,我们定义了网页 报告中的各种元素(标题,章节,表格等)的格式。而且还专门针对于单元测试结果报告,定义了四种样式: .pass, .fail, .attempt, .nattempt 。定义了它们的颜色和字体,读者可以根据自己的需要,修改它们的样式。
这样我们做好了一份测试报告的准备工作,定义了不同测试结果的 html 样式,定义了报告开始部分的格式。下面将介绍如何生成报告的主体部分。
自定义单元测试报告内容格式
在 Muse 中我们可以使用一种格式类似于 XML 的标签来表示特定的内容,例如如果想输入一段包括了 Muse 的关键字字符的文本,而又不想被 Muse 所解释这些关键字字符,则可以在 Muse 文件中输入如清单8所示的文本:
清单8 标签示例
<verbatim> 这是 *着重* 的文字,这是 **进一步着重** 的文字,这是 ***更进一步的着重*** 的文字 </verbatim> |
输出则如图3所示。
图 3. verbatim 标签输出示例
![verbatim 标签输出示例](http://www.ibm.com/developerworks/cn/linux/l-cn-emacsmuse/images/image003.jpg)
Muse 提供了多种标签可以在 Muse 文件中使用,包括 lisp(动态嵌入 lisp 代码的运行结果),python (动态嵌入 python 代码的运算结果), src (对标签内的代码文本进行着色)等等。通过 Muse 函数 muse-publish-markup-tags ,我们可以自定义标签。本测试报告自定义了 result 标签,通过在该标签范围内输入测试结果, 那么Muse 在生成 HTML 文件时,会根据我们的扩展代码解释 result 标签内的内容,生成我们所期望的格式。result 标签的定义代码如清单9所示。
清单9 result标签定义代码
(defvar muse-pass-tag '("pass" t nil nil muse-ut-pass-tag)) (defun muse-ut-pass-tag (beg end) (delete-region beg end) (goto-char beg) (muse-insert-markup "<span class=/"pass/">PASS</span>")) (defvar muse-fail-tag '("fail" t nil nil muse-ut-fail-tag)) (defun muse-ut-fail-tag (beg end) (delete-region beg end) (goto-char beg) (muse-insert-markup "<span class=/"fail/">FAIL</span>")) (defvar muse-attempt-tag '("attempt" t nil nil muse-ut-attempt-tag)) (defun muse-ut-attempt-tag (beg end) (delete-region beg end) (goto-char beg) (muse-insert-markup "<span class=/"attempt/">ATTEMPTED</span>")) (defvar muse-nattempt-tag '("nattempt" t nil nil muse-ut-nattempt-tag)) (defun muse-ut-nattempt-tag (beg end) (delete-region beg end) (goto-char beg) (muse-insert-markup "<span class=/"nattempt/">NOT ATTEMPTED</span>")) (defvar muse-result-tag '("result" t t nil muse-ut-result-tag)) (defun muse-ut-result-tag (beg end attrs) "Insert unit test result <result> ... </result>." (muse-publish-markup-attribute beg end attrs nil (save-excursion (save-restriction (setq passed 0) (setq failed 0) (setq attempted 0) (setq nattempted 0) (goto-char (point-min)) (while (re-search-forward "<pass/>" nil t) (setq passed (1+ passed))) (goto-char (point-min)) (while (re-search-forward "<fail/>" nil t) (setq failed (1+ failed))) (goto-char (point-min)) (while (re-search-forward "<attempt/>" nil t) (setq attempted (1+ attempted))) (goto-char (point-min)) (while (re-search-forward "<nattempt/>" nil t) (setq nattempted (1+ nattempted))) (goto-char (point-min)) (setq count (+ passed failed attempted nattempted)) (goto-char (point-min)) (muse-insert-markup (concat "<h3>Result:</h3><p><strong><em>" "Totally " (number-to-string count) " cases," (number-to-string passed) " passed, " (number-to-string failed) " failed, " (number-to-string attempted) " attempted, " (number-to-string nattempted) " not attempted." "</em></strong></p>")) )))) (add-to-list 'muse-publish-markup-tags muse-result-tag) (add-to-list 'muse-publish-markup-tags muse-pass-tag) (add-to-list 'muse-publish-markup-tags muse-fail-tag) (add-to-list 'muse-publish-markup-tags muse-attempt-tag) (add-to-list 'muse-publish-markup-tags muse-nattempt-tag) |
在清单9中,首先我们定义了四个单元测试 结果标签,这四个标签分别代表了四种单元测试结果,并对每种结果应用对用的样式表样式,进行着色和设置字体。然后定义了 result 标签,该标签统计在该标签内容中所包含的每种测试结果标签的个数。最后一句代码将 result 标签和四种单元测试结果标签发布到 muse 的标签列表中。
解释 result 标签的代码位于 muse-ut-result-tag
函数中,它首先定义了4个变量用于存储每种测试结果的次数,然后不断遍历标签中的文本,统计测试结果标签的个数来获知测试结果。最后,该函数输出统计结果,将其列在报告中的 Result 小节的开始处,如图4 所示。
生成第一份单元测试结果报告
上面做好了所有的准备工作,保存好 emacs-muse.el 文件。重启 Emacs 或者运行命令 M-x eval-buffer
,我们自定义的单元测试报告格式就生效了。
现在新建一个 Muse 工程,如清单10所示:
清单10 第一个单元测试报告工程
;添加一个wiki工程 (setq muse-project-alist '(("MyWiki" ("~/Documents/wiki" :default "index") (:base "html" :path "~/Document/wiki/publish")) ("MyUTReport" ("~/Documents/wiki2" :default "index") (:base "ut" :path "~/Document/wiki2/publish")))) |
新建 muse 源文件 ~/Documents/wiki2/firstReport.muse ,输入如清单11所示的文本。
清单11 第一份单元测试报告的Muse文件
#author sky #package org.example <result> Script Name || Result || Description Script_a || <fail/> || resaon...reason...reason...reason... Scrpit_b | <pass/> | Script_c | <nattempt/> | why...why...why...why...why...why...why... Script_d | <attempt/> | result...result...result...result </result> * Analysis 1. Below methods need refactor: <src lang="c"> 1. code ... 2. code2... </src> |
按快捷键 Ctrl+c Ctrl+p
发布工程,发布成功后,按快捷键 Ctrl+c Ctrl+v
来预览结果,结果图4 所示。
图 4. 第一份测试报告输出结果
![第一份测试报告输出结果](http://www.ibm.com/developerworks/cn/linux/l-cn-emacsmuse/images/image004.jpg)
![]() ![]() |
![]()
|
同其他工具的结合
通 过 Emacs Muse ,我们可以通过简单的标记来生成精美的测试结果报告。生成报告所需要的muse文件既可以是手动输入,也可以是由自动化测试工具来自动生成。通过 Emacs 的 batch 模式,我们可以从命令行运行 Emacs ,让它以命令行的形式执行 emacs-muse.el 文件中的 Elisp 代码,生成 HTML 格式的网页报告。这一切只需要执行如下的命令:
skys-imac:~ sky$ emacs –q -batch -l ~/emacs-muse.el –f muse-project-batch-publish MyWiki |
最后的 MyWiki 是 muse 工程的名字。这样,通过自动化的测试工具来生成 muse 文件,再从命令行运行生成 HTML 报告。这样就将 Emacs Muse 同其他工具完美结合在一起。而且可以根据自己需求来自定义样式,将艺术和技术完美地结合到了一起,达到了很好的效果。
![]() ![]() |
![]()
|
结束语
Emacs Muse 扩展性强,并在发布 Wiki 方面有着独到的强大功能。它支持格式多,支持源代码标记,可嵌套列表等等。有兴趣的读者可以直接访问附录中 Muse 的官方网站 http://mwolson.org/ ,这个网站完全使用 Emacs Muse 生成并发布到网络中的,并且所有的 Muse 文件都是开放代码,可以直接下载学习的。正是由于它的强大扩展性,也使得我们可以自定义样式来生成符合我们要求的文档,这也正是 Emacs 编辑器的迷人之处。
![]() ![]() |
![]()
|
下载
描述 | 名字 | 大小 | 下载方法 |
---|---|---|---|
样例代码 | muse.zip | 3KB | HTTP |
![]() | ||||
![]() | 关于下载方法的信息 | ![]() |
参考资料
- Emacs Muse 的官方主页 http://mwolson.org/ ,上面有全部的文档和最新的代码下载。
- 王银的个人主页,Emacs 部分 :这是我的第一份 Emacs 入门教程。
- “Emacs 编辑环境” :值得一看。
- 生活在 Emacs 中 :developerWorks 中的一系列 Emacs 入门教程。很多人的 Emacs 入门教程。
- Emacs Wiki :汇聚大量 Emacs 爱好者贡献的 Emacs 扩展代码的维基百科。
- 让 Emacs 为您工作,第 1 部分 :是这篇文章启发了本文的写作。
关于作者
![]() | ||
![]() | 颜林,目前是 IBM 中国软件开发实验室的软件工程师,从事 Mac OS X 平台下的自动化测试工作。技术兴趣包括 Eclipse ,Mac OS X 开发,Linux 开发,Open Source。 |