最近因为服务端的一些变故, 需要一份客户端与服务器交互的 api 文档. 首先肯定是要排除掉手写的, api 文档这货肯定是要自动生成啦, 要不以后维护起来得死人的.

项目前端是使用 quick-cocos2d-x 来开发的, 开发语言是 lua, 找了一下 lua 的文档生成工具, 貌似只有 LuaDoc 和 LDoc 可以选. LuaDoc 已经好几年没有人维护了, 加上 LDoc 可以兼容 LuaDoc 的文档, 所以就定了 LDoc.

一. 安装

因为 LDoc 依赖与 penlight 和 lfs , 所以使用 luarocks 来安装是最简单的, 不然自己还得处理依赖. 因此我们需要先安装 luarocks.

1. 安装luarocks

如果已经安装过了的话,可以跳过这一步.

1.1 通过 homebrew 安装

通过 homwbrew 安装是最简单的, 只需要 brew updatebrew install luarocks 两步就可以啦! 不过 brew update 等待的时间可能会比较久, 耐心不够的话可以尝试从源码安装.

1.2 通过源码安装

1). 从这里下载最新版的 luarocks 源文件, 解压.

2). 打开终端, cd 到刚才解压的目录.

3). 键入 ./configure

这一步的话比较诡异, 我在公司装的时候各种问题, 在家里装就没有问题. 比如出现了这个:

Looking for Lua…
lua not found in $PATH.
You may want to use the flags –with-lua, –with-lua-bin and/or –lua-suffix. See –help.
configure failed.

这是没有找到lua的原因, 确保你安装了lua, 可以通过which lua来找到lua的安装路径. 然后用--with-lua-bin 参数传给configure, 如:

1
./configure --with-lua-bin=/usr/local

Could not find a downloader helper program. Tried: curl wget fetch.
Make sure one of them is installed and available in your PATH.
configure failed.

其实我也不知道为什么会抽这个风, curlwget 我都有安装的, 用 --with-downloader 指定一下就ok了, 如:

1
./configure --with-lua=/usr/local --with-downloader=wget

Could not find a MD5 checksum calculator. Tried: md5sum openssl md5.
Make sure one of them is installed and available in your PATH.
configure failed.

额, 还是指定一下 --with-md5-checker 吧!

1
./configure --with-lua=/usr/local --with-downloader=wget --with-md5-checker=md5

4). 键入 make build

5). 键入 make install

如果一切正常的话, 那么就安装成功了. 可以通过键入 luarocks 来检测.

2. 安装 LDoc

安装好 luarocks 之后, 安装 LDoc 是非常简单的, 只需要:

1
luarocks install ldoc

就可以了, luarocks 会自动帮你安装依赖项. 安装好之后在终端键入 ldoc -h, 如果出现下面这个, 则代表安装成功!

1
2
ldoc, a documentation generator for Lua, vs 1.4.3
...

二. 概览

让我们先通过一个简单的测试来了解下 ldoc , 先创建一个目录, 在目录下创建一个 test.lua 文件, 将下面的内容复制到里面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
--- a test module
-- @module test

local test = {}

--- this is a function
-- @string param1 this is param1
-- @int param2 this is param2
-- @return a string value
function test.my_module_function_1(param1, param2)
return param1 .. param2
end

return test

然后在这个目录下打开终端, 键入 ldoc test.lua, 一切正常的话, 会在当前目录下生成一个名为 doc 文件夹, 打开 doc/index.html 文件, 会看到下面这样的东西.

虽然很丑陋, 但也还不错, 该有的都有. 我们仔细看一下这个测试, 总体由 test 模块 和 my_module_function_1 函数 2部分组成. 它们都是以 --- 开始的, 这是 ldoc 的一个规则, 只有以 --- 开始的注释才会被 ldoc 解析, 这样就可以排除掉普通的注释信息. @module 是一个特殊的标签, 后面跟着模块的名字, 但其实这个标签是可选的, 没有的话默认会以文件名来定义模块名.

类似的标签还有很多, 我们在下面会一一说明.

三. 详解

1. 标签

  • @module 模块, 一般一个文件就是一个模块.
  • @classmod 和 @module 类似, 但是用来描述 class, 用这个标签后, 生成的文档中 Module 文字会变成 Class.
  • @submodule 如果一个模块的内容被分到了好几个文件中, 那么就可以再其他文件中用 submodule 来定义, 后面跟上master module的名字.
  • @script 和 @module 类似, 生成的文档中 Module 文字会变成 Script.

