Comments on: Function summary auto-doc generator

Carl Sassenrath, CTO
REBOL Technologies
6-Nov-2009 6:29 GMT

Article #0291
Main page || Index || Prior Article [0290] || Next Article [0292] || 5 Comments || Send feedback

One task on the project list is to review all function refinements. In order to make that task easier, I revived and enhanced an old script from R2 called words.r. It generates a nice HTML summary of all functions directly from REBOL's embedded function specs.

Here's what its Function Summary output looks like. Note that function names are linked to their R3 document reference pages.

You might find the script useful as a small example of using language reflection to generate an HTML document.

    Title: "REBOL 3 Auto-Doc Function Summarizer"
    Version: 3.0.0
    Author: "Carl Sassenrath"
    Purpose: {Generates an HTML document of REBOL functions.}

title: "REBOL 3 - Function Summary"

html: make string! 120000
emit: func [data] [repend html data]

get-next: func ['series] [first back set series next get series]

special-file: charset "!?*+/=<>"

word-to-file: func [file /local f][

    file: lowercase form file

    if all [
        f: find file #"!"
        not head? f
    ][remove f] ; datatype!

    if all [
        f: find file #"/"
        file <> "/"
        file <> "//"
    ][remove f] ; refinements

    if find file special-file [
        ; very bad performance! (replace this)
        replace/all file "!" "-ex"
        replace/all file "?" "-q"
        replace/all file "*" "-mul"
        replace/all file "+" "-plu"
        replace/all file "/" "-div"
        replace/all file "=" "-eq"
        replace/all file "<" "-gt"
        replace/all file ">" "-lt"

    if #"-" = file/1 [insert file #"z"]
    append file ".html"

emit [
    <meta http-equiv="content-type" content="text/html;charset=utf-8">
    <title> title </title>
    <style type="text/css"> {
    body {font-family: arial, sans-serif; font-size: 10pt;}
    .name {color: #000; font-weight: bold; font-size: 14pt; text-decoration: none;}
    .arg  {color: #248; font-weight: bold; font-size: 14pt; font-style: italic}
    .args {color: #248; font-weight: bold;}
    .refs {color: #822; font-weight: bold;}
    .type {color: #765;}
    .desc  {margin-left: 1cm}
    } </style>
    <h2> title </h2>
    <p> "For version: " system/version
    <br> "Click word for full documentation" </p>

foreach word sort words-of system/contexts/exports [
    value: attempt [get in system/contexts/exports word]
    unless any-function? :value [continue]

    args: words-of :value ; function's arg list
    spec: spec-of :value ; function's specification

    if loc: find args refinement! [args: copy/part args loc]

    emit [
        {<a href="} join url word-to-file word {" class="name">} word </a> " "
        <span class="arg"> args </span>
        <p class="desc">
        either string? spec/1 [get-next spec]["undocumented function."]
        <span class="type"> " [" type? :value "]" </span>

    ; spec format: argument [types] "description"
    while [not empty? spec] [
        unless block? arg: get-next spec [
            if any [arg = /local number? arg] [break]
            types: if block? spec/1 [get-next spec]
            description: either string? spec/1 [get-next spec][""]
            emit [
                pick [<span class="refs"><span class="args">] refinement? arg
                mold :arg </span>
                " -- " description
                <span class="type"> " [" any [types "any value"] "]" </span>
            emit <br>
    emit [<p> newline]

emit [</body></html>]

write file: %r3-funcs.html html
browse join file:// to-local-file/full file

PS: You can also see in this example why I want a replace-each function. I do that kind of mass substitution a lot.



6-Nov-2009 6:22:08
Thanks a lot Carl. This is not only an excellent example of REBOL's powers of reflection, but also shows (again) how natural it is to generate HTML with REBOL. Since this is to be run only once for each new release, performance seems a minor issue.
Hostile Fork
6-Nov-2009 12:54:01
This is a useful script. I wrote a similar one when I was first introduced to Rebol in order to give an editor (Source Insight) the ability to identify "keywords" and be able to jump to their definitions. I didn't know about system/contexts/exports, so I went through a step where I redirected the output of help to a file to get the list.

(Would be even cooler with a mezzanine source dump where applicable, just for those who are curious.)

Since you brought up reviewing refinements *and* replace, I'll bring up something I've thought about. It would be more natural to have /all be the default and turn it off with /once. Avoided mentioning this because I think there are more crucial changes that wouldn't break old code as badly (e.g. the four key ones from my email). BUT I'm sure it would be better if all things were equal.

It's happened to me on several occasions to forget the /all when that is what I meant. I think because if you told someone to take the string "ABBA" and replace B with C you would generally get "ACCA". If you saw replace/once that'd make it clear that you were only doing one replacement, so you're covered there too.

Saw an interesting lecture by Brad Meyers about "Natural Programming". He talked about research they'd done with questions like "go to the fruit bin and bring back anything that's not an apple or a pear". No one brings back a pear. :)

Hostile Fork
6-Nov-2009 14:09:41
P.S. another useful replace refinement would be replace/deep...
1-Dec-2009 11:55:56
the output is great however

One thing that is missing is "return" , for example, does "ask" not return something?

I thought that Rebol was using a functional programming paradigm.

my humble suggestion is that every feature documented should have a mandatory "return" section in their documentation.


example of "ask" in the documentation missing "return" . there are many like this:---

ask question

Ask the user for input. [function!]

question -- Prompt to user [series!] /hide -- mask input with * [any value]



ask question

description: Ask the user for input. [function!]

returns : string or something, bla, bla bla.

question -- Prompt to user [series!]

/hide -- mask input with * [any value]

20-Dec-2009 6:31:43
Both in this output and in the official docs (to which the entries in this output link) operators are listed followed by their two arguments, instead of between them, as in the USAGE section of the console HELP output. The latter layout is surely more helpful. Would it be much work to change this output and the docs in this way?

Post a Comment:

You can post a comment here. Keep it on-topic.


Blog id:



 Note: HTML tags allowed for: b i u li ol ul font span div a p br pre tt blockquote

This is a technical blog related to the above topic. We reserve the right to remove comments that are off-topic, irrelevant links, advertisements, spams, personal attacks, politics, religion, etc.

Updated 25-Jun-2024 - Edit - Copyright REBOL Technologies -