Class: RDoc::Server

Inherits:
Object
  • Object
show all
Defined in:
lib/rdoc/server.rb

Overview

A minimal HTTP server for live-reloading RDoc documentation.

Uses Ruby’s built-in TCPServer (no external dependencies).

Used by rdoc --server to let developers preview documentation while editing source files. Parses sources once on startup, watches for file changes, re-parses only the changed files, and auto-refreshes the browser via a simple polling script.

Defined Under Namespace

Classes: FileChanges

Constant Summary collapse

CONTENT_TYPES =
{
  '.html' => 'text/html',
  '.css'  => 'text/css',
  '.js'   => 'application/javascript',
  '.json' => 'application/json',
}.freeze
STATUS_TEXTS =
{
  200 => 'OK',
  400 => 'Bad Request',
  404 => 'Not Found',
  405 => 'Method Not Allowed',
  500 => 'Internal Server Error',
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rdoc, port) ⇒ Server

Creates a new server.

rdoc is the RDoc::RDoc instance that has already parsed the source files. port is the TCP port to listen on.



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/rdoc/server.rb', line 100

def initialize(rdoc, port)
  @rdoc = rdoc
  @options = rdoc.options
  @store = rdoc.store
  @port = port

  # Silence stats output — the server prints its own timing.
  @rdoc.stats.verbosity = 0
  @generator = create_generator
  @template_dir = File.expand_path(@generator.template_dir)
  @page_cache = {}
  @last_change_time = Time.now.to_f
  @mutex = Mutex.new
  @running = false
end

Class Method Details

.live_reload_script(last_change_time) ⇒ Object

Returns a live-reload polling script with the given last_change_time embedded so the browser knows the exact timestamp of the content it received. This avoids a race where a change that occurs between page generation and the first poll would be silently skipped.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/rdoc/server.rb', line 27

def self.live_reload_script(last_change_time)
  <<~JS
    <script>
    (function() {
      var lastChange = #{last_change_time.to_json};
      setInterval(function() {
        fetch('/__status').then(function(r) { return r.json(); }).then(function(data) {
          if (data.last_change > lastChange) location.reload();
          lastChange = data.last_change;
        }).catch(function() {});
      }, 1000);
    })();
    </script>
  JS
end

Instance Method Details

#startObject

Starts the server. Blocks until interrupted.



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/rdoc/server.rb', line 119

def start
  @tcp_server = TCPServer.new('127.0.0.1', @port)
  @running = true

  @watcher_thread = start_watcher(@rdoc.watch_files)

  url = "http://localhost:#{@port}"
  $stderr.puts "\nServing documentation at: \e]8;;#{url}\e\\#{url}\e]8;;\e\\"
  $stderr.puts "Press Ctrl+C to stop.\n\n"

  loop do
    client = @tcp_server.accept
    Thread.new(client) { |c| handle_client(c) }
  end
rescue Interrupt
  # Ctrl+C
ensure
  @running = false
  @tcp_server&.close
  @watcher_thread&.join(2)
end