rocco 0.1 → 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +23 -0
- data/Rakefile +63 -7
- data/bin/rocco +5 -0
- data/lib/rocco.rb +54 -36
- data/lib/rocco/layout.mustache +7 -1
- data/lib/rocco/tasks.rb +110 -0
- data/rocco.gemspec +4 -3
- metadata +5 -4
- data/README.md +0 -8
data/README
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
___ ___ ___ ___ ___
|
4
|
+
/\ \ /\ \ /\ \ /\ \ /\ \
|
5
|
+
/::\ \ /::\ \ /::\ \ /::\ \ /::\ \
|
6
|
+
/::\:\__\ /:/\:\__\ /:/\:\__\ /:/\:\__\ /:/\:\__\
|
7
|
+
\;:::/ / \:\/:/ / \:\ \/__/ \:\ \/__/ \:\/:/ /
|
8
|
+
|:\/__/ \::/ / \:\__\ \:\__\ \::/ /
|
9
|
+
\|__| \/__/ \/__/ \/__/ \/__/
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
Rocco is a quick-and-dirty, literate-programming-style documentation
|
14
|
+
generator for Ruby. See the Rocco generated docs for more information:
|
15
|
+
|
16
|
+
<http://rtomayko.github.com/rocco/>
|
17
|
+
|
18
|
+
|
19
|
+
Rocco is a port of, and borrows heavily from, Docco -- the original
|
20
|
+
quick-and-dirty, hundred-line-long, literate-programming-style
|
21
|
+
documentation generator in CoffeeScript:
|
22
|
+
|
23
|
+
<http://jashkenas.github.com/docco/>
|
data/Rakefile
CHANGED
@@ -1,5 +1,18 @@
|
|
1
|
+
$LOAD_PATH.unshift 'lib'
|
2
|
+
|
1
3
|
require 'rake/testtask'
|
2
|
-
|
4
|
+
require 'rake/clean'
|
5
|
+
|
6
|
+
task :default => [:sup, :docs]
|
7
|
+
|
8
|
+
desc 'Holla'
|
9
|
+
task :sup do
|
10
|
+
verbose do
|
11
|
+
lines = File.read('README').split("\n")[0,12]
|
12
|
+
lines.map! { |line| line[15..-1] }
|
13
|
+
puts lines.join("\n")
|
14
|
+
end
|
15
|
+
end
|
3
16
|
|
4
17
|
desc 'Run tests (default)'
|
5
18
|
Rake::TestTask.new(:test) do |t|
|
@@ -7,6 +20,52 @@ Rake::TestTask.new(:test) do |t|
|
|
7
20
|
t.ruby_opts = ['-rubygems'] if defined? Gem
|
8
21
|
end
|
9
22
|
|
23
|
+
# Bring in Rocco tasks
|
24
|
+
require 'rocco/tasks'
|
25
|
+
Rocco::make 'docs/'
|
26
|
+
|
27
|
+
desc 'Build rocco docs'
|
28
|
+
task :docs => :rocco
|
29
|
+
directory 'docs/'
|
30
|
+
|
31
|
+
desc 'Build docs and open in browser for the reading'
|
32
|
+
task :read => :docs do
|
33
|
+
sh 'open docs/rocco.html'
|
34
|
+
end
|
35
|
+
|
36
|
+
# Make index.html a copy of rocco.html
|
37
|
+
file 'docs/index.html' => 'docs/rocco.html' do |f|
|
38
|
+
cp 'docs/rocco.html', 'docs/index.html', :preserve => true
|
39
|
+
end
|
40
|
+
task :docs => 'docs/index.html'
|
41
|
+
CLEAN.include 'docs/index.html'
|
42
|
+
|
43
|
+
# Alias for docs task
|
44
|
+
task :doc => :docs
|
45
|
+
|
46
|
+
# GITHUB PAGES ===============================================================
|
47
|
+
|
48
|
+
desc 'Update gh-pages branch'
|
49
|
+
task :pages => ['docs/.git', :docs] do
|
50
|
+
rev = `git rev-parse --short HEAD`.strip
|
51
|
+
Dir.chdir 'docs' do
|
52
|
+
sh "git add *.html"
|
53
|
+
sh "git commit -m 'rebuild pages from #{rev}'" do |ok,res|
|
54
|
+
if ok
|
55
|
+
verbose { puts "gh-pages updated" }
|
56
|
+
sh "git push -q o HEAD:gh-pages"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Update the pages/ directory clone
|
63
|
+
file 'docs/.git' => ['docs/', '.git/refs/heads/gh-pages'] do |f|
|
64
|
+
sh "cd docs && git init -q && git remote add o ../.git" if !File.exist?(f.name)
|
65
|
+
sh "cd docs && git fetch -q o && git reset -q --hard o/gh-pages && touch ."
|
66
|
+
end
|
67
|
+
CLOBBER.include 'docs/.git'
|
68
|
+
|
10
69
|
# PACKAGING =================================================================
|
11
70
|
|
12
71
|
if defined?(Gem)
|
@@ -39,21 +98,18 @@ end
|
|
39
98
|
# GEMSPEC ===================================================================
|
40
99
|
|
41
100
|
file 'rocco.gemspec' => FileList['{lib,test,bin}/**','Rakefile'] do |f|
|
42
|
-
# read version from tilt.rb
|
43
101
|
version = File.read('lib/rocco.rb')[/VERSION = '(.*)'/] && $1
|
44
|
-
|
102
|
+
date = Time.now.strftime("%Y-%m-%d")
|
45
103
|
spec = File.
|
46
104
|
read(f.name).
|
47
105
|
sub(/s\.version\s*=\s*'.*'/, "s.version = '#{version}'")
|
48
106
|
parts = spec.split(" # = MANIFEST =\n")
|
49
|
-
# determine file list from git ls-files
|
50
107
|
files = `git ls-files`.
|
51
108
|
split("\n").sort.reject{ |file| file =~ /^\./ }.
|
52
109
|
map{ |file| " #{file}" }.join("\n")
|
53
|
-
# piece file back together and write...
|
54
110
|
parts[1] = " s.files = %w[\n#{files}\n ]\n"
|
55
111
|
spec = parts.join(" # = MANIFEST =\n")
|
56
|
-
spec.sub!(/s.date = '.*'/, "s.date = '#{
|
112
|
+
spec.sub!(/s.date = '.*'/, "s.date = '#{date}'")
|
57
113
|
File.open(f.name, 'w') { |io| io.write(spec) }
|
58
|
-
puts "
|
114
|
+
puts "#{f.name} #{version} (#{date})"
|
59
115
|
end
|
data/bin/rocco
CHANGED
data/lib/rocco.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# Rocco reads Ruby source files and produces annotated source documentation
|
5
5
|
# in HTML format. Comments are formatted with [Markdown][md] and presented
|
6
6
|
# alongside syntax highlighted code so as to give an annotation effect.
|
7
|
-
# This page is the result of running Rocco against its own source file.
|
7
|
+
# This page is the result of running Rocco against [its own source file][so].
|
8
8
|
#
|
9
9
|
# Most of this was written while waiting for [node.js][no] to build (so I
|
10
10
|
# could use Docco!). Docco's gorgeous HTML and CSS are taken verbatim.
|
@@ -12,7 +12,7 @@
|
|
12
12
|
# [CoffeeScript][co] and may be a bit easier to obtain and install in
|
13
13
|
# existing Ruby environments or where node doesn't run yet.
|
14
14
|
#
|
15
|
-
# Rocco
|
15
|
+
# Install Rocco with Rubygems:
|
16
16
|
#
|
17
17
|
# gem install rocco
|
18
18
|
#
|
@@ -27,19 +27,29 @@
|
|
27
27
|
# [do]: http://jashkenas.github.com/docco/
|
28
28
|
# [co]: http://coffeescript.org/
|
29
29
|
# [md]: http://daringfireball.net/projects/markdown/
|
30
|
+
# [so]: http://github.com/rtomayko/rocco/blob/master/lib/rocco.rb#commit
|
30
31
|
|
31
32
|
#### Prerequisites
|
32
33
|
|
33
|
-
#
|
34
|
-
#
|
35
|
-
|
34
|
+
# We'll need a Markdown library. [RDiscount][rd], if we're lucky. Otherwise,
|
35
|
+
# issue a warning and fall back on using BlueCloth.
|
36
|
+
#
|
37
|
+
# [rd]: http://github.com/rtomayko/rdiscount
|
38
|
+
begin
|
39
|
+
require 'rdiscount'
|
40
|
+
rescue LoadError => boom
|
41
|
+
warn "warn: #{boom}. trying bluecloth"
|
42
|
+
require 'bluecloth'
|
43
|
+
Markdown = BlueCloth
|
44
|
+
end
|
36
45
|
|
37
46
|
# We use [{{ mustache }}](http://defunkt.github.com/mustache/) for
|
38
|
-
# templating.
|
47
|
+
# HTML templating.
|
39
48
|
require 'mustache'
|
40
49
|
|
41
50
|
# Code is run through [Pygments](http://pygments.org/) for syntax
|
42
|
-
# highlighting. Fail fast if we can't find the `pygmentize`
|
51
|
+
# highlighting. Fail fast right here if we can't find the `pygmentize`
|
52
|
+
# program on PATH.
|
43
53
|
if ! ENV['PATH'].split(':').any? { |dir| File.exist?("#{dir}/pygmentize") }
|
44
54
|
fail "Pygments is required for syntax highlighting"
|
45
55
|
end
|
@@ -51,7 +61,7 @@ end
|
|
51
61
|
# whatever means necessary and return it as a string. With no `block`, the
|
52
62
|
# file is read to retrieve data.
|
53
63
|
class Rocco
|
54
|
-
VERSION = '0.
|
64
|
+
VERSION = '0.2'
|
55
65
|
|
56
66
|
def initialize(filename, &block)
|
57
67
|
@file = filename
|
@@ -61,8 +71,7 @@ class Rocco
|
|
61
71
|
else
|
62
72
|
File.read(filename)
|
63
73
|
end
|
64
|
-
|
65
|
-
@sections = highlight(parse(@data))
|
74
|
+
@sections = highlight(split(parse(@data)))
|
66
75
|
end
|
67
76
|
|
68
77
|
# The filename as given to `Rocco.new`.
|
@@ -82,7 +91,9 @@ class Rocco
|
|
82
91
|
|
83
92
|
#### Internal Parsing and Highlighting
|
84
93
|
|
85
|
-
# Parse the raw file data into a list of two-tuples.
|
94
|
+
# Parse the raw file data into a list of two-tuples. Each tuple has the
|
95
|
+
# form `[docs, code]` where both elements are arrays containing the
|
96
|
+
# raw lines parsed from the input file.
|
86
97
|
def parse(data)
|
87
98
|
sections = []
|
88
99
|
docs, code = [], []
|
@@ -94,8 +105,6 @@ class Rocco
|
|
94
105
|
docs, code = [], []
|
95
106
|
end
|
96
107
|
docs << line
|
97
|
-
when /^\s*$/
|
98
|
-
code << line
|
99
108
|
else
|
100
109
|
code << line
|
101
110
|
end
|
@@ -104,50 +113,59 @@ class Rocco
|
|
104
113
|
sections
|
105
114
|
end
|
106
115
|
|
107
|
-
# Take the
|
108
|
-
#
|
109
|
-
|
110
|
-
|
116
|
+
# Take the list of paired *sections* two-tuples and split into two
|
117
|
+
# separate lists: one holding the comments with leaders removed and
|
118
|
+
# one with the code blocks.
|
119
|
+
def split(sections)
|
111
120
|
docs_blocks, code_blocks = [], []
|
112
121
|
sections.each do |docs,code|
|
113
122
|
docs_blocks << docs.map { |line| line.sub(/^\s*#\s?/, '') }.join("\n")
|
114
123
|
code_blocks << code.join("\n")
|
115
124
|
end
|
125
|
+
[docs_blocks, code_blocks]
|
126
|
+
end
|
116
127
|
|
117
|
-
|
118
|
-
|
119
|
-
|
128
|
+
# Take the result of `split` and apply Markdown formatting to comments and
|
129
|
+
# syntax highlighting to source code.
|
130
|
+
def highlight(blocks)
|
131
|
+
docs_blocks, code_blocks = blocks
|
132
|
+
|
133
|
+
# Combine all docs blocks into a single big markdown document with section
|
134
|
+
# dividers and run through the Markdown processor. Then split it back out
|
135
|
+
# into separate sections.
|
136
|
+
markdown = docs_blocks.join("\n\n##### DIVIDER\n\n")
|
120
137
|
docs_html = Markdown.new(markdown, :smart).
|
121
138
|
to_html.
|
122
|
-
split(
|
139
|
+
split(/\n*<h5>DIVIDER<\/h5>\n*/m)
|
123
140
|
|
124
141
|
# Combine all code blocks into a single big stream and run through
|
125
|
-
#
|
126
|
-
#
|
142
|
+
# Pygments. We `popen` a read/write pygmentize process in the parent and
|
143
|
+
# then fork off a child process to write the input.
|
127
144
|
code_html = nil
|
128
145
|
open("|pygmentize -l ruby -f html", 'r+') do |fd|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
146
|
+
pid =
|
147
|
+
fork {
|
148
|
+
fd.close_read
|
149
|
+
fd.write code_blocks.join("\n\n# DIVIDER\n\n")
|
150
|
+
fd.close_write
|
151
|
+
exit!
|
152
|
+
}
|
136
153
|
fd.close_write
|
137
154
|
code_html = fd.read
|
138
155
|
fd.close_read
|
156
|
+
Process.wait(pid)
|
139
157
|
end
|
140
158
|
|
141
|
-
# Do some post-processing on the pygments output to
|
142
|
-
# partial `<pre>` blocks.
|
143
|
-
# document.
|
159
|
+
# Do some post-processing on the pygments output to split things back
|
160
|
+
# into sections and remove partial `<pre>` blocks.
|
144
161
|
code_html = code_html.
|
145
|
-
split(/\n
|
162
|
+
split(/\n*<span class="c1"># DIVIDER<\/span>\n*/m).
|
146
163
|
map { |code| code.sub(/\n?<div class="highlight"><pre>/m, '') }.
|
147
164
|
map { |code| code.sub(/\n?<\/pre><\/div>\n/m, '') }
|
148
165
|
|
149
|
-
#
|
150
|
-
# started with.
|
166
|
+
# Lastly, combine the docs and code lists back into a list of two-tuples.
|
151
167
|
docs_html.zip(code_html)
|
152
168
|
end
|
153
169
|
end
|
170
|
+
|
171
|
+
# And that's it.
|
data/lib/rocco/layout.mustache
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
</head>
|
8
8
|
<body>
|
9
9
|
<div id='container'>
|
10
|
+
<div id="background"></div>
|
10
11
|
<table cellspacing=0 cellpadding=0>
|
11
12
|
<thead>
|
12
13
|
<tr>
|
@@ -17,7 +18,12 @@
|
|
17
18
|
<tbody>
|
18
19
|
{{#sections}}
|
19
20
|
<tr id='section-{{ num }}'>
|
20
|
-
<td class=docs>
|
21
|
+
<td class=docs>
|
22
|
+
<div class="octowrap">
|
23
|
+
<a class="octothorpe" href="#section-{{ num }}">#</a>
|
24
|
+
</div>
|
25
|
+
{{{ docs }}}
|
26
|
+
</td>
|
21
27
|
<td class=code>
|
22
28
|
<div class='highlight'><pre>{{{ code }}}</pre></div>
|
23
29
|
</td>
|
data/lib/rocco/tasks.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
#### Rocco Rake Tasks
|
2
|
+
#
|
3
|
+
# To use the Rocco Rake tasks, require `rocco/tasks` in your `Rakefile`
|
4
|
+
# and define a Rake task with `rocco_task`. In its simplest form, `rocco_task`
|
5
|
+
# takes the path to a destination directory where HTML docs should be built:
|
6
|
+
#
|
7
|
+
# require 'rocco/tasks'
|
8
|
+
#
|
9
|
+
# desc "Build Rocco Docs"
|
10
|
+
# Rocco::make 'docs/'
|
11
|
+
#
|
12
|
+
# This creates a `:rocco` rake task, which can then be run with:
|
13
|
+
#
|
14
|
+
# rake rocco
|
15
|
+
#
|
16
|
+
# It's a good idea to guard against Rocco not being available, since your
|
17
|
+
# Rakefile will fail to load otherwise. Consider doing something like this,
|
18
|
+
# so that your Rakefile will still work
|
19
|
+
#
|
20
|
+
# begin
|
21
|
+
# require 'rocco/tasks'
|
22
|
+
# Rocco::make 'docs/'
|
23
|
+
# rescue LoadError
|
24
|
+
# warn "#$! -- rocco tasks not loaded."
|
25
|
+
# task :rocco
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# It's also possible to pass a glob pattern:
|
29
|
+
#
|
30
|
+
# Rocco::make 'html/', 'lib/thing/**/*.rb'
|
31
|
+
#
|
32
|
+
# Or a list of glob patterns:
|
33
|
+
#
|
34
|
+
# Rocco::make 'html/', ['lib/thing.rb', 'lib/thing/*.rb']
|
35
|
+
#
|
36
|
+
|
37
|
+
# Might be nice to defer this until we actually need to build docs but this
|
38
|
+
# will have to do for now.
|
39
|
+
require 'rocco'
|
40
|
+
|
41
|
+
# Reopen the Rocco class and add a `make` class method. This is a simple bit
|
42
|
+
# of sugar over `Rocco::Task.new`. If you want your Rake task to be named
|
43
|
+
# something other than `:rocco`, you can use `Rocco::Task` directly.
|
44
|
+
class Rocco
|
45
|
+
def self.make(dest='docs/', source_files='lib/**/*.rb')
|
46
|
+
Task.new(:rocco, dest, source_files)
|
47
|
+
end
|
48
|
+
|
49
|
+
# `Rocco::Task.new` takes a task name, the destination directory docs
|
50
|
+
# should be built under, and a source file pattern or file list.
|
51
|
+
class Task
|
52
|
+
def initialize(task_name, dest='docs/', sources='lib/**/*.rb')
|
53
|
+
@name = task_name
|
54
|
+
@dest = dest[-1] == ?/ ? dest : "#{dest}/"
|
55
|
+
@sources = FileList[sources]
|
56
|
+
|
57
|
+
# Make sure there's a `directory` task defined for our destination.
|
58
|
+
define_directory_task @dest
|
59
|
+
|
60
|
+
# Run over the source file list, constructing destination filenames
|
61
|
+
# and defining file tasks.
|
62
|
+
@sources.each do |source_file|
|
63
|
+
dest_file = File.basename(source_file, '.rb') + '.html'
|
64
|
+
define_file_task source_file, "#{@dest}#{dest_file}"
|
65
|
+
|
66
|
+
# If `rake/clean` was required, add the generated files to the list.
|
67
|
+
# That way all Rocco generated are removed when running `rake clean`.
|
68
|
+
CLEAN.include "#{@dest}#{dest_file}" if defined? CLEAN
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Define the destination directory task and make the `:rocco` task depend
|
73
|
+
# on it. This causes the destination directory to be created if it doesn't
|
74
|
+
# already exist.
|
75
|
+
def define_directory_task(path)
|
76
|
+
directory path
|
77
|
+
task @name => path
|
78
|
+
end
|
79
|
+
|
80
|
+
# Setup a `file` task for a single Rocco output file (`dest_file`). It
|
81
|
+
# depends on the source file, the destination directory, and all of Rocco's
|
82
|
+
# internal source code, so that the destination file is rebuilt when any of
|
83
|
+
# those changes.
|
84
|
+
#
|
85
|
+
# You can run these tasks directly with Rake:
|
86
|
+
#
|
87
|
+
# rake docs/foo.html docs/bar.html
|
88
|
+
#
|
89
|
+
# ... would generate the `foo.html` and `bar.html` files but only if they
|
90
|
+
# don't already exist or one of their dependencies was changed.
|
91
|
+
def define_file_task(source_file, dest_file)
|
92
|
+
prerequisites = [@dest, source_file] + rocco_source_files
|
93
|
+
file dest_file => prerequisites do |f|
|
94
|
+
verbose { puts "rocco: #{source_file} -> #{dest_file}" }
|
95
|
+
rocco = Rocco.new(source_file)
|
96
|
+
File.open(dest_file, 'wb') { |fd| fd.write(rocco.to_html) }
|
97
|
+
end
|
98
|
+
task @name => dest_file
|
99
|
+
end
|
100
|
+
|
101
|
+
# Return a `FileList` that includes all of Roccos source files. This causes
|
102
|
+
# output files to be regenerated properly when someone upgrades the Rocco
|
103
|
+
# library.
|
104
|
+
def rocco_source_files
|
105
|
+
libdir = File.expand_path('../..', __FILE__)
|
106
|
+
FileList["#{libdir}/rocco.rb", "#{libdir}/rocco/**"]
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
data/rocco.gemspec
CHANGED
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
|
|
3
3
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
4
|
|
5
5
|
s.name = 'rocco'
|
6
|
-
s.version = '0.
|
7
|
-
s.date = '2010-03-
|
6
|
+
s.version = '0.2'
|
7
|
+
s.date = '2010-03-11'
|
8
8
|
|
9
9
|
s.description = "Docco in Ruby"
|
10
10
|
s.summary = s.description
|
@@ -15,12 +15,13 @@ Gem::Specification.new do |s|
|
|
15
15
|
# = MANIFEST =
|
16
16
|
s.files = %w[
|
17
17
|
COPYING
|
18
|
-
README
|
18
|
+
README
|
19
19
|
Rakefile
|
20
20
|
bin/rocco
|
21
21
|
lib/rocco.rb
|
22
22
|
lib/rocco/layout.mustache
|
23
23
|
lib/rocco/layout.rb
|
24
|
+
lib/rocco/tasks.rb
|
24
25
|
rocco.gemspec
|
25
26
|
]
|
26
27
|
# = MANIFEST =
|
metadata
CHANGED
@@ -4,8 +4,8 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
version: "0.
|
7
|
+
- 2
|
8
|
+
version: "0.2"
|
9
9
|
platform: ruby
|
10
10
|
authors:
|
11
11
|
- Ryan Tomayko
|
@@ -13,7 +13,7 @@ autorequire:
|
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
15
|
|
16
|
-
date: 2010-03-
|
16
|
+
date: 2010-03-11 00:00:00 -08:00
|
17
17
|
default_executable:
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
@@ -50,12 +50,13 @@ extra_rdoc_files: []
|
|
50
50
|
|
51
51
|
files:
|
52
52
|
- COPYING
|
53
|
-
- README
|
53
|
+
- README
|
54
54
|
- Rakefile
|
55
55
|
- bin/rocco
|
56
56
|
- lib/rocco.rb
|
57
57
|
- lib/rocco/layout.mustache
|
58
58
|
- lib/rocco/layout.rb
|
59
|
+
- lib/rocco/tasks.rb
|
59
60
|
- rocco.gemspec
|
60
61
|
has_rdoc: true
|
61
62
|
homepage: http://rtomayko.github.com/rocco/
|
data/README.md
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
# rocco
|
2
|
-
|
3
|
-
This is a Ruby port of [Docco](http://jashkenas.github.com/docco/), a
|
4
|
-
_quick-and-dirty, hundred-line-long, literate-programming-style
|
5
|
-
documentation generator_.
|
6
|
-
|
7
|
-
See the [Rocco generated documentation](http://rtomayko.github.com/rocco/)
|
8
|
-
for more information.
|