123456789_123456789_123456789_123456789_123456789_

RDoc Project Guide for AI Agents

Project Overview

RDoc is Ruby's default documentation generation tool that produces HTML and command-line documentation for Ruby projects. It parses Ruby source code, C extensions, RBS signature files, and markup files to generate documentation.

Key Development Commands

Testing

# Run all tests (default task)
bundle exec rake

# Run unit tests only (excludes RubyGems integration)
bundle exec rake normal_test

# Run RubyGems integration tests only
bundle exec rake rubygems_test

# Verify generated parser files are current (CI check)
bundle exec rake verify_generated

Test Framework: Test::Unit with test-unit gem Test Location: test/ directory Test Helper: test/lib/helper.rb

Linting

RuboCop (Ruby Linting)

# Check Ruby code style
bundle exec rubocop

# Auto-fix style issues
bundle exec rubocop -A

Configuration: .rubocop.yml

Herb Linter (ERB/RHTML Files)

# Lint ERB template files
npx @herb-tools/linter "**/*.rhtml"

# Lint specific directory
npx @herb-tools/linter "lib/**/*.rhtml"

Template Location: lib/rdoc/generator/template/**/*.rhtml CI Workflow: .github/workflows/lint.yml

Stylelint (CSS Files)

# Lint CSS files
npm run lint:css

# Auto-fix style issues
npm run lint:css -- --fix

# Lint specific file
npx stylelint "lib/rdoc/generator/template/aliki/css/rdoc.css"

Configuration: .stylelintrc.json Features:

Type annotations

Annotate method types using Sorbet flavored RBS in inline comments. For more information about RBS syntax, see the documentation.

A few examples:

# Method that receives an integer and doesn't return anything
#: (Integer) -> void
def foo(something); end

# Method that receives a string and returns an integer
#: (String) -> Integer
def bar(something)
   123
end

# Method that doesn't accept arguments and returns a hash of symbol to string
#: () -> Hash[Symbol, String]
def bar
   { key: "value" }
end

# Method that accepts a block, which yields a single integer argument and returns whatever the block returns
#: [T] () { (Integer) -> T } -> T
def bar
   yield(5)
end

Documentation Generation

# Generate documentation (creates _site directory)
bundle exec rake rdoc

# Force regenerate documentation
bundle exec rake rerdoc

# Show documentation coverage
bundle exec rake rdoc:coverage
bundle exec rake coverage

# Start live-reloading preview server (port 4000)
bundle exec rake rdoc:server

# Or via CLI with custom port
bundle exec rdoc --server=8080

Output Directory: _site/ (GitHub Pages compatible) Configuration: .rdoc_options

Parser Generation

RDoc uses generated parsers for Markdown and RD formats:

# Generate all parser files from sources
bundle exec rake generate

# Remove generated parser files
bundle exec rake clean

Generated Files:

Note: These files are auto-generated and should not be edited manually. Always regenerate after modifying source .ry or .kpeg files.

Building and Releasing

# Build gem package
bundle exec rake build

# Install gem locally
bundle exec rake install

# Create tag and push to rubygems.org
bundle exec rake release

Project Structure

lib/rdoc/
├── rdoc.rb                    # Main entry point (RDoc::RDoc class)
├── version.rb                 # Version constant
├── task.rb                    # Rake task integration
├── parser/                    # Source code parsers (Ruby, C, RBS, Markdown, RD)
│   ├── ruby.rb                # Prism-based Ruby parser
│   ├── c.rb                   # C extension parser
│   ├── rbs.rb                 # RBS signature parser
│   └── ...
├── server.rb                  # Live-reloading preview server (rdoc --server)
├── generator/                 # Documentation generators
│   ├── aliki.rb               # HTML generator (default theme)
│   ├── darkfish.rb            # HTML generator (deprecated, will be removed in v9.0)
│   ├── markup.rb              # Markup format generator
│   ├── ri.rb                  # RI command generator
│   └── template/              # ERB templates (.rhtml files)
│       ├── aliki/             # Aliki theme (default)
│       └── darkfish/          # Darkfish theme (deprecated)
├── markup/                    # Markup parsing and formatting
├── code_object/               # AST objects for documented items
├── markdown/                  # Markdown parsing
├── rd/                        # RD format parsing
└── ri/                        # RI (Ruby Info) tool

