sdoc_live 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 55e49cf8d368ca829d746abd1038fbfbc6e93cae8fa12a96e0a9c0afa072ea8b
4
+ data.tar.gz: 947f0bd79a515516e1288375812314c1bb15529ef25c68ccafca93cdcc379cd9
5
+ SHA512:
6
+ metadata.gz: 8a5724323180f8c3b0c3182609ecbfd43502bfb4ec40d5a65f92c8d28df0a8bc34d1e956ead8a048fe1add718685f1aaf895b6857a801a48fbf13962fec148dd
7
+ data.tar.gz: ff75942af57a3d5c5a8a057be1df2fd99aa796614bea43d965ed4c2bf794fb740819bca5918348dda7cc54cfd7954d7a5f5de7d983ae5bbbd9682e177022da91
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # SDoc Live
2
+
3
+ Live SDoc generation for Rails — watches your source files and auto-regenerates API documentation on changes. Serves docs from `public/doc/` so they're available at `/doc/index.html` in development.
4
+
5
+ ## Requirements
6
+
7
+ - **SDoc** gem (included as a dependency)
8
+
9
+ ## Installation
10
+
11
+ Add to your Gemfile:
12
+
13
+ ```ruby
14
+ gem "sdoc_live"
15
+ ```
16
+
17
+ Then run `bundle install`.
18
+
19
+ ## Usage
20
+
21
+ ### 1. Puma Plugin (Development Watch Mode)
22
+
23
+ Add to your `config/puma.rb`:
24
+
25
+ ```ruby
26
+ if ENV.fetch("RAILS_ENV", "development") == "development"
27
+ plugin :sdoc
28
+ end
29
+ ```
30
+
31
+ This watches `app/` and `lib/` for `.rb` file changes and automatically regenerates SDoc documentation.
32
+
33
+ Docs are served at `/doc/index.html` via Rails' `public/` directory.
34
+
35
+ ### 2. Rake Task (Manual / Deploy)
36
+
37
+ ```bash
38
+ rake sdoc:build
39
+ ```
40
+
41
+ ## Configuration
42
+
43
+ ```ruby
44
+ # config/initializers/sdoc_live.rb
45
+ SdocLive.configure do |config|
46
+ # Title for the generated documentation (default: "Documentation")
47
+ config.title = "My App API"
48
+
49
+ # Main file displayed on the docs landing page (default: "README.md")
50
+ config.main_file = "README.md"
51
+
52
+ # Directories to scan for Ruby source files (default: ["app", "lib"])
53
+ config.source_dirs = ["app", "lib"]
54
+
55
+ # Directories to watch for changes in dev mode (defaults to source_dirs)
56
+ # config.watch_dirs = ["app", "lib"]
57
+
58
+ # Regex for file types that trigger regeneration (default: /\.rb$/)
59
+ # config.watch_file_type_regex = /\.(rb|md)$/
60
+
61
+ # Override the output directory (default: Rails.root.join("public", "doc"))
62
+ # config.output_dir = Rails.root.join("public", "doc")
63
+
64
+ # Additional RDoc options passed to the SDoc generator
65
+ # config.rdoc_options = ["--all", "--hyperlink-all"]
66
+ end
67
+ ```
68
+
69
+ ## How It Works
70
+
71
+ 1. **Development**: Puma boots → forks a child process that runs `SdocLive::Generator#build_watch`
72
+ 2. The `listen` gem monitors `app/` and `lib/` for `.rb` file changes
73
+ 3. On change, SDoc regenerates documentation into `public/doc/`
74
+ 4. Docs are immediately available at `/doc/index.html`
75
+ 5. Clean subprocess management with bidirectional lifecycle monitoring (Puma ↔ SDoc)
76
+
77
+ ## License
78
+
79
+ [MIT](LICENSE.txt) — Copyright (c) 2026
@@ -0,0 +1,92 @@
1
+ require "puma/plugin"
2
+
3
+ class Sdoc
4
+ end
5
+
6
+ Puma::Plugin.create do
7
+
8
+ attr_reader :puma_pid, :sdoc_pid, :log_writer
9
+
10
+ def start(launcher)
11
+ @log_writer = launcher.log_writer
12
+ @puma_pid = $PROCESS_ID
13
+
14
+ launcher.events.on_booted do
15
+
16
+ @sdoc_pid = fork do
17
+
18
+ Thread.new { monitor_puma }
19
+
20
+ begin
21
+ trap("INT") { exit 0 }
22
+ trap("TERM") { exit 0 }
23
+
24
+ require "sdoc_live"
25
+ generator = SdocLive::Generator.new
26
+ generator.build_watch
27
+ rescue => e
28
+ @log_writer.log "SdocLive error: #{ e.message }"
29
+ @log_writer.log e.backtrace.join("\n")
30
+ exit 1
31
+ end
32
+
33
+ end
34
+
35
+ in_background do
36
+
37
+ monitor_sdoc
38
+
39
+ end
40
+
41
+ end
42
+
43
+ launcher.events.on_stopped { stop_sdoc }
44
+ end
45
+
46
+ private
47
+
48
+ def stop_sdoc
49
+ Process.waitpid(sdoc_pid, Process::WNOHANG)
50
+ log "Stopping SdocLive..."
51
+ Process.kill(:INT, sdoc_pid) if sdoc_pid
52
+ Process.wait(sdoc_pid)
53
+ rescue Errno::ECHILD, Errno::ESRCH
54
+ end
55
+
56
+ def monitor_puma
57
+ monitor(:puma_dead?, "Detected Puma has gone away, stopping SdocLive...")
58
+ end
59
+
60
+ def monitor_sdoc
61
+ monitor(:sdoc_dead?, "Detected SdocLive has gone away, stopping Puma...")
62
+ end
63
+
64
+ def monitor(process_dead, message)
65
+ loop do
66
+
67
+ if send(process_dead)
68
+ log message
69
+ Process.kill(:INT, $PROCESS_ID)
70
+ break
71
+ end
72
+ sleep 2
73
+
74
+ end
75
+ end
76
+
77
+ def sdoc_dead?
78
+ Process.waitpid(sdoc_pid, Process::WNOHANG)
79
+ false
80
+ rescue Errno::ECHILD, Errno::ESRCH
81
+ true
82
+ end
83
+
84
+ def puma_dead?
85
+ Process.ppid != puma_pid
86
+ end
87
+
88
+ def log(...)
89
+ log_writer.log(...)
90
+ end
91
+
92
+ end
@@ -0,0 +1,11 @@
1
+ module SdocLive
2
+
3
+ class Engine < ::Rails::Engine
4
+
5
+ rake_tasks do
6
+ load File.expand_path("../tasks/sdoc_live.rake", __dir__)
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,84 @@
1
+ require "fileutils"
2
+
3
+ module SdocLive
4
+
5
+ class Generator
6
+
7
+ def initialize(root: nil)
8
+ @root = root || defined?(Rails) && Rails.root || Pathname.new(Dir.pwd)
9
+ @root = Pathname.new(@root) unless @root.is_a?(Pathname)
10
+
11
+ config = SdocLive.configuration
12
+
13
+ @output_dir = config.output_dir || @root.join("public", "doc")
14
+ @title = config.title
15
+ @main_file = config.main_file
16
+
17
+ @source_dirs = (config.source_dirs || ["app", "lib"]).map { @root.join(it).to_s }
18
+
19
+ @watch_dirs = (config.watch_dirs || config.source_dirs || ["app", "lib"]).map do
20
+ path = @root.join(it)
21
+ path.exist? ? path : nil
22
+ end.compact
23
+
24
+ @watch_file_type_regex = config.watch_file_type_regex
25
+ @rdoc_options = config.rdoc_options
26
+ end
27
+
28
+ def build
29
+ start_time = Time.now
30
+
31
+ require "sdoc"
32
+ require "rdoc/rdoc"
33
+
34
+ main_file = @root.join(@main_file)
35
+
36
+ args = [
37
+ "--format", "sdoc",
38
+ "--output", @output_dir.to_s,
39
+ "--title", @title,
40
+ "--force-output",
41
+ "--quiet"
42
+ ]
43
+
44
+ args.push("--main", main_file.to_s) if main_file.exist?
45
+
46
+ if @rdoc_options
47
+ args.concat(@rdoc_options)
48
+ end
49
+
50
+ args.push(main_file.to_s) if main_file.exist?
51
+ args.concat(@source_dirs.select { File.directory?(it) })
52
+
53
+ rdoc = RDoc::RDoc.new
54
+ rdoc.document(args)
55
+
56
+ elapsed = Time.now - start_time
57
+ puts "[SdocLive] Generated in #{ format('%.2f', elapsed) }s → #{ @output_dir }"
58
+ end
59
+
60
+ def build_watch
61
+ require "listen"
62
+
63
+ build
64
+
65
+ puts "[SdocLive] Starting watch mode..."
66
+
67
+ listener = Listen.to(*@watch_dirs, only: @watch_file_type_regex) do | modified, added, _removed |
68
+ next if (modified + added).empty?
69
+
70
+ puts "[SdocLive] Detected changes, regenerating..."
71
+ build
72
+ end
73
+
74
+ listener.start
75
+
76
+ loop { sleep 1 }
77
+ rescue Interrupt
78
+ puts "[SdocLive] Watch stopped"
79
+ listener&.stop
80
+ end
81
+
82
+ end
83
+
84
+ end
@@ -0,0 +1,5 @@
1
+ module SdocLive
2
+
3
+ VERSION = "0.1.0"
4
+
5
+ end
data/lib/sdoc_live.rb ADDED
@@ -0,0 +1,36 @@
1
+ require_relative "sdoc_live/version"
2
+
3
+ module SdocLive
4
+
5
+ class << self
6
+
7
+ attr_writer :configuration
8
+
9
+ def configuration
10
+ @configuration ||= Configuration.new
11
+ end
12
+
13
+ def configure
14
+ yield(configuration)
15
+ end
16
+
17
+ end
18
+
19
+ class Configuration
20
+
21
+ attr_accessor :output_dir, :title, :main_file, :source_dirs, :watch_dirs,
22
+ :watch_file_type_regex, :rdoc_options
23
+
24
+ def initialize
25
+ @source_dirs = ["app", "lib"]
26
+ @watch_file_type_regex = /\.rb$/
27
+ @title = "Documentation"
28
+ @main_file = "README.md"
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+
35
+ require_relative "sdoc_live/generator"
36
+ require_relative "sdoc_live/engine" if defined?(Rails)
@@ -0,0 +1,13 @@
1
+ namespace :sdoc do
2
+
3
+ desc "Generate SDoc documentation"
4
+ task :build do
5
+ require "sdoc_live"
6
+
7
+ generator = SdocLive::Generator.new
8
+ generator.build
9
+
10
+ puts "SDoc build completed successfully!"
11
+ end
12
+
13
+ end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sdoc_live
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - 16554289+optimuspwnius@users.noreply.github.com
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: railties
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '7.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rdoc
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '6.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '6.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: sdoc
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '2.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '2.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: listen
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '3.0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '3.0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: puma
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '5.0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '5.0'
82
+ description: Watches your app and lib directories for Ruby file changes and automatically
83
+ regenerates SDoc documentation. Includes a Puma plugin for development watch mode
84
+ and a rake task for manual/deploy builds.
85
+ email:
86
+ - 16554289+optimuspwnius@users.noreply.github.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - LICENSE.txt
92
+ - README.md
93
+ - lib/puma/plugin/sdoc.rb
94
+ - lib/sdoc_live.rb
95
+ - lib/sdoc_live/engine.rb
96
+ - lib/sdoc_live/generator.rb
97
+ - lib/sdoc_live/version.rb
98
+ - lib/tasks/sdoc_live.rake
99
+ homepage: https://github.com/optimuspwnius/sdoc-live
100
+ licenses:
101
+ - MIT
102
+ metadata:
103
+ homepage_uri: https://github.com/optimuspwnius/sdoc-live
104
+ source_code_uri: https://github.com/optimuspwnius/sdoc-live
105
+ changelog_uri: https://github.com/optimuspwnius/sdoc-live/blob/main/CHANGELOG.md
106
+ allowed_push_host: https://rubygems.org
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '3.2'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubygems_version: 4.0.7
122
+ specification_version: 4
123
+ summary: Live SDoc generation for Rails — auto-regenerates API documentation on file
124
+ changes.
125
+ test_files: []