fdoc: a poor man's 'edoc', or, what I stole from Lisp

Luke Gorrie <>
Wed Feb 26 23:31:40 CET 2003


Ahoy,

Just did a kinda fun hack. The idea is a semi-automatic documentation
system that:

  1. Can be queried online
  2. Can find documentation by itself (nothing extra in Makefiles)
  3. Has a simple documentation syntax that looks good in source files

Basically, Lisp "docstrings".

The syntax I chose is: any comment appearing before a function head is
considered to be documentation for that function. Happily, this syntax
is already used by a lot of erlang code :-).

To find the documentation I have it look at the loaded modules, find
out where their sources are, and then scan the comments out of the
source files. So, it doesn't need any setup, but you may need to have
it regenerate its doc database after you load a lot of new modules.

The main interface functions are:

  apropos(Regexp): print docs for all functions matching the regexp

  describe(Mod, [Fun, [Arity]]): print docs for specific function(s)

Anyway, I hacked it up and checked it in on the Jungerl: module 'fdoc'
in the 'msc' application - it's kinda fun. The results it gets are
mixed (an incredible understatement), but here are a few
not-so-randomly-chosen examples to give the idea:

  ()220> fdoc:apropos("FIXME").
  gstk:to_ascii/3:
    FIXME: Currently we accept newlines in strings and handle this at
    the Tcl side. Is this the best way or should we translate to "\n"
    here?

  gstk_font:choose_ascii/2:
    Returns: Font specification string in Tk format
    The input is {Family,Size} or {Family,Style,Size} where Family and
    Style are atoms ?! FIXME true???

  ok
  ()221> fdoc:describe(gen_server, call).
  gen_server:call/2:
    Make a call to a generic server.
    If the server is located at another node, that node will
    be monitored.
    If the client is trapping exits and is linked server termination
    is handled here (? Shall we do that here (or rely on timeouts) ?).

  gen_server:call/3:
    (undocumented)

  ok
  ()222> fdoc:describe(regexp).
  regexp:first_match/2:
    -type first_match(String, RegExp) -> matchres().
     Find the first match of RegExp in String.

  regexp:format_error/1:
    format_error(Error) -> String.

  regexp:gsub/3:
    -type gsub(String, RegExp, Replace) -> subres().
     Substitute every match of the regular expression RegExp with the
     string New in String. Accept pre-parsed regular expressions.

  regexp:match/2:
    -type match(String, RegExp) -> matchres().
     Find the longest match of RegExp in String.

  regexp:matches/2:
    -type matches(String, RegExp) -> {match,[{Start,Length}]} | {error,E}.
     Return the all the non-overlapping matches of RegExp in String.

  regexp:parse/1:
    parse(RegExp) -> {ok,RE} | {error,E}.
     Parse the regexp described in the string RegExp.

  regexp:sh_to_awk/1:
    sh_to_awk(ShellRegExp)
     Convert a sh style regexp into a full AWK one. The main difficulty is
     getting character sets right as the conventions are different.

  regexp:split/2:
    -type split(String, RegExp) -> splitres().
     Split a string into substrings where the RegExp describes the
     field seperator. The RegExp " " is specially treated.

  regexp:sub/3:
    -type sub(String, RegExp, Replace) -> subsres().
     Substitute the first match of the regular expression RegExp with
     the string Replace in String. Accept pre-parsed regular
     expressions.

  ok

Cheers,
Luke




More information about the erlang-questions mailing list