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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5650fe4d2019c3e87194df2b3991e1353be042296fb48d4d6401832981aae200
4
- data.tar.gz: 0a2aa835270a49e4e053e7c6e43de03cab05c335ce1bf3f28633d7db82bf7ce1
3
+ metadata.gz: e430a8c15b61ce23a122b5b69b45bdee182c67067bd22e06379f369dbc888348
4
+ data.tar.gz: 6d15cc569f162076e03ed12464dd097845ce25af526a07c88c1c188ee26534d5
5
5
  SHA512:
6
- metadata.gz: d3370cd47fb6b9c436cf25f4b2da691c6da616bc225039393887be61133b8e20a7ca00b3bc107eba25fff09d906e8e164c0f859668fc29457141fada77960cf5
7
- data.tar.gz: 0aee08711b0940fe269167b1e583b4578884d25c72b596cd7810be10e1bdcf4daeede3bed516bf033fccb4e805c548d8227409a1a2daf20afbbe7ef2e88f9a34
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 a mountable engine at a path you choose (e.g. `/doc`).
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
- ### 1. Puma Plugin (Development Watch Mode)
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
- This watches `app/` and `lib/` for `.rb` file changes and automatically regenerates SDoc documentation.
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
- ### 2. Rake Task (Manual / Deploy)
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
- 1. **Development**: Puma boots → forks a child process that runs `SdocLive::Generator#build_watch`
81
- 2. The `listen` gem monitors `app/` and `lib/` for `.rb` file changes
82
- 3. On change, SDoc regenerates documentation into `tmp/doc/`
83
- 4. Docs are served via middleware at the configured `mount_path` (default: `/doc`)
84
- 5. Clean subprocess management with bidirectional lifecycle monitoring (Puma ↔ SDoc)
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
@@ -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
- def initialize(app, doc_root, mount_path)
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" => "public, max-age=3600" }
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
@@ -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
 
@@ -1,5 +1,5 @@
1
1
  module SdocLive
2
2
 
3
- VERSION = "0.1.13"
3
+ VERSION = "0.1.15"
4
4
 
5
5
  end
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sdoc_live
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.13
4
+ version: 0.1.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - 16554289+optimuspwnius@users.noreply.github.com