nov
3
0
RDoc Introduction
Automatically generating documentation from source code has been available as far back as 1993. Its so common now that its expected to be available in any mainstream programming languages. I’ve seen it most commonly in Object Oriented languages offering nicely formatted descriptions of classs and their public methods/attributes.
Consistency is Nice
The main advantage I see with automatically generated documentation is that it is consistent. Take Javadocs for instance. They are all the same. When a developer wants to work with a Java library, they expect Javadocs. Why? Because they are familiar with them. They can easily navigate them and quickly find whatever it is that they are looking for. Documentation in any other way would require wasting time learning how to use/navigate it searching for what you want to know.
RDoc is Ruby’s documentation generator. You see RDoc generated documentation all over the place in Ruby. See YAML, Hpricot, or even core classes like Array.
So, I felt if I want to continue using Ruby I should at least learn how its handled. It turns out that its easier then I thought. I’m a huge fan of Markdown syntax and RDoc turns out to be pretty close to that. So, here is what I think is all you need to know to handle producing some simple, yet thorough, documentation for a class.
RDoc Resources
Start by updating your rdoc. The latest version at the time of writing is 2.2.1. The gem provides you with the rdoc and ri tools so that you can both generate and display documentation from the command line. Here is how you can install them:
shell> sudo gem install rdoc
The best online resources I found were not surprisingly:
- RDoc’s documentation itself – an RDoc on RDoc… actually its RDoc’s classes but its overview is helpful.
- An Older Writeup by Dave Thomas – has a similar example
- Markdown Syntax – Very similar to what is used in RDoc comments
Structure
Here is a basic example that shows the structure of the RDoc as it describes a File, Class, Attributes, and Methods. The placement of the comments is important. RDoc comments are always on top of what they are documenting:
# Documentation for the file itself
# There should be a blank line between this and any class
# definition to separate the documentation about the file
# and the class. If there is no space then the entire text
# is used for both the file and the class, no different.
# Documentation for the class itself.
# This will appear at the top of the page specific to this
# class, before any other content.
# Documentation for an attribute
# To documentation each attribute you must make individual
# calls to attr_accessor, attr_reader, and attr_writer.
# Appears next to the attribute name in the attrs section
attr_accessor :sides
# Documentation for the constructor
# Corresponds to the `new` method
@sides = sides
end
# Documentation for a method
Array.new(times).map {1+rand(@sides) }
end
# Documentation for a method
roll(1).first > num
end
end
Running `rdoc` on that file creates this documentation.
Style
Rich documentation makes the important parts stand out. It makes use of HTML’s expressive power and enables lists, headers, links, bold/italics, code, and other presentation helpers. I’ll now document the Dice class and add some style and realistic content.
# == sample.rb
# This file contains the Dice class definition and it runs
# some simple test code on a 16 sided dice. A 20 dice
# roll fight again the COMPUTER who always rolls 10s!
#
# Multi-sided dice class. The number of sides is determined
# in the constructor, or later on by accessing the _sides_
# attribute.
#
# == Summary
#
# A #single_roll returns a single integer from 1 to the
# number of sides, _inclusive_. However, if you want to
# roll multiple times you can can use the #roll method,
# specifying the number of rolls you want, and you will
# get an Array with the values of all the rolls!
#
# == Example
#
# dice = Dice.new(8) # An eight sided dice
# four = dice.roll(4) # An Array containing 4 rolls
# sum = four.inject(0) { |mem,i| mem+i } # Sum of rolls
#
# == Contact
#
# Author:: Joseph Pecoraro (mailto:joepeck02@gmail.com)
# Website:: http://blog.bogojoker.com
# Date:: Saturday November 29, 2008
#
# Number of sides on the dice
attr_accessor :sides
# Create a dice with `sides` of dice.
# Defaults to 6.
@sides = sides
end
# Returns an array of size `times` containing
# a group of dice rolls.
Array.new(times).map { single_roll }
end
# Returns the value of a single dice roll. The
# values are from 1 to @sides _inclusive_.
1+rand(@sides)
end
# A single roll challenge:
# * makes a single_roll
# * returns true if the roll was strictly greater
# then the given number
# * returns false otherwise
single_roll > num
end
end
# Note that this is a constant, which is special
# and it is documented like a Class Attribute.
# This is in the RDoc generated documentation for
# the file.
COMPUTER = 10
# Note that these comments, for generic code
# are not in the RDoc generated documentation.
dice = Dice.new(16)
winCount = loseCount = 0
20.times do
if dice.beat(COMPUTER)
winCount += 1
else
loseCount += 1
end
end
# Output
puts "You won times and lost times!"
puts "Muhahah. Try again later!!" if winCount < loseCount
puts "Well Played. I'll get you next time." if winCount > loseCount
puts "What a match! Boy that was fun." if winCount == loseCount
That generates this documentation.
Specifics
There are some subtle points that make this documentation format nicely. I’ll point them out and explain them. Most of this is straight from the above resources, however some of it I could not find documented anywhere.
- The file documentation links to the Dice class. Furthermore the Class documentation links down to the single_roll and roll methods. This is because:
Names of classes, source files, and any method names containing an underscore or preceded by a hash character are automatically hyperlinked from comment text to their description.
- sample.rb was a filename and so it was automatically linked.
- Dice was the name of a class and so it was automatically linked.
- single_roll had an underscore and happened to be a method name so it was automatically linked in a few places.
- #roll had a hash character signifying that it should be linked.
- Sections begin with a “=” or a “==”. I prefer to use double, because it stands out more in the source code. Technically a single “=” becomes a level 1 header, and a double becomes a level 2 header. However, they both display the same.
- URIs like http://blog.bogojoker.com and mailto:email are automatically turned into links and formatted nicely.
- Bold, Italics, and Typewriter Text can be quickly formated much like Markdown:
_italic_ or <em>italic</em>
*bold* or <b>bold</b>
+typewriter+ or <tt>typewriter</tt> - Code is displayed if each line
- Tabular Labeled List, like the Contact information, are formatted like:
label:: description 1
label2:: both descriptions will line up - Formatting source code is like Markdown. The code that you want formatted must be indented with a few spaces. As long as the indention is maintained the text will display as source code in the HTML documentation.
- Formatting lists is again like Markdown. Just use *’s or -‘s and they will turn into bullet points. For numbered lists just use numbers followed by a dot and they will be formatted automatically.
Final Notes on `rdoc` itself
When I created the final documentation above I used a few of rdoc’s command line switches to customize the output. What I actually used was:
shell> rdoc --title="Dice Documentation" --line-numbers --tab-width=2
The title switch changed the <title> for the documentation page, and the other two deal with formatting the htmlized source code that RDoc shows when you click on the function name to view the source in the documentation. There are plenty of command line switches. To view the full list do:
shell> rdoc --help
A few useful switches are “–ri” to create ri documentation so you can access your classes from the command line. Also you can output to several formats. For instance you can make a PDF using “–format=texinfo” then using `texi2pdf` on the texinfo file. The PDF doesn’t look that bad, here is my example as a PDF.
NOTE: Finding the generators was tricky. I had to check out the rdoc source code and find the different generators. If anyone knows an easier way to check what generators are available, please let me know.
I hope this helps some people using RDoc for their classes. Enjoy.