---
title: RDoc
url: 'https://wiki.teletypegames.org/development/rdoc'
markdown: 'https://wiki.teletypegames.org/development/rdoc.md'
lang: en
date: '2026-10-28'
description: 'Our Ruby gems document every class and method in the source, and each release tag publishes the RDoc built from it under /rdoc/. The table below always shows the newest published version. Go modules do the same with Go doc. Published gems /rdoc/index.json Gem Engine page Release tag bbs Ru…'
taxonomy:
  tag:
    - howto
---

# RDoc

> Our Ruby gems document every class and method in the source, and each release tag publishes the RDoc built from it under [/rdoc/](https://wiki.teletypegames.org/rdoc/index.json). The table below always shows the newest published version. Go modules do the same with [Go doc](https://wiki.teletypegames.org/development/godoc).

# Published gems

[/rdoc/index.json](https://wiki.teletypegames.org/rdoc/index.json)

| Gem | Engine page | Release tag |
|---|---|---|
| `bbs` | [RuBBS](https://wiki.teletypegames.org/engines/rubbs) | `vX.Y.Z` in engines/rubbs |
| `warp_engine` | [WarpEngine](https://wiki.teletypegames.org/engines/warp-engine) | `warp_engine-vX.Y.Z` in services/teletypegames |

Each gem keeps its ten newest versions; `/rdoc/bbs/latest/` and `/rdoc/warp_engine/latest/` always point at the newest one, and the version picker at the top of every page switches between them.

# The rule: 100% documented

Both repos say it in their `CLAUDE.md`, and CI enforces it: a push fails when `rdoc -C` reports anything below 100%. Every class, module, constant, attribute and public or protected method gets an RDoc comment directly above it that says what it does, what it takes, what it returns, what it raises and what it changes. The why of a change goes into the commit, not the comment.

- RDoc markup, not Markdown or YARD: `+word+`, tt tags for several words, `*bold*`, `_emphasis_`, labelled lists for arguments, examples in an indented block.
- No `:nodoc:` to reach the number; a helper that is not part of the API becomes `private` instead.
- In the teletypegames monorepo the no-comments rule still holds inside method bodies; the RDoc comment above a definition is the one exception, and only under `libs/ruby/warp_engine`.

# How it gets here

1. A release tag runs the gem's pipeline: tests, the coverage gate, then `rdoc` builds the HTML and a `meta.json` (version, commit, date, coverage).
2. The pipeline uploads `rdoc.tar.gz` as the Gitea generic package named after the gem with an `-rdoc` suffix, in the engines org.
3. Gitea's package webhook calls the wiki-fetcher (`/rdoc-hook`), which also checks every ten minutes. It unpacks the new version, links in the wiki look, moves `latest` and rewrites `/rdoc/index.json`.
4. The table above reads that index in the browser, and the engine pages link the `latest` reference, so no wiki page has to be edited for a release.

The wiki-fetcher's `/health` turns red when an RDoc round fails. Details: `fetcher/README.md` in services/wiki-pages.

# Writing docs locally

```bash
rdoc -C lib                                   # rubbs: coverage, lists what is missing
rdoc -C -x templates app lib                  # warp_engine
rdoc -o /tmp/doc --main README.md lib README.md && open /tmp/doc/index.html
```

Use the same RDoc version as CI (8.1.0, `gem install rdoc -v 8.1.0`): older versions count attributes and namespaces differently.

'; var prevLevel = 2; for (var i = 0; i < headings.length; i++) { var h = headings\[i\]; var text = h.textContent.trim(); var slug = text.toLowerCase() .replace(/\[áàâä\]/g,'a').replace(/\[éèêë\]/g,'e').replace(/\[íìîï\]/g,'i') .replace(/\[óòôöő\]/g,'o').replace(/\[úùûüű\]/g,'u') .replace(/\[^a-z0-9\]+/g, '-').replace(/^-|-$/g, ''); if (!slug) slug = 'heading-' + i; if (used\[slug\]) { slug += '-' + i; } used\[slug\] = true; h.id = slug; var level = parseInt(h.tagName.charAt(1)); var cls = level > 2 ? ' class="toc-child"' : ''; html += '- [' + text + '](#'%20+%20slug%20+%20')
'; } html += '
'; toc.innerHTML = html; // Scroll-spy: highlight current heading var links = toc.querySelectorAll('a'); var ids = \[\]; for (var j = 0; j < links.length; j++) ids.push(links\[j\].getAttribute('href').slice(1)); function updateActive() { var current = ''; for (var k = 0; k < ids.length; k++) { var el = document.getElementById(ids\[k\]); if (el && el.getBoundingClientRect().top <= 80) current = ids\[k\]; } for (var m = 0; m < links.length; m++) { links\[m\].parentNode.classList.toggle('active', links\[m\].getAttribute('href') === '#' + current); } } window.addEventListener('scroll', updateActive, { passive: true }); updateActive(); })();

---

## Navigation

- Parent: [Development](https://wiki.teletypegames.org/development.md)
- Previous: [Pixelorama](https://wiki.teletypegames.org/development/pixelorama.md)
- Next: [RoR Styleguide](https://wiki.teletypegames.org/development/ror-styleguide.md)