test/                          # 79 test files
├── lib/helper.rb              # Test helpers
└── rdoc/                      # Main test directory

exe/
├── rdoc                       # rdoc command executable
└── ri                         # ri command executable

Important Files

Configuration

CI/CD

Documentation

Architecture Notes

Parsers and Generators

Parser tests live under test/rdoc/parser/, including RDocParserRubyTest (test/rdoc/parser/ruby_test.rb) and RDocParserRBSTest (test/rdoc/parser/rbs_test.rb).

RBS Documentation Input and Signature Merging

Selected .rbs files are first-class documentation input through ::RDoc::Parser::RBS. RBS declarations can create documentation for classes, modules, methods, attributes, and constants, or extend objects already documented from Ruby source.

RBS files under the project's sig/ directory are also auto-discovered by ::RDoc::RDoc for type signature merging and live preview bookkeeping. Keep this distinction clear: .rbs parsing builds documentation objects, while sig/**/*.rbs auto-discovery feeds the existing RBS type-signature merge path.

Code Object Model and Constant Aliases

The code-object tree (lib/rdoc/code_object/) is built in two phases. Parse-time work happens in the parsers and ::RDoc::Context (add_constant, add_module_alias). Finalization happens in Store#complete, which calls ClassModule#update_aliases on each container — this is where forward-reference aliases (Foo = Bar parsed before class Bar in another file) get resolved via Constant#resolved_alias_target.

If you add an invariant to one of these paths — for example the Context#add_module_alias collision guard that refuses to clobber an existing class — mirror it on the other. The two paths are not interchangeable: add_module_alias runs against partial store state and does extra bookkeeping (unmatched_constant_alias); update_aliases runs against the finalized store and writes the alias copies into classes_hash / modules_hash.

Known limitation: lexical scope. Context#find_enclosing_module_named walks the syntactic parent chain as a stand-in for Ruby's lexical constant lookup. The prism parser doesn't represent module nesting via the parent chain at all (see the docstring on Context#find_enclosing_module_named), so alias resolution in deeply nested or re-opened classes can pick the wrong target. Fixing this properly requires capturing lexical scope at parse time — a feature change rather than an incremental fix.

Marshal / ri Data Compatibility

::RDoc::Constant, ::RDoc::ClassModule, and other code objects implement marshal_dump / marshal_load to persist ri data on disk, gated by a per-class MARSHAL_VERSION constant. The ri CLI (lib/rdoc/ri/driver.rb) and the ri --server servlet (lib/rdoc/ri/servlet.rb) read this format. Any change that alters the dumped array — adding/removing slots, reinterpreting an existing slot's meaning — needs MARSHAL_VERSION bumped and the loader taught to handle older payloads, otherwise locally-cached .ri data from an earlier rdoc version stops loading after an upgrade.

Live Preview Server (::RDoc::Server)

The server (lib/rdoc/server.rb) provides rdoc --server for live documentation preview.

Architecture:

Key files:

Known limitations:

Common Workflows

Do NOT commit anything. Ask the developer to review the changes after tasks are finished.

NEVER pushes code to any repositories.

Making Code Changes

Use Red, Green, Refactor approach:

  1. Ensure Ruby version: Verify you're using Ruby 3.3.0+ (prepend chruby if needed)
  2. Red - Write failing tests: Add tests that fail for the new behavior
  3. Verify failure: Run bundle exec rake to confirm tests fail as expected
  4. Green - Make it work: Implement the minimum code to make tests pass
  5. Refactor - Make it right: Improve code quality while keeping tests green
    • Run bundle exec rake after each refactor to ensure tests still pass
    • Iterate on steps 4-5 as needed
  6. Lint your changes:
    • Ruby code: bundle exec rubocop -A (auto-fix when possible)
    • ERB templates: npx @herb-tools/linter "**/*.rhtml" (if modified)
    • CSS files: npm run lint:css -- --fix (if modified)

Modifying Parsers

  1. Edit source files (.ry or .kpeg)
  2. Regenerate: bundle exec rake generate
  3. Verify: bundle exec rake verify_generated
  4. Run tests: bundle exec rake

