lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


 > I'm currently exploring the idea of generating documentation for the
 > Lua interface of a Lua module with doxygen...
 > 
 > In addition, I'd also like to generate some source files that will add
 > in-application help strings to the module table.  Something like
 > module.__help = { functionx = "functionx does x", ... etc.}.  I'm
 > wondering also if other people have done this and if perhaps there is
 > some kind of agreed upon field to put this in and format for the help
 > strings.

Fidelis Assis and I have done something like this for the upcoming
new version of OSBF-Lua (which will never be released because I can't
stop tinkering with it!).  We've been focusing on internal
documentation; we have commands such as

  osbf internals
  osbf internals util
  osbf internals util.die

This thing has been a lifesaver, especially if we have to go off and
do real work for a couple of weeks and forget everything.

The implementation uses the convention that every module has an
internal value called __doc.  The 'internals' module is attached to
this message.   We use the same mechanism to document the C APIs
except they live in a Lua module of their own.

We have desultory ambitions in the direction of user documentation but
until things stabilize it won't happen soon.   

Oh, and everything is simple ASCII.  We thought html would be nice but
for us it's more important that the sources be readable and that it
work instantly on the command line.  Eventually a wiki-like markup
might be a good compromise, but at the moment we're more in the
mail-handling business than in the documentation business :-)
And a distinct advantage is that there's no separate step for
extracting the doco; it's always just right there.


Norman

local modname = ...
local osbfname = string.gsub(modname, '%..-$', '')
local util = require(osbfname .. '.util')

local osbf = _G[osbfname]

local function internals(out, s)
  local function show(what, t)
    local l = table.sorted_keys(t)
    if #l > 0 then
      out:write('\n', what, ':\n')
      for _, m in ipairs(l) do out:write('  ', m, '\n') end
    end
  end

  local function undoc(modname, m, ufuns)
    local doc = assert(m.__doc)
    ufuns = ufuns or { }
    for f in pairs(m) do
      if not string.find(f, '^_') and not doc[f] then
        ufuns[modname .. '.' .. f] = true
      end
    end
    return ufuns
  end
    

  if not s then
    local documented, undocumented, ufuns = { }, { }, { }
    for k, v in pairs(osbf) do
      if package.loaded[osbfname .. '.' .. k] == v then
        (v.__doc and documented or undocumented)[k] = true
        if v.__doc then
          undoc(k, v, ufuns)
        end
      end
    end
    show('Documented modules', documented)
    show('Undocumented modules', undocumented)
    show('Undocumented functions', ufuns)
  else
    local module, member
    if osbf[s] then
      module, member = s, nil
    else
      module, member = string.match(s, '^([^%.]+)%.([^%.]+)$')
    end
    if not module then
      out:write("There is no internal module called ", s, '\n')
      return
    end
    if not osbf[module] then
      out:write('There is no such internal module as ', module, '\n')
      return
    end
    local doc = osbf[module].__doc

    local function final_newline(s)
      return string.match(s, '\n$') and '' or '\n'
    end

    local function document(k)
      if string.find(k, '^__') then return end
      local d = string.gsub(doc[k], '\n\n', '\n  \n')
      d = string.gsub(d, '\n(.)', '\n  %1')
      local exported = osbf[module][k] ~= nil
      if not exported then
        d = string.gsub(d, '^%s*function', 'local function')
      end
      out:write('\n', module, exported and '.' or ': ', k, ' = ', d, final_newline(d))
    end

    if not doc then
      out:write('Internal module ', module, ' is not documented\n')
    elseif not member then -- document the whole module
      local first = doc.__order or { }
      local sorted = table.sorted_keys(doc)
      local written = { }
      if doc.__overview then
        out:write('=============== Overview of module ', s, ' ===============\n\n')
        out:write(doc.__overview, final_newline(doc.__overview))
        out:write('===================================', string.gsub(s, '.', '='),
                  '===============\n')
      end
      for _, k in ipairs(first) do
        written[k] = true
        document(k)
      end
      for _, k in ipairs(sorted) do
        if not written[k] then
          document(k)
        end
      end
      show('Undocumented functions', undoc(module, osbf[module]))
    else -- document just the member
      if doc[member] then
        document(member)
      elseif osbf[module][member] then
        out:write(s, " seems to exist, but it's not documented")
      else
        out:write('There is no such thing as ', s, '\n')
      end
    end
  end
end

return internals