以上几个标签都是project-level, 意味着每个文件中只能包含它们其中的一个, 否则生成时就会提示 Module already declared! 错误.

  • @author (multiple), @copyright, @license, @release 这几个啥意思就不必说了吧, 值得一提的是它们必须放在project-level,如 @module 标签下.

  • @function, @lfunction. 用来描述函数. @function 一般情况下不用加, 只需要给函数加上---注释就可以. @lfunction 用来表示一个局部函数, 但是ldoc默认是不会导出局部变量和函数的.

  • @param @int, @string, @bool, @func, @tab, @thread 用来描述函数参数, 后面几个指定了参数类型.
  • @return 函数的返回值, 函数的返回值可能有多种, 因此 @return 在一个函数中也是可以多次使用的
  • @raise 这个函数可能抛出的错误
  • @local 最大的作用是使得一个函数不被导出, 除非使用了(unless –all)
  • @see 引用文档的其他内容, 同一模块的话直接 @see xxx, 不同模块的话需要加上模块名 @see xxmodule.xxfunc
  • @usage 给出函数的用例, 可以分多行来写
  • @fixme, @todo 和 @warning , 意思大家应该都懂. 但是必须在函数体内部并且以 --- 开头才能生效.

以上几个标签都是描述function的一些行为的

  • @table 描述一个table, 也可以不加, 只需要给table加上---注释就可以.
  • @field 用来描述table中的一个字段

  • @section 用来把一个模块分隔成好几块

  • @type 和 @class 的作用差不多, 但不能与 @class 同时存在. 一个文件中可以有多处 @type , 会和 @section 似得吧文件分隔成好多份.
  • @within 用来形容函数和table, 指定它们属于哪个section, 可以指定不存在的一个section, 会自动创建一个

哈哈, 以上就是所有的标签啦, 虽然比较多, 但是有很多都不怎么常用, 所以还是很好理解的.

2. 对于函数的一些高级用法

2.1 显示参数的类型

这个前面有提过, @param 是不指明具体类型的, 若想指明的话可以用 @int, @string, @bool, @func, @tab, @thread 几个标签来.

2.2 可选参数与默认值

可选参数的标记是自参数标签后紧跟 [opt] 来标识, 默认值则是 [opt=xx]. 让我们看一个官方的示例:

1
2
3
4
5
6
7
8
9
--- a function with typed args.
-- @string name person's name
-- @int age
-- @string[opt='gregorian'] calender optional calendar
-- @int[opt=0] offset optional offset
-- @treturn string
function one (name,age,...)
end
----> displayed as: one (name, age [, calender='gregorian' [, offset=0]])

2.3 多种返回值

一个函数不同的情况可能返回不同的值, 意义也都不一样, 那么怎么来表示呢? 答案是在 @return 后紧跟 [x] (x可以是1,2,3,…) 来标识. 生成出来的文档是用 Or 来列出这些不同的返回值的.

3. config.ld 的字段说明

ldoc 运行时有一堆参数可以传递, 在终端中去做比较麻烦, 修改也不太方便. 因此我们可以创建一个 config.ld 配置文件来做这个事情, ldoc . 表示在当前目前下查找 config.ld 文件, ldoc -c path/to/myconfig.ld <file> 读取特殊的目录的配置文件. 其实 config.ld 就是一个lua文件, 填写时需要遵循lua语法.

config.ld 文件中有一大坨的条目可以选择, 我们来看一下他们都是什么意思吧.

  • file 可以是一个文件名或者目录名, 如: file = 'test.lua'. file 也可以是一个table, 这时里面可以填写文件数组或目录数组, 同时也可以包含另一个特殊的数组 exclude, 表明要排除的文件或目录
  • project 项目的名称, 会出现在文档的左上角. 默认为 ldoc
  • title 页面的名称, 默认为 Reference
  • all 导出 local 的 function
  • output 导出 html 的名字, 默认是 index
  • dir 导出目录的名字, 默认是 doc
  • colon 使用冒号风格代替 @ 风格的 tag
  • boilerplate 忽略所有源文件中的首个注释(块), 比如: license 注释.
  • ext 输出文件的后缀(默认为 html)
  • one 文档使用单列的布局
  • style, template 指定模板和样式的目录. 在 config.ld 中它也可以为 true , 表示使用和配置文件同一目录的模板.
  • merge 允许文档从不同的文件合并同名的 module , 而不是产生多个module.

其它可选的参数还有很多, 但是都不常用. 大家可以点击这里跳转到官方文档继续查看.


这篇文章到这里就差不多, ldoc 网上的中文资料不是很多, 加上我使用时遇到了一些问题, 因此我写下这篇文章, 主要是帮大家对 ldoc 形成一个大体的印象, 具体细节或者高级功能可能还是得去看官方的文档.

当然有什么问题也欢迎大家评论指出, 多多交流!

附录:

官方文档: 这里
github地址: 这里