Overview
RDoc processes Ruby source files to generate documentation from specially formatted comments and code structure. Ruby includes RDoc as part of the standard library, providing both command-line tools and programmatic APIs for documentation generation.
The primary component is the RDoc::RDoc
class, which coordinates the documentation generation process. RDoc parses Ruby files using RDoc::Parser
classes, extracts documentation from comments using RDoc::Markup
, and generates output through RDoc::Generator
classes.
require 'rdoc/rdoc'
rdoc = RDoc::RDoc.new
rdoc.document(['lib/myclass.rb'])
RDoc recognizes several comment formats. Single-line comments starting with #
become documentation when placed before classes, modules, or methods. Multi-line comments using =begin rdoc
and =end
provide block documentation.
# This method calculates the factorial of a number
#
# Returns the factorial as an integer
def factorial(n)
return 1 if n <= 1
n * factorial(n - 1)
end
The markup system supports formatting directives like *bold*
, _italic_
, and +code+
. Lists use *
or 1.
prefixes, and code blocks are indented or fenced with ---
.
RDoc generates multiple output formats including HTML, PDF, and plain text. The default HTML generator creates navigable documentation with class hierarchies, method indices, and cross-references. Custom templates and generators allow output customization.
Basic Usage
RDoc operates through command-line invocation or programmatic control. The rdoc
command processes source files and generates documentation in a specified output directory.
# Command line usage
# rdoc lib/*.rb --output doc --format html
The programmatic interface provides finer control over the documentation process. Create an RDoc::RDoc
instance, configure options, and specify source files.
require 'rdoc/rdoc'
rdoc = RDoc::RDoc.new
rdoc.options.op_dir = 'documentation'
rdoc.options.fmt = 'html'
rdoc.options.files = ['lib/calculator.rb', 'lib/parser.rb']
rdoc.document(['lib'])
Documentation comments follow specific conventions. Method documentation appears immediately before the method definition. Parameter documentation uses the param
directive, and return values use return
.
##
# Parses mathematical expressions and evaluates results
#
# param expression [String] the mathematical expression to parse
# param variables [Hash] variable substitutions (default: {})
# return [Numeric] the calculated result
# raises [ParseError] when expression syntax is invalid
def evaluate(expression, variables = {})
# method implementation
end
Class and module documentation appears after the class or module declaration. Use include
and exclude
directives to control which elements appear in generated documentation.
##
# Mathematical expression parser and evaluator
#
# This class provides methods for parsing and evaluating
# mathematical expressions with variable substitution.
#
# include Calculator::Parser
# exclude Calculator::InternalMethods
class Calculator
# class implementation
end
RDoc processes visibility modifiers like private
and protected
, excluding private methods from documentation by default. Override this behavior with the --visibility
option or :doc:
directive.
private
##
# :doc:
# Internal calculation method exposed in documentation
def internal_calculate(value)
# implementation
end
Advanced Usage
RDoc supports extensive customization through templates, custom generators, and markup extensions. Templates control HTML output structure and styling, while generators create different output formats entirely.
Custom templates modify the default HTML appearance. Create template directories with erb files for different page types. The template system uses instance variables from RDoc classes to populate content.
# Custom template structure:
# templates/
# custom/
# class.rhtml
# method.rhtml
# index.rhtml
# style.css
rdoc = RDoc::RDoc.new
rdoc.options.template = 'custom'
rdoc.options.template_dir = 'templates'
rdoc.document(['lib'])
Generator classes extend RDoc::Generator
to create new output formats. Implement generate
method to process the documentation tree and create output files.
class JSONGenerator < RDoc::Generator
def initialize(options)
@options = options
@output_dir = options.op_dir
end
def generate(top_level)
classes = []
top_level.classes_and_modules.each do |klass|
class_data = {
name: klass.full_name,
superclass: klass.superclass&.full_name,
methods: klass.method_list.map do |method|
{
name: method.name,
params: method.params,
comment: method.comment.to_s
}
end
}
classes << class_data
end
File.write(File.join(@output_dir, 'documentation.json'),
JSON.pretty_generate(classes))
end
end
RDoc::RDoc.add_generator(JSONGenerator)
Markup extensions add custom formatting directives. Extend RDoc::Markup::ToHtml
or other formatter classes to implement new markup syntax.
class CustomMarkup < RDoc::Markup::ToHtml
def handle_special_CUSTOM(special)
content = special.text
"<span class='custom-format'>#{content}</span>"
end
end
# Register the custom handler
RDoc::Markup.add_special(/\{custom:([^}]+)\}/, :CUSTOM)
Advanced parsing options control which files RDoc processes and how it interprets code structure. Use RDoc::Options
to configure parsing behavior, file patterns, and exclusion rules.
require 'rdoc/options'
options = RDoc::Options.new
options.files = ['lib/**/*.rb', 'ext/**/*.c']
options.exclude = ['lib/internal/**/*.rb']
options.main_page = 'README.rdoc'
options.title = 'Project Documentation'
options.charset = 'UTF-8'
rdoc = RDoc::RDoc.new
rdoc.options = options
rdoc.document(['lib', 'ext'])
Production Patterns
RDoc integrates into development workflows through automated documentation generation, continuous integration, and deployment processes. Modern Ruby projects typically generate documentation as part of their build pipeline.
Rails applications use RDoc for API documentation generation. Configure RDoc through rake doc:app
tasks or custom Rake tasks that process application-specific files and generate documentation with project-specific templates.
# Rakefile
namespace :doc do
desc "Generate application documentation"
task :generate do
require 'rdoc/rdoc'
rdoc = RDoc::RDoc.new
rdoc.options.op_dir = 'doc/api'
rdoc.options.fmt = 'html'
rdoc.options.title = "#{Rails.application.class.parent} API Documentation"
rdoc.options.main_page = 'app/README.rdoc'
rdoc.options.exclude = ['app/assets/**/*', 'tmp/**/*']
rdoc.document(['app/models', 'app/controllers', 'app/services', 'lib'])
end
end
Gem development incorporates RDoc documentation that publishes to RubyGems.org. Configure gem specifications to include documentation files and ensure proper markup formatting for online viewing.
# gemspec configuration
Gem::Specification.new do |spec|
spec.name = 'my_gem'
spec.files = Dir['lib/**/*.rb', 'README.rdoc', 'LICENSE']
spec.extra_rdoc_files = ['README.rdoc', 'CHANGELOG.rdoc']
spec.rdoc_options = ['--main', 'README.rdoc', '--charset=UTF-8']
end
# Custom documentation task
desc "Generate and publish documentation"
task :docs do
system("rdoc --main README.rdoc --op doc lib/")
system("rsync -av doc/ user@server:/var/www/docs/")
end
Continuous integration systems automate documentation generation and validation. GitHub Actions workflows can generate documentation on each commit and deploy to GitHub Pages or other hosting platforms.
# .github/workflows/docs.yml
name: Generate Documentation
on: [push]
jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: 3.0
- run: gem install rdoc
- run: rdoc --output docs lib/
- uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
Documentation hosting requires careful consideration of file organization and linking. Generate documentation with appropriate base URLs and ensure asset paths work correctly when deployed to subdirectories or content delivery networks.
# Production documentation generation
rdoc = RDoc::RDoc.new
rdoc.options.op_dir = 'public/api-docs'
rdoc.options.fmt = 'html'
rdoc.options.hyperlink_all = true
rdoc.options.show_hash = true
rdoc.options.webcvs = 'https://github.com/user/repo/blob/main/'
rdoc.document(['lib'])
# Post-process for CDN deployment
Dir.glob('public/api-docs/**/*.html') do |file|
content = File.read(file)
content.gsub!(/href="([^"]+)\.html"/, 'href="\1/"')
File.write(file, content)
end
Common Pitfalls
RDoc markup syntax creates frequent confusion, particularly with formatting directives and whitespace sensitivity. Improper spacing around markup elements prevents rendering, and mixing markup styles produces unexpected results.
# Incorrect markup - missing spaces
# This *bold*text and +code+sample won't format properly
# Correct markup - proper spacing
# This *bold* text and +code+ sample formats correctly
# Incorrect list formatting
# *Item one
# *Item two
# Correct list formatting
# * Item one
# * Item two
Documentation comments require specific positioning relative to code elements. Comments separated from their target by blank lines or other code elements don't associate correctly, resulting in missing or misplaced documentation.
# This comment won't document the method below
# because of the intervening blank line
def problematic_method
end
# This comment properly documents the method
# because it immediately precedes it
def documented_method
end
private
# This comment documents the wrong method
# because private affects visibility
def private_method
end
Template and generator conflicts occur when custom templates reference variables that don't exist or use incompatible markup. RDoc generates errors or produces empty output when templates access undefined instance variables or call non-existent methods.
# Problematic template code
<% @classes.each do |klass| %>
<h2><%= klass.undefined_method %></h2> # Error: method doesn't exist
<% end %>
# Safe template code with error checking
<% @classes.each do |klass| %>
<h2><%= klass.respond_to?(:full_name) ? klass.full_name : klass.name %></h2>
<% end %>
File encoding issues cause RDoc parsing failures when source files contain non-ASCII characters without proper encoding declarations. RDoc assumes UTF-8 encoding but fails when encountering incompatible byte sequences.
# Add encoding declaration to files with non-ASCII content
# encoding: utf-8
##
# Handles currency symbols like € and ¥
class CurrencyConverter
end
Cross-reference linking breaks when class or method names change after documentation generation. RDoc creates static links that become invalid when refactoring code, requiring regeneration to fix broken internal references.
# Original class name creates links
class DataProcessor
# See DataProcessor#validate for details
def process(data)
end
end
# Renamed class breaks existing links
class AdvancedProcessor # Links to DataProcessor still exist in old docs
def process(data)
end
end
Visibility modifier placement affects documentation generation in unexpected ways. Methods marked private after their documentation comments still appear in output, while methods made private before their comments may not appear at all.
# Documentation appears despite private modifier
##
# This method will appear in documentation
def should_be_hidden
end
private :should_be_hidden
# Documentation doesn't appear
private
##
# This method won't appear without :doc: directive
def truly_hidden
end
Reference
Core Classes
Class | Purpose | Key Methods |
---|---|---|
RDoc::RDoc |
Main documentation coordinator | #document , #options |
RDoc::Options |
Configuration management | #parse , #op_dir , #fmt |
RDoc::Parser |
Source code parsing | #parse , #scan |
RDoc::Markup |
Comment formatting | #convert , #add_special |
RDoc::Generator |
Output generation | #generate , #class_dir |
Command Line Options
Option | Description | Default |
---|---|---|
--output DIR |
Output directory | doc/ |
--format FORMAT |
Output format | html |
--main FILE |
Main page file | none |
--title TITLE |
Documentation title | Directory name |
--exclude PATTERN |
Files to exclude | none |
--visibility LEVEL |
Visibility level | protected |
--charset ENCODING |
Character encoding | UTF-8 |
--hyperlink-all |
Link all words | false |
Markup Directives
Syntax | Renders As | Notes |
---|---|---|
*bold* |
bold | Requires surrounding spaces |
_italic_ |
italic | Requires surrounding spaces |
+code+ |
code |
Inline code formatting |
--- |
Code block | Indented code block delimiter |
* item |
• item | Unordered list item |
1. item |
1. item | Ordered list item |
[text](url) |
text | Markdown-style links |
== Header |
Header | Section header |
Documentation Directives
Directive | Purpose | Example |
---|---|---|
:nodoc: |
Exclude from documentation | class Secret # :nodoc: |
:doc: |
Include despite visibility | private; def method # :doc: |
include Module |
Include module documentation | # include Enumerable |
exclude Method |
Exclude specific methods | # exclude #internal_method |
Generator Types
Generator | Output Format | File Extension |
---|---|---|
html |
HTML pages | .html |
ri |
Ruby Interactive | .ri |
xml |
XML format | .xml |
pdf |
PDF document | .pdf |
Error Types
Error | Cause | Solution |
---|---|---|
RDoc::Error |
General RDoc failure | Check file permissions and syntax |
Encoding::InvalidByteSequenceError |
Invalid character encoding | Add encoding declaration |
NoMethodError |
Template variable undefined | Update template or check RDoc version |
Errno::ENOENT |
File not found | Verify file paths and existence |