Skip to content

Commit 7b4efde

Browse files
committed
Replace WEBrick servlet with minimal TCPServer-based implementation
Drop the webrick dependency by rewriting RDoc::Server to use Ruby's built-in TCPServer. The new implementation handles HTTP directly with thread-per-connection, simplifies the start/shutdown lifecycle, and keeps all existing functionality (live reload, file watching, caching).
1 parent 9a87d29 commit 7b4efde

File tree

5 files changed

+209
-107
lines changed

5 files changed

+209
-107
lines changed

AGENTS.md

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ bundle exec rake rerdoc
125125
# Show documentation coverage
126126
bundle exec rake rdoc:coverage
127127
bundle exec rake coverage
128+
129+
# Start live-reloading preview server (port 4000)
130+
bundle exec rake rdoc:server
131+
132+
# Or via CLI with custom port
133+
bundle exec rdoc --server=8080
128134
```
129135

130136
**Output Directory:** `_site/` (GitHub Pages compatible)
@@ -176,6 +182,7 @@ lib/rdoc/
176182
│ ├── c.rb # C extension parser
177183
│ ├── prism_ruby.rb # Prism-based Ruby parser
178184
│ └── ...
185+
├── server.rb # Live-reloading preview server (rdoc --server)
179186
├── generator/ # Documentation generators
180187
│ ├── aliki.rb # HTML generator (default theme)
181188
│ ├── darkfish.rb # HTML generator (deprecated, will be removed in v8.0)
@@ -232,6 +239,30 @@ exe/
232239
- **Parsers:** Ruby, C, Markdown, RD, Prism-based Ruby (experimental)
233240
- **Generators:** HTML/Aliki (default), HTML/Darkfish (deprecated), RI, POT (gettext), JSON, Markup
234241

242+
### Live Preview Server (`RDoc::Server`)
243+
244+
The server (`lib/rdoc/server.rb`) provides `rdoc --server` for live documentation preview.
245+
246+
**Architecture:**
247+
- Uses Ruby's built-in `TCPServer` (`socket` stdlib) — no WEBrick or external dependencies
248+
- Creates a persistent `RDoc::Generator::Aliki` instance with `file_output = false` (renders to strings)
249+
- Thread-per-connection HTTP handling with `Connection: close` (no keep-alive)
250+
- Background watcher thread polls file mtimes every 1 second
251+
- Live reload via inline JS polling `/__status` endpoint
252+
253+
**Key files:**
254+
- `lib/rdoc/server.rb` — HTTP server, routing, caching, file watcher
255+
- `lib/rdoc/rdoc.rb``start_server` method, server branch in `document`
256+
- `lib/rdoc/options.rb``--server[=PORT]` option
257+
- `lib/rdoc/generator/darkfish.rb``refresh_store_data` (extracted for server reuse)
258+
- `lib/rdoc/store.rb``remove_file` (for deleted file handling)
259+
- `lib/rdoc/task.rb``rdoc:server` Rake task
260+
261+
**Known limitations:**
262+
- Reopened classes: deleting a file that partially defines a class removes the entire class from the store (save the other file to restore)
263+
- Template/CSS changes require server restart (only source files are watched)
264+
- Full page cache invalidation on any change (rendering is fast, so this is acceptable)
265+
235266
## Common Workflows
236267

237268
Do NOT commit anything. Ask the developer to review the changes after tasks are finished.
@@ -319,20 +350,17 @@ When editing markup reference documentation, such as `doc/markup_reference/markd
319350

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

322-
1. **Generate documentation**: Run `bundle exec rake rerdoc` to create baseline
323-
2. **Start HTTP server**: Run `cd _site && python3 -m http.server 8000` (use different port if 8000 is in use)
324-
3. **Investigate with Playwright**: Ask the AI assistant to take screenshots and inspect the documentation visually
325-
- Example: "Navigate to the docs at localhost:8000 and screenshot the RDoc module page"
353+
1. **Start the live-reloading server**: Run `bundle exec rdoc --server` (or `bundle exec rake rdoc:server`)
354+
2. **Make changes**: Edit files in `lib/rdoc/generator/template/<theme>/` or source code
355+
3. **Browser auto-refreshes**: The server detects file changes and refreshes the browser automatically
356+
4. **Investigate with Playwright**: Ask the AI assistant to take screenshots and inspect the documentation visually
357+
- Example: "Navigate to the docs at localhost:4000 and screenshot the RDoc module page"
326358
- See "Playwright MCP for Testing Generated Documentation" section below for details
327-
4. **Make changes**: Edit files in `lib/rdoc/generator/template/<theme>/` as needed
328-
5. **Regenerate**: Run `bundle exec rake rerdoc` to rebuild documentation with changes
329-
6. **Verify with Playwright**: Take new screenshots and compare to original issues
330-
7. **Lint changes** (if modified):
359+
5. **Lint changes** (if modified):
331360
- ERB templates: `npx @herb-tools/linter "lib/rdoc/generator/template/**/*.rhtml"`
332361
- CSS files: `npm run lint:css -- --fix`
333-
8. **Stop server**: Kill the HTTP server process when done
334362

335-
**Tip:** Keep HTTP server running during iteration. Just regenerate with `bundle exec rake rerdoc` between changes.
363+
**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.
336364

337365
## Notes for AI Agents
338366

@@ -386,23 +414,27 @@ Restart Claude Code after running these commands.
386414

387415
### Testing Generated Documentation
388416

389-
To test the generated documentation:
417+
The easiest way to test documentation is with the live-reloading server:
390418

391419
```bash
392-
# Generate documentation
393-
bundle exec rake rerdoc
420+
bundle exec rdoc --server
421+
# Or: bundle exec rake rdoc:server
422+
```
423+
424+
This starts a server at `http://localhost:4000` that auto-refreshes on file changes.
425+
426+
Alternatively, for testing static output:
394427

395-
# Start a simple HTTP server in the _site directory (use an available port)
428+
```bash
429+
bundle exec rake rerdoc
396430
cd _site && python3 -m http.server 8000
397431
```
398432

399-
If port 8000 is already in use, try another port (e.g., `python3 -m http.server 9000`).
400-
401433
Then ask the AI assistant to inspect the documentation. It will use the appropriate Playwright tools (`browser_navigate`, `browser_snapshot`, `browser_take_screenshot`, etc.) based on your request.
402434

403435
**Example requests:**
404436

405-
- "Navigate to `http://localhost:8000` and take a screenshot"
437+
- "Navigate to `http://localhost:4000` and take a screenshot"
406438
- "Take a screenshot of the RDoc module page"
407439
- "Check if code blocks are rendering properly on the Markup page"
408440
- "Compare the index page before and after my CSS changes"

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,41 @@ There are also a few community-maintained themes for RDoc:
180180
181181
Please follow the theme's README for usage instructions.
182182
183+
## Live Preview Server
184+
185+
RDoc includes a built-in server for previewing documentation while you edit source files. It parses your code once on startup, then watches for changes and auto-refreshes the browser.
186+
187+
```shell
188+
rdoc --server
189+
```
190+
191+
This starts a server at `http://localhost:4000`. You can specify a different port:
192+
193+
```shell
194+
rdoc --server=8080
195+
```
196+
197+
Or use the Rake task:
198+
199+
```shell
200+
rake rdoc:server
201+
```
202+
203+
### How It Works
204+
205+
- Parses all source files on startup and serves pages from memory using the Aliki theme
206+
- A background thread polls file mtimes every second
207+
- When a file changes, only that file is re-parsed — the browser refreshes automatically
208+
- New files are detected and added; deleted files are removed
209+
210+
**No external dependencies.** The server uses Ruby's built-in `TCPServer` (`socket` stdlib) — no WEBrick or other gems required.
211+
212+
### Limitations
213+
214+
- **Reopened classes and file deletion.** If a class is defined across multiple files (e.g. `Foo` in both `a.rb` and `b.rb`), deleting one file removes the entire class from the store, including parts from the other file. Saving the remaining file triggers a re-parse that restores it.
215+
- **Full cache invalidation.** Any file change clears all cached pages. This is simple and correct — rendering is fast (~ms per page), parsing is the expensive part and is done incrementally.
216+
- **No HTTPS or HTTP/2.** The server is intended for local development preview only.
217+
183218
## Bugs
184219

185220
See [CONTRIBUTING.md](CONTRIBUTING.md) for information on filing a bug report. It's OK to file a bug report for anything you're having a problem with. If you can't figure out how to make RDoc produce the output you like that is probably a documentation bug.

lib/rdoc/rdoc.rb

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -534,19 +534,7 @@ def generate
534534
# Called from #document when <tt>--server</tt> is given.
535535

536536
def start_server
537-
require 'webrick'
538-
539-
port = @options.server_port
540-
server = WEBrick::HTTPServer.new(
541-
Port: port,
542-
Logger: WEBrick::Log.new($stderr, WEBrick::Log::INFO),
543-
AccessLog: []
544-
)
545-
server.mount '/', RDoc::Server, self
546-
547-
url = "http://localhost:#{port}"
548-
$stderr.puts "\nServing documentation at: \e]8;;#{url}\e\\#{url}\e]8;;\e\\"
549-
$stderr.puts "Press Ctrl+C to stop."
537+
server = RDoc::Server.new(self, @options.server_port)
550538

551539
trap('INT') { server.shutdown }
552540
trap('TERM') { server.shutdown }

0 commit comments

Comments
 (0)