Skip to content

Commit 9a87d29

Browse files
committed
Add server mode with live reload (rdoc --server)
Implement `rdoc --server[=PORT]` for previewing documentation with automatic browser refresh on source file changes. The server parses all sources on startup, serves pages from memory via the Aliki generator, and watches for file modifications, additions, and deletions — re-parsing only what changed. - Move RDoc::Servlet → RDoc::RI::Servlet (clarify RI-specific usage) - Add --server[=PORT] CLI option (default port 4000) - Create RDoc::Server WEBrick servlet with: - In-memory HTML page cache and search index cache - Live-reload via polling script injected into pages - Background file watcher (1s mtime polling) - Incremental re-parse of changed files only - Detection of new and deleted source files - Add RDoc::Store#remove_file for cleaning up deleted files - Extract Darkfish#refresh_store_data for server-mode reuse - Add `rdoc:server` Rake task
1 parent 5214a30 commit 9a87d29

File tree

11 files changed

+441
-10
lines changed

11 files changed

+441
-10
lines changed

lib/rdoc.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ def self.home
160160
autoload :Generator, "#{__dir__}/rdoc/generator"
161161
autoload :Options, "#{__dir__}/rdoc/options"
162162
autoload :Parser, "#{__dir__}/rdoc/parser"
163-
autoload :Servlet, "#{__dir__}/rdoc/servlet"
163+
autoload :Server, "#{__dir__}/rdoc/server"
164164
autoload :RI, "#{__dir__}/rdoc/ri"
165165
autoload :Stats, "#{__dir__}/rdoc/stats"
166166
autoload :Store, "#{__dir__}/rdoc/store"

lib/rdoc/generator/darkfish.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,15 @@ def setup
580580

581581
return unless @store
582582

583+
refresh_store_data
584+
end
585+
586+
##
587+
# Refreshes the generator's data from the store. Called by #setup and
588+
# can be called again after the store has been updated (e.g. in server
589+
# mode after re-parsing changed files).
590+
591+
def refresh_store_data
583592
@classes = @store.all_classes_and_modules.sort
584593
@files = @store.all_files.sort
585594
@methods = @classes.flat_map { |m| m.method_list }.sort

lib/rdoc/options.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ class RDoc::Options
9595
pipe
9696
rdoc_include
9797
root
98+
server_port
9899
static_path
99100
template
100101
template_dir
@@ -328,6 +329,13 @@ class RDoc::Options
328329

329330
attr_reader :visibility
330331

332+
##
333+
# When set to a port number, starts a live-reloading server instead of
334+
# writing files. Defaults to +false+ (no server). Set via
335+
# <tt>--server[=PORT]</tt>.
336+
337+
attr_reader :server_port
338+
331339
##
332340
# Indicates if files of test suites should be skipped
333341
attr_accessor :skip_tests
@@ -410,6 +418,7 @@ def init_ivars # :nodoc:
410418
@output_decoration = true
411419
@rdoc_include = []
412420
@root = Pathname(Dir.pwd)
421+
@server_port = false
413422
@show_hash = false
414423
@static_path = []
415424
@tab_width = 8
@@ -1123,6 +1132,15 @@ def parse(argv)
11231132
opt.separator "Generic options:"
11241133
opt.separator nil
11251134

1135+
opt.on("--server[=PORT]", Integer,
1136+
"Start a web server to preview",
1137+
"documentation with live reload.",
1138+
"Defaults to port 4000.") do |port|
1139+
@server_port = port || 4000
1140+
end
1141+
1142+
opt.separator nil
1143+
11261144
opt.on("--write-options",
11271145
"Write .rdoc_options to the current",
11281146
"directory with the given options. Not all",

lib/rdoc/rdoc.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,19 @@ def document(options)
456456
exit
457457
end
458458

459+
if @options.server_port
460+
@store.load_cache
461+
462+
file_info = parse_files @options.files
463+
464+
@options.default_title = "RDoc Documentation"
465+
466+
@store.complete @options.visibility
467+
468+
start_server
469+
return
470+
end
471+
459472
unless @options.coverage_report then
460473
@last_modified = setup_output_dir @options.op_dir, @options.force_update
461474
end
@@ -516,6 +529,31 @@ def generate
516529
end
517530
end
518531

532+
##
533+
# Starts a live-reloading WEBrick server for previewing documentation.
534+
# Called from #document when <tt>--server</tt> is given.
535+
536+
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."
550+
551+
trap('INT') { server.shutdown }
552+
trap('TERM') { server.shutdown }
553+
554+
server.start
555+
end
556+
519557
##
520558
# Removes a siginfo handler and replaces the previous
521559

lib/rdoc/ri.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ module RDoc::RI
1313

1414
class Error < RDoc::Error; end
1515

16-
autoload :Driver, "#{__dir__}/ri/driver"
17-
autoload :Paths, "#{__dir__}/ri/paths"
18-
autoload :Store, "#{__dir__}/ri/store"
16+
autoload :Driver, "#{__dir__}/ri/driver"
17+
autoload :Paths, "#{__dir__}/ri/paths"
18+
autoload :Servlet, "#{__dir__}/ri/servlet"
19+
autoload :Store, "#{__dir__}/ri/store"
1920

2021
end

lib/rdoc/ri/driver.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1521,7 +1521,7 @@ def start_server
15211521

15221522
extra_doc_dirs = @stores.map {|s| s.type == :extra ? s.path : nil}.compact
15231523

1524-
server.mount '/', RDoc::Servlet, nil, extra_doc_dirs
1524+
server.mount '/', RDoc::RI::Servlet, nil, extra_doc_dirs
15251525

15261526
trap 'INT' do server.shutdown end
15271527
trap 'TERM' do server.shutdown end
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
2-
require_relative '../rdoc'
2+
require_relative '../../rdoc'
33
require 'erb'
44
require 'time'
55
require 'json'
@@ -31,7 +31,7 @@
3131
#
3232
# server.mount '/rdoc', RDoc::Servlet, '/rdoc'
3333

34-
class RDoc::Servlet < WEBrick::HTTPServlet::AbstractServlet
34+
class RDoc::RI::Servlet < WEBrick::HTTPServlet::AbstractServlet
3535

3636
@server_stores = Hash.new { |hash, server| hash[server] = {} }
3737
@cache = Hash.new { |hash, store| hash[store] = {} }

0 commit comments

Comments
 (0)