CrackedRuby logo

CrackedRuby

RDoc

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