#!/usr/bin/env lua -- docext.lua is a small script for extracting API documentation from Lua -- source files. -- Copyright (C) 2007 Christian Siefkes. -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ------------------------------------------------------------------------ -- Specify any sources files to process on the command line. -- Public variables and functions that are undocumented (no preceding comment -- block) will be ignored. -- Helper function that writes a block of |text| to a |file| using the -- given |header| (which will be '='-underlined). If |text| is empty, the -- |file| is not changed. function writeblock(file, header, text) if text ~= "" then file:write(underlined(header, "=") .. "\n") file:write(text) file:write("\n") end end -- Strips the ".lua" extension from a |text| (if present). function striplua(text) return string.gsub(text, "%.lua$", "") end -- Returns a copy of the given line of text |text| underlined with sufficient -- repetitions of the specified |char| (which defaults to "-" function underlined(text, char) char = char or "-" return text .. "\n" .. string.gsub(text, ".", char) .. "\n" end -- Extracts documentation from a Lua sourcefile and stores it as formatted -- text the given outfile (which will be created or overwritten). function docext(sourcefile, outfile) if sourcefile == outfile then error("Cannot use source file as output file: " .. sourcefile) end local source = assert(io.open(sourcefile)) -- open for reading local out = assert(io.open(outfile, "w")) -- open for writing -- print main header out:write(underlined(striplua(sourcefile), "*") .. "\n") local indent = " " local commentblock = "" local variabledoc = "" local functiondoc = "" local line, match local firstcommentblock = true -- some pattern definitions: local luaname = "[%a_][%w_]*" -- a Lua identifier -- line declaring a public variable local varline = "^(" .. luaname .. ")%s*=.*" -- line declaring a public function local funcline = "^function%s+(" .. luaname .. ").*" -- iterate over lines of Lua source for line in source:lines() do match = string.match(line, "%-%-%s*(.*)") if match then -- comment line: add content to current comment block commentblock = commentblock .. match .. "\n" else match = string.match(line, varline) if match then -- Public variable declaration if commentblock ~= "" then -- skip undocumented variabledoc = variabledoc .. underlined(match) .. "\n" .. indent .. line .. "\n\n" .. commentblock .. "\n" commentblock = "" -- reset comment block end else match = string.match(line, funcline) if match then -- public function declaration if commentblock ~= "" then -- skip undocumented functiondoc = functiondoc .. underlined(match) .. "\n" .. indent .. line .. "\n\n" .. commentblock .. "\n" commentblock = "" -- reset comment block end else -- something else if firstcommentblock and commentblock ~= "" then -- reached end of first comment block firstcommentblock = false local innercommentdelim = "%-%-%-%-%-%-%-%-%-%-+%s*" local startIdx, endIdx = string.find(commentblock, innercommentdelim) if startIdx and endIdx and endIdx < string.len(commentblock) then -- remove anything up to first "----------" line -- (probably copyright/license stuff) commentblock = string.sub(commentblock, endIdx+1) -- is there a second one? startIdx, endIdx = string.find(commentblock, innercommentdelim) if startIdx and startIdx > 1 then -- remove anything after second "----------" -- line (versioning stuff or something) commentblock = string.sub(commentblock, 1, startIdx -1 ) end end -- print relevant rest of first comment block out:write(commentblock .. "\n") end commentblock = "" -- reset comment block end end end end -- for -- Print public variable and function blocks (if present) writeblock(out, "Public Variables", variabledoc) writeblock(out, "Public Functions", functiondoc) -- Close files source:close() out:close() end -- Variables local sourcefile, outfile -- Main loop: extract documentation from files specified on command line for _, sourcefile in ipairs(arg) do -- remove ".lua" extension (if present) and append ".txt" extension outfile = striplua(sourcefile) .. ".txt" docext(sourcefile, outfile) end