sdoc_live 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +78 -10
- data/lib/puma/plugin/sdoc_live.rb +19 -0
- data/lib/sdoc_live/engine.rb +30 -4
- data/lib/sdoc_live/generator.rb +16 -0
- data/lib/sdoc_live/version.rb +1 -1
- data/lib/sdoc_live.rb +33 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e430a8c15b61ce23a122b5b69b45bdee182c67067bd22e06379f369dbc888348
|
|
4
|
+
data.tar.gz: 6d15cc569f162076e03ed12464dd097845ce25af526a07c88c1c188ee26534d5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a0172e9fcd45479f579491b084d07ff0bc7804bb1c4c539effea3d6d97417d0fec325dc6390e07a64841b327fe38389aa5cff012176fdf9cb5497e7dea550445
|
|
7
|
+
data.tar.gz: 12ba4c7955a9b5da5bb329cb444557f1e4aec6eead864c76f193540d788ea50a9b6658e2fe44764aa722880e6427d10c78c984c6b02848ac20856dac5c0666c9
|
data/README.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# SDoc Live
|
|
2
2
|
|
|
3
|
-
Live SDoc generation for Rails — watches your source files and auto-regenerates API documentation on changes. Serves docs via
|
|
3
|
+
Live SDoc generation for Rails — watches your source files and auto-regenerates API documentation on changes. Serves docs via Rack middleware at a configurable path (default: `/doc`).
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
|
+
- Ruby >= 3.2
|
|
8
|
+
- Rails >= 7.0
|
|
7
9
|
- **SDoc** gem (included as a dependency)
|
|
8
10
|
|
|
9
11
|
## Installation
|
|
@@ -24,9 +26,26 @@ Then run `bundle install`.
|
|
|
24
26
|
> end
|
|
25
27
|
> ```
|
|
26
28
|
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
1. Add the gem to your Gemfile and run `bundle install`
|
|
32
|
+
2. Add the Puma plugin to `config/puma.rb`:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
if ENV.fetch("RAILS_ENV", "development") == "development"
|
|
36
|
+
plugin :sdoc_live
|
|
37
|
+
end
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
3. Start your Rails server and visit `/doc`
|
|
41
|
+
|
|
42
|
+
That's it — documentation is generated automatically and rebuilds when you change any `.rb` file in `app/` or `lib/`.
|
|
43
|
+
|
|
27
44
|
## Usage
|
|
28
45
|
|
|
29
|
-
###
|
|
46
|
+
### Puma Plugin (Development Watch Mode)
|
|
47
|
+
|
|
48
|
+
The Puma plugin is the primary way to use SDoc Live in development. It forks a child process that generates documentation on boot and watches for file changes.
|
|
30
49
|
|
|
31
50
|
Add to your `config/puma.rb`:
|
|
32
51
|
|
|
@@ -36,18 +55,37 @@ if ENV.fetch("RAILS_ENV", "development") == "development"
|
|
|
36
55
|
end
|
|
37
56
|
```
|
|
38
57
|
|
|
39
|
-
|
|
58
|
+
The plugin provides:
|
|
59
|
+
|
|
60
|
+
- **Automatic generation** on Puma boot
|
|
61
|
+
- **File watching** via the `listen` gem — regenerates docs when `.rb` files change
|
|
62
|
+
- **Lifecycle management** — the SDoc process stops when Puma stops, and vice versa
|
|
63
|
+
|
|
64
|
+
### Rake Task (Manual / CI / Deploy)
|
|
40
65
|
|
|
41
|
-
|
|
66
|
+
For one-off generation without file watching:
|
|
42
67
|
|
|
43
68
|
```bash
|
|
44
69
|
rake sdoc:build
|
|
45
70
|
```
|
|
46
71
|
|
|
72
|
+
This is useful for CI pipelines or production deployments where you want to pre-generate documentation.
|
|
73
|
+
|
|
74
|
+
## Serving Documentation
|
|
75
|
+
|
|
76
|
+
SDoc Live automatically inserts Rack middleware that serves generated documentation at the configured `mount_path` (default: `/doc`). No route mounting is needed — it works out of the box.
|
|
77
|
+
|
|
78
|
+
- `GET /doc` redirects to `/doc/`
|
|
79
|
+
- `GET /doc/` serves the documentation index
|
|
80
|
+
- `GET /doc/...` serves any generated documentation file
|
|
81
|
+
|
|
82
|
+
The middleware is inserted before `Rails::Rack::Logger`, so documentation requests don't appear in your Rails logs.
|
|
83
|
+
|
|
47
84
|
## Configuration
|
|
48
85
|
|
|
86
|
+
Create an initializer at `config/initializers/sdoc_live.rb`:
|
|
87
|
+
|
|
49
88
|
```ruby
|
|
50
|
-
# config/initializers/sdoc_live.rb
|
|
51
89
|
SdocLive.configure do |config|
|
|
52
90
|
# Title for the generated documentation (default: "Documentation")
|
|
53
91
|
config.title = "My App API"
|
|
@@ -72,16 +110,46 @@ SdocLive.configure do |config|
|
|
|
72
110
|
|
|
73
111
|
# URL path where documentation is served (default: "/doc")
|
|
74
112
|
# config.mount_path = "/doc"
|
|
113
|
+
|
|
114
|
+
# Cache-Control header for served documentation files (default: "no-cache")
|
|
115
|
+
# Use "no-cache" in development to always get fresh docs.
|
|
116
|
+
# Use "public, max-age=3600" in production for better performance.
|
|
117
|
+
# config.cache_control = "public, max-age=3600"
|
|
75
118
|
end if defined?(SdocLive)
|
|
76
119
|
```
|
|
77
120
|
|
|
121
|
+
### Configuration Options
|
|
122
|
+
|
|
123
|
+
| Option | Default | Description |
|
|
124
|
+
|--------|---------|-------------|
|
|
125
|
+
| `title` | `"Documentation"` | HTML title for the generated docs |
|
|
126
|
+
| `main_file` | `"README.md"` | File displayed on the docs landing page |
|
|
127
|
+
| `source_dirs` | `["app", "lib"]` | Directories scanned by RDoc for source files |
|
|
128
|
+
| `watch_dirs` | `nil` (falls back to `source_dirs`) | Directories watched for file changes in dev mode |
|
|
129
|
+
| `watch_file_type_regex` | `/\.rb$/` | File pattern that triggers regeneration |
|
|
130
|
+
| `output_dir` | `nil` (defaults to `tmp/doc`) | Where generated HTML documentation is written |
|
|
131
|
+
| `rdoc_options` | `nil` | Additional CLI options passed to RDoc/SDoc |
|
|
132
|
+
| `mount_path` | `"/doc"` | URL path where documentation is served |
|
|
133
|
+
| `cache_control` | `"no-cache"` | `Cache-Control` header for served files |
|
|
134
|
+
|
|
78
135
|
## How It Works
|
|
79
136
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
137
|
+
```
|
|
138
|
+
Rails app boots
|
|
139
|
+
├── Engine initializer inserts StaticFiles middleware
|
|
140
|
+
│ └── Serves tmp/doc/ at /doc (before Rails logger)
|
|
141
|
+
└── Puma plugin forks child process
|
|
142
|
+
├── Generator#build runs full SDoc generation → tmp/doc/
|
|
143
|
+
├── Listen gem watches app/ + lib/ for .rb changes
|
|
144
|
+
└── On change → Generator#build again (full regeneration)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
1. **Boot**: When Rails starts, the `SdocLive::Engine` initializer inserts `SdocLive::StaticFiles` Rack middleware that serves files from the output directory
|
|
148
|
+
2. **Generate**: The Puma plugin forks a child process that runs a full SDoc build
|
|
149
|
+
3. **Watch**: The child process uses the `listen` gem to monitor source directories for file changes
|
|
150
|
+
4. **Rebuild**: When a matching file changes, the generator runs a complete SDoc rebuild with `--force-output`
|
|
151
|
+
5. **Serve**: The middleware serves documentation files using `ActionDispatch::FileHandler`, handling path prefixing and trailing slash redirects
|
|
152
|
+
6. **Lifecycle**: Bidirectional process monitoring ensures the SDoc child process and Puma stay in sync — if either dies, the other is stopped
|
|
85
153
|
|
|
86
154
|
## License
|
|
87
155
|
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
require "puma/plugin"
|
|
2
2
|
|
|
3
|
+
# Puma plugin that runs SDoc Live in a forked child process during development.
|
|
4
|
+
#
|
|
5
|
+
# Activated by adding <tt>plugin :sdoc_live</tt> to +config/puma.rb+.
|
|
6
|
+
#
|
|
7
|
+
# After Puma boots, it forks a child that calls
|
|
8
|
+
# +SdocLive::Generator#build_watch+ (initial build + file watching).
|
|
9
|
+
# Bidirectional lifecycle monitoring ensures both processes stay in sync:
|
|
10
|
+
#
|
|
11
|
+
# - If Puma dies, the SDoc child exits.
|
|
12
|
+
# - If the SDoc child dies, Puma is stopped.
|
|
3
13
|
Puma::Plugin.create do
|
|
4
14
|
|
|
5
15
|
attr_reader :puma_pid, :sdoc_pid, :log_writer
|
|
6
16
|
|
|
17
|
+
# Called by Puma during plugin registration. Sets up the forked SDoc
|
|
18
|
+
# process after boot and registers a shutdown hook.
|
|
7
19
|
def start(launcher)
|
|
8
20
|
@log_writer = launcher.log_writer
|
|
9
21
|
@puma_pid = $PROCESS_ID
|
|
@@ -42,6 +54,7 @@ Puma::Plugin.create do
|
|
|
42
54
|
|
|
43
55
|
private
|
|
44
56
|
|
|
57
|
+
# Sends INT to the SDoc child process and waits for it to exit.
|
|
45
58
|
def stop_sdoc
|
|
46
59
|
Process.waitpid(sdoc_pid, Process::WNOHANG)
|
|
47
60
|
log "Stopping SdocLive..."
|
|
@@ -50,14 +63,18 @@ Puma::Plugin.create do
|
|
|
50
63
|
rescue Errno::ECHILD, Errno::ESRCH
|
|
51
64
|
end
|
|
52
65
|
|
|
66
|
+
# Monitors the Puma parent process from the SDoc child.
|
|
53
67
|
def monitor_puma
|
|
54
68
|
monitor(:puma_dead?, "Detected Puma has gone away, stopping SdocLive...")
|
|
55
69
|
end
|
|
56
70
|
|
|
71
|
+
# Monitors the SDoc child process from the Puma parent.
|
|
57
72
|
def monitor_sdoc
|
|
58
73
|
monitor(:sdoc_dead?, "Detected SdocLive has gone away, stopping Puma...")
|
|
59
74
|
end
|
|
60
75
|
|
|
76
|
+
# Polls +process_dead+ every 2 seconds. When the monitored process is
|
|
77
|
+
# detected as dead, logs the message and sends INT to the current process.
|
|
61
78
|
def monitor(process_dead, message)
|
|
62
79
|
loop do
|
|
63
80
|
|
|
@@ -71,6 +88,7 @@ Puma::Plugin.create do
|
|
|
71
88
|
end
|
|
72
89
|
end
|
|
73
90
|
|
|
91
|
+
# Returns +true+ if the SDoc child process has exited.
|
|
74
92
|
def sdoc_dead?
|
|
75
93
|
Process.waitpid(sdoc_pid, Process::WNOHANG)
|
|
76
94
|
false
|
|
@@ -78,6 +96,7 @@ Puma::Plugin.create do
|
|
|
78
96
|
true
|
|
79
97
|
end
|
|
80
98
|
|
|
99
|
+
# Returns +true+ if the Puma parent process has been replaced (i.e. died).
|
|
81
100
|
def puma_dead?
|
|
82
101
|
Process.ppid != puma_pid
|
|
83
102
|
end
|
data/lib/sdoc_live/engine.rb
CHANGED
|
@@ -1,37 +1,63 @@
|
|
|
1
1
|
module SdocLive
|
|
2
2
|
|
|
3
|
+
# Rails engine that registers the SdocLive::StaticFiles middleware and
|
|
4
|
+
# loads the +sdoc:build+ rake task. No route mounting is required — the
|
|
5
|
+
# middleware is inserted automatically before +Rails::Rack::Logger+ so
|
|
6
|
+
# documentation requests don't appear in application logs.
|
|
3
7
|
class Engine < ::Rails::Engine
|
|
4
8
|
|
|
5
9
|
rake_tasks do
|
|
6
10
|
load File.expand_path("../tasks/sdoc_live.rake", __dir__)
|
|
7
11
|
end
|
|
8
12
|
|
|
13
|
+
# Inserts the StaticFiles middleware using the current SdocLive configuration.
|
|
9
14
|
initializer "sdoc_live.static" do
|
|
10
15
|
config = SdocLive.configuration
|
|
11
16
|
doc_root = (config.output_dir || Rails.root.join("tmp", "doc")).to_s
|
|
12
17
|
mount_path = config.mount_path
|
|
18
|
+
cache_control = config.cache_control
|
|
13
19
|
|
|
14
20
|
Rails.application.middleware.insert_before(
|
|
15
21
|
Rails::Rack::Logger,
|
|
16
22
|
SdocLive::StaticFiles,
|
|
17
23
|
doc_root,
|
|
18
|
-
mount_path
|
|
24
|
+
mount_path,
|
|
25
|
+
cache_control
|
|
19
26
|
)
|
|
20
27
|
end
|
|
21
28
|
|
|
22
29
|
end
|
|
23
30
|
|
|
31
|
+
# Rack middleware that serves generated SDoc files from +doc_root+ at the
|
|
32
|
+
# configured +mount_path+. Uses +ActionDispatch::FileHandler+ for efficient
|
|
33
|
+
# file serving with configurable +Cache-Control+ headers.
|
|
34
|
+
#
|
|
35
|
+
# == Behavior
|
|
36
|
+
#
|
|
37
|
+
# - +GET /doc+ → 301 redirect to +/doc/+
|
|
38
|
+
# - +GET /doc/...+ → serves matching file from +doc_root+, or falls through
|
|
39
|
+
# to the Rails app if no file matches
|
|
24
40
|
class StaticFiles
|
|
25
41
|
|
|
26
|
-
|
|
42
|
+
# Initializes the middleware.
|
|
43
|
+
#
|
|
44
|
+
# [app] The next Rack app in the middleware stack.
|
|
45
|
+
# [doc_root] Absolute path to the directory containing generated docs.
|
|
46
|
+
# [mount_path] URL prefix where docs are served (e.g. +"/doc"+).
|
|
47
|
+
# [cache_control] Value for the +Cache-Control+ response header.
|
|
48
|
+
# Default: +"no-cache"+.
|
|
49
|
+
def initialize(app, doc_root, mount_path, cache_control = "no-cache")
|
|
27
50
|
@app = app
|
|
28
51
|
@mount_path = mount_path.chomp("/")
|
|
29
52
|
@file_handler = ActionDispatch::FileHandler.new(
|
|
30
53
|
doc_root,
|
|
31
|
-
headers: { "cache-control" =>
|
|
54
|
+
headers: { "cache-control" => cache_control }
|
|
32
55
|
)
|
|
33
56
|
end
|
|
34
57
|
|
|
58
|
+
# Handles an incoming Rack request. Redirects bare mount path to trailing
|
|
59
|
+
# slash, attempts to serve a file for paths under the mount path, and
|
|
60
|
+
# falls through to the next middleware otherwise.
|
|
35
61
|
def call(env)
|
|
36
62
|
path_info = env["PATH_INFO"]
|
|
37
63
|
|
|
@@ -52,4 +78,4 @@ module SdocLive
|
|
|
52
78
|
|
|
53
79
|
end
|
|
54
80
|
|
|
55
|
-
end
|
|
81
|
+
end
|
data/lib/sdoc_live/generator.rb
CHANGED
|
@@ -2,8 +2,16 @@ require "fileutils"
|
|
|
2
2
|
|
|
3
3
|
module SdocLive
|
|
4
4
|
|
|
5
|
+
# Generates SDoc documentation from Ruby source files. Wraps +RDoc::RDoc+
|
|
6
|
+
# with SDoc formatting and supports both one-shot builds and continuous
|
|
7
|
+
# watch-mode regeneration.
|
|
5
8
|
class Generator
|
|
6
9
|
|
|
10
|
+
# Creates a new generator.
|
|
11
|
+
#
|
|
12
|
+
# [root] Project root directory. Defaults to +Rails.root+ when available,
|
|
13
|
+
# otherwise +Dir.pwd+. All configured paths are resolved relative
|
|
14
|
+
# to this root.
|
|
7
15
|
def initialize(root: nil)
|
|
8
16
|
@root = root || defined?(Rails) && Rails.root || Pathname.new(Dir.pwd)
|
|
9
17
|
@root = Pathname.new(@root) unless @root.is_a?(Pathname)
|
|
@@ -25,6 +33,9 @@ module SdocLive
|
|
|
25
33
|
@rdoc_options = config.rdoc_options
|
|
26
34
|
end
|
|
27
35
|
|
|
36
|
+
# Runs a full SDoc generation pass into the configured output directory.
|
|
37
|
+
# Uses <tt>--force-output</tt> to overwrite any existing docs. Prints
|
|
38
|
+
# elapsed time on completion.
|
|
28
39
|
def build
|
|
29
40
|
start_time = Time.now
|
|
30
41
|
|
|
@@ -57,6 +68,11 @@ module SdocLive
|
|
|
57
68
|
puts "[SdocLive] Generated in #{ format('%.2f', elapsed) }s → #{ @output_dir }"
|
|
58
69
|
end
|
|
59
70
|
|
|
71
|
+
# Builds documentation once, then watches +watch_dirs+ for file changes
|
|
72
|
+
# matching +watch_file_type_regex+ and rebuilds on each change. Blocks
|
|
73
|
+
# the current thread until interrupted.
|
|
74
|
+
#
|
|
75
|
+
# This is the method called by the Puma plugin in a forked child process.
|
|
60
76
|
def build_watch
|
|
61
77
|
require "listen"
|
|
62
78
|
|
data/lib/sdoc_live/version.rb
CHANGED
data/lib/sdoc_live.rb
CHANGED
|
@@ -1,25 +1,56 @@
|
|
|
1
1
|
require_relative "sdoc_live/version"
|
|
2
2
|
|
|
3
|
+
# Live SDoc generation for Rails. Watches source files and auto-regenerates
|
|
4
|
+
# API documentation on changes, serving it via Rack middleware.
|
|
5
|
+
#
|
|
6
|
+
# == Quick Start
|
|
7
|
+
#
|
|
8
|
+
# # config/initializers/sdoc_live.rb
|
|
9
|
+
# SdocLive.configure do |config|
|
|
10
|
+
# config.title = "My App API"
|
|
11
|
+
# end if defined?(SdocLive)
|
|
12
|
+
#
|
|
13
|
+
# See Configuration for all available options.
|
|
3
14
|
module SdocLive
|
|
4
15
|
|
|
5
16
|
class << self
|
|
6
17
|
|
|
7
18
|
attr_writer :configuration
|
|
8
19
|
|
|
20
|
+
# Returns the current configuration, initializing with defaults if needed.
|
|
9
21
|
def configuration
|
|
10
22
|
@configuration ||= Configuration.new
|
|
11
23
|
end
|
|
12
24
|
|
|
25
|
+
# Yields the current Configuration for modification.
|
|
26
|
+
#
|
|
27
|
+
# SdocLive.configure do |config|
|
|
28
|
+
# config.title = "My Docs"
|
|
29
|
+
# config.source_dirs = ["app", "lib", "engines"]
|
|
30
|
+
# end
|
|
13
31
|
def configure
|
|
14
32
|
yield(configuration)
|
|
15
33
|
end
|
|
16
34
|
|
|
17
35
|
end
|
|
18
36
|
|
|
37
|
+
# Holds all configuration options for SDoc Live.
|
|
38
|
+
#
|
|
39
|
+
# == Attributes
|
|
40
|
+
#
|
|
41
|
+
# [output_dir] Where generated HTML is written. Default: +Rails.root.join("tmp", "doc")+.
|
|
42
|
+
# [title] HTML title for generated docs. Default: +"Documentation"+.
|
|
43
|
+
# [main_file] Landing page source file. Default: +"README.md"+.
|
|
44
|
+
# [source_dirs] Directories scanned by RDoc. Default: <tt>["app", "lib"]</tt>.
|
|
45
|
+
# [watch_dirs] Directories watched for changes (falls back to +source_dirs+). Default: +nil+.
|
|
46
|
+
# [watch_file_type_regex] File pattern that triggers regeneration. Default: +/\.rb$/+.
|
|
47
|
+
# [rdoc_options] Additional CLI options passed to RDoc/SDoc. Default: +nil+.
|
|
48
|
+
# [mount_path] URL path where docs are served. Default: +"/doc"+.
|
|
49
|
+
# [cache_control] Cache-Control header value for served files. Default: +"no-cache"+.
|
|
19
50
|
class Configuration
|
|
20
51
|
|
|
21
52
|
attr_accessor :output_dir, :title, :main_file, :source_dirs, :watch_dirs,
|
|
22
|
-
:watch_file_type_regex, :rdoc_options, :mount_path
|
|
53
|
+
:watch_file_type_regex, :rdoc_options, :mount_path, :cache_control
|
|
23
54
|
|
|
24
55
|
def initialize
|
|
25
56
|
@source_dirs = ["app", "lib"]
|
|
@@ -27,6 +58,7 @@ module SdocLive
|
|
|
27
58
|
@title = "Documentation"
|
|
28
59
|
@main_file = "README.md"
|
|
29
60
|
@mount_path = "/doc"
|
|
61
|
+
@cache_control = "no-cache"
|
|
30
62
|
end
|
|
31
63
|
|
|
32
64
|
end
|