Updating Documentation

  1. Modify documentation comments in source
  2. Regenerate: bundle exec rake rerdoc
  3. Check output in _site/ directory
  4. Check coverage: bundle exec rake coverage

Modifying Markup Reference Documentation

When editing markup reference documentation, such as doc/markup_reference/markdown.md and doc/markup_reference/rdoc.rdoc:

  1. Always verify rendering - After making changes, test that the content renders correctly using Ruby:

    For Markdown files:

    ruby -r rdoc -r rdoc/markdown -e '
    md = RDoc::Markdown.new
    doc = md.parse("YOUR CONTENT HERE")
    formatter = RDoc::Markup::ToHtml.new(RDoc::Options.new)
    puts formatter.convert(doc)
    '

    For RDoc files:

    ruby -r rdoc -e '
    parser = RDoc::Markup::Parser.new
    doc = parser.parse("YOUR CONTENT HERE")
    formatter = RDoc::Markup::ToHtml.new(RDoc::Options.new)
    puts formatter.convert(doc)
    '
  2. Watch for rendering issues:

    • Backtick escaping (especially nested code blocks)
    • Tilde characters being interpreted as strikethrough
    • Special characters in examples
    • Anchor links pointing to correct headings
  3. Known RDoc Markdown limitations:

    • Only triple backticks for fenced code blocks (no tildes, no quad-backticks)
    • Tilde fences (~~~) conflict with strikethrough syntax
    • Use 4-space indentation to show literal code fence examples
  4. Full verification: Generate documentation and inspect the HTML output:

    bundle exec rake rerdoc
    # Inspect the generated HTML file directly
    grep -A5 "your content" _site/path/to/file.html
    

Modifying Themes/Styling

When making changes to theme CSS or templates (e.g., Darkfish or Aliki themes):

  1. Start the live-reloading server: Run bundle exec rdoc --server (or bundle exec rake rdoc:server)
  2. Make changes: Edit files in lib/rdoc/generator/template// or source code
  3. Browser auto-refreshes: The server detects file changes and refreshes the browser automatically
  4. Verify with /test-server: Use the test-server skill for endpoint checks, live-reload verification, and optional Playwright screenshots
  5. Lint changes (if modified):
    • ERB templates: npx @herb-tools/linter "lib/rdoc/generator/template/**/*.rhtml"
    • CSS files: npm run lint:css -- --fix

Note: The server watches source files, not template files. If you modify .rhtml templates or CSS in the template directory, restart the server to pick up those changes.

Visual Testing with Playwright CLI

Use npx playwright to take screenshots of generated documentation — works with both the live-reload server and static _site/ output.

# Install browsers (one-time)
npx playwright install chromium

# Screenshot a live server page
npx playwright screenshot http://localhost:4000/RDoc.html /tmp/rdoc-class.png

# Screenshot static output (start a file server first)
cd _site && python3 -m http.server 8000 &
npx playwright screenshot http://localhost:8000/index.html /tmp/rdoc-index.png

# Full-page screenshot
npx playwright screenshot --full-page http://localhost:4000/RDoc.html /tmp/rdoc-full.png

For server-specific E2E testing (endpoint checks, live-reload verification, file change detection), use the /test-server skill.

Notes for AI Agents

  1. Always run tests after making changes: bundle exec rake
  2. Lint your changes:
    • RuboCop for Ruby: bundle exec rubocop -A
    • Herb for ERB templates: npx @herb-tools/linter "**/*.rhtml"
    • Stylelint for CSS: npm run lint:css -- --fix
  3. Regenerate parsers if you modify .ry or .kpeg files
  4. Use rake rerdoc to regenerate documentation (not just rdoc)
  5. Verify generated files with rake verify_generated
  6. Don't edit generated files directly (in lib/rdoc/markdown/ and lib/rdoc/rd/)
  7. Pull request descriptions must be concise. Use 2–4 short paragraphs explaining the context, why the change is correct, and any notable side effect. Do not include a "Test plan" section. Do not append a Claude Code session link or any AI attribution.
  8. Sync the fork before branching: when this repository is a fork of ruby/rdoc, fast-forward the fork's master to ruby/rdoc:master before creating a new branch. Branching from a stale master invites merge conflicts and PRs that diverge from upstream history.