# gleedoc
[](https://hex.pm/packages/gleedoc)
[](https://hexdocs.pm/gleedoc/)
A **doc test** library for Gleam, inspired by Rust and Elixir's doctest tooling.
Doc tests let you write executable examples in your documentation comments (`///`).
These examples are extracted, compiled, and run as part of your test suite, ensuring your documentation never goes out of date.
> Disclaimer: This project contains many LLM-generated code, and I used LLMs to do research and design. But I (as a Gleam amateur) have tried my best to review line by line, adjust and refactor.
## How it works
1. **Extract** `///` doc comments from your `.gleam` source files.
2. **Find** fenced code blocks tagged with `gleam` inside those comments.
3. **Generate** test modules in your `test/` directory.
4. **Run** the generated tests with `gleam test`.
### How other languages do it
| Language | Approach | Key Difference from Gleam |
| ---------- | ----------------------------------------------------------------------------- | ----------------------------------------- |
| **Rust** | `cargo test` compiles ` ```rust ` blocks from `///` comments. No REPL needed. | Gleam follows this model closely. |
| **Elixir** | `doctest Module` parses `iex>` prompts from `@doc` strings. | Elixir has a REPL; Gleam does not. |
| **Python** | `doctest` parses `>>>` prompts from docstrings. | Python is interpreted; Gleam is compiled. |
Because Gleam is a compiled language with no built-in REPL, **gleedoc** adopts Rust's approach: doc blocks are treated as standalone Gleam code that gets compiled and executed. If a block panics, the test fails.
## Installation
```sh
gleam add gleedoc --dev
```
## Usage
Write doc comments with `gleam` code blocks in your source files:
````gleam
// src/math.gleam
/// Adds two numbers together.
///
/// ```gleam
/// let result = add(1, 2)
/// assert result == 3
/// ```
pub fn add(a: Int, b: Int) -> Int {
a + b
}
````
Then run gleedoc to generate tests:
```sh
gleam run -m gleedoc
```
This creates `test/gleedoc/math_gleedoc_test.gleam` containing:
```gleam
// Generated by gleedoc - do not edit manually
import math.{add}
// From: src/math.gleam:4
pub fn add_1_test() {
let result = add(1, 2)
assert result == 3
}
```
Now run your tests as usual:
```sh
gleam test
```
## API
You can also use gleedoc programmatically from your test suite:
```gleam
// test/gleedoc_setup.gleam
import gleedoc
pub fn main() {
let config = gleedoc.GleedocConfig(
output_dir: "test",
source_dir: "src",
)
case gleedoc.run(config) {
Ok(Nil) -> Nil
Error(snag) -> panic as snag.issue
}
}
```
## Architecture
```
src/
gleedoc.gleam # Main entry point and CLI
gleedoc/
extract.gleam # Line-based doc comment extraction
parse.gleam # Markdown code block parsing
generate.gleam # Test file generation
scan.gleam # Public names and imports extraction with glance
```
### Key dependencies
| Package | Role |
| ------------ | -------------------------- |
| `glance` | Gleam source parser |
| `simplifile` | Cross-target file I/O |
| `snag` | Lightweight error handling |
## Development
```sh
rm -rf test/integration/ && gleam test # Run the test suite
```
### Contributing
Please kindly create an issue in your human voice, describe the feature request or bug clearly with reproduction steps, and ideally with a proposed solution **before** creating any PR.
## Roadmap
### Implemented
- [x] Extract `///` doc comments from source files
- [x] Parse ` ```gleam ` fenced code blocks
- [x] Generate compatible `gleeunit` test files
- [x] Multi-file source discovery
- [x] Use `glance` to extract public names for unqualified imports
- [x] Cross-module imports: `import` statements in code blocks are merged into generated tests
- [x] Single-command `gleam run -m gleedoc` CLI experience
### Missing Features (compared to Rust, Elixir, and Python)
| Feature | Rust | Elixir | Python | **gleedoc** |
| -------------------------------------- | ---------- | ----------- | ---------- | ----------- |
| `ignore` / skip attribute | ✅ | ✅ | ✅ | ❌ |
| `no_run` (compile only) | ✅ | ❌ | ❌ | ❌ |
| `should_panic` | ✅ | ❌ | ❌ | ❌ |
| Hidden setup lines (`#`) | ✅ | ❌ | ❌ | ❌ |
| Output assertions (`// ->`) | ❌ | ✅ (`iex>`) | ✅ (`>>>`) | ❌ |
| Module-level doc tests | ✅ (`//!`) | ✅ | ✅ | ❌ |
| `compile_fail` | ✅ | ❌ | ❌ | ❌ |
| Multi-target (`erlang` / `javascript`) | ✅ (`cfg`) | ❌ | ❌ | ❌ |
| Incremental / cached generation | ✅ | ✅ | ✅ | ❌ |
| Source-mapped error reporting | ✅ | ✅ | ✅ | ❌ |
### Know Issues
- [ ] Generated tests will contain unused imports