Skip to content

Commit f0e98cf

Browse files
committed
Add RDoc::Server and --server flag
1 parent 8d8f344 commit f0e98cf

File tree

7 files changed

+240
-2
lines changed

7 files changed

+240
-2
lines changed

lib/rdoc.rb

+1
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ def self.home
167167
autoload :Store, "#{__dir__}/rdoc/store"
168168
autoload :Task, "#{__dir__}/rdoc/task"
169169
autoload :Text, "#{__dir__}/rdoc/text"
170+
autoload :Server, "#{__dir__}/rdoc/server"
170171

171172
autoload :Markdown, "#{__dir__}/rdoc/markdown"
172173
autoload :Markup, "#{__dir__}/rdoc/markup"

lib/rdoc/generator/darkfish.rb

+16
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,22 @@ def generate
259259
raise
260260
end
261261

262+
def generate_for_server
263+
write_style_sheet
264+
generate_index
265+
generate_class_files
266+
generate_file_files
267+
generate_table_of_contents
268+
269+
copy_static
270+
rescue => e
271+
debug_msg "%s: %s\n %s" % [
272+
e.class.name, e.message, e.backtrace.join("\n ")
273+
]
274+
275+
raise
276+
end
277+
262278
##
263279
# Copies static files from the static_path into the output directory
264280

lib/rdoc/options.rb

+14
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,11 @@ class RDoc::Options
340340

341341
attr_reader :visibility
342342

343+
##
344+
# Whether server mode is enabled or not
345+
346+
attr_reader :server
347+
343348
##
344349
# Indicates if files of test suites should be skipped
345350
attr_accessor :skip_tests
@@ -392,6 +397,7 @@ def init_ivars # :nodoc:
392397
@encoding = Encoding::UTF_8
393398
@charset = @encoding.name
394399
@skip_tests = true
400+
@server = false
395401
end
396402

397403
def init_with map # :nodoc:
@@ -1116,6 +1122,14 @@ def parse argv
11161122

11171123
opt.separator nil
11181124

1125+
opt.on(
1126+
"--server",
1127+
"-s",
1128+
"[Experimental] Run WEBrick server with generated documentation. Will use ./tmp for file output."
1129+
) do
1130+
@server = true
1131+
end
1132+
11191133
opt.on("--help", "-h", "Display this help") do
11201134
RDoc::RDoc::GENERATORS.each_key do |generator|
11211135
setup_generator generator

lib/rdoc/rdoc.rb

+29-2
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ def document options
463463
exit
464464
end
465465

466-
unless @options.coverage_report then
466+
unless @options.coverage_report || @options.server
467467
@last_modified = setup_output_dir @options.op_dir, @options.force_update
468468
end
469469

@@ -496,9 +496,16 @@ def document options
496496

497497
@generator = gen_klass.new @store, @options
498498

499-
generate
499+
if @options.server
500+
start_server
501+
else
502+
generate
503+
end
500504
end
501505

506+
# Don't need to run stats for server mode
507+
return if @options.server
508+
502509
if @stats and (@options.coverage_report or not @options.quiet) then
503510
puts
504511
puts @stats.summary.accept RDoc::Markup::ToRdoc.new
@@ -507,6 +514,26 @@ def document options
507514
exit @stats.fully_documented? if @options.coverage_report
508515
end
509516

517+
def start_server
518+
begin
519+
require 'webrick'
520+
rescue LoadError
521+
abort "webrick is not found. You may need to `gem install webrick` to install webrick."
522+
end
523+
524+
# Change the output directory to tmp so it doesn't overwrite the current documentation
525+
Dir.chdir "tmp" do
526+
server = WEBrick::HTTPServer.new :Port => 8080
527+
528+
server.mount '/', RDoc::Server, self
529+
530+
trap 'INT' do server.shutdown end
531+
trap 'TERM' do server.shutdown end
532+
533+
server.start
534+
end
535+
end
536+
510537
##
511538
# Generates documentation for +file_info+ (from #parse_files) into the
512539
# output dir using the generator selected

lib/rdoc/server.rb

+178
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
# frozen_string_literal: true
2+
require 'erb'
3+
require 'time'
4+
require 'json'
5+
6+
class RDoc::Server < WEBrick::HTTPServlet::AbstractServlet
7+
##
8+
# Creates an instance of this servlet that shares cached data between
9+
# requests.
10+
11+
def self.get_instance server, rdoc # :nodoc:
12+
new server, rdoc
13+
end
14+
15+
##
16+
# Creates a new WEBrick servlet.
17+
#
18+
# +server+ is provided automatically by WEBrick when mounting.
19+
# +rdoc+ is the RDoc::RDoc instance to display documentation from.
20+
21+
def initialize server, rdoc
22+
super server
23+
24+
@rdoc = rdoc
25+
@generator = rdoc.generator
26+
@generator.file_output = false
27+
28+
darkfish_dir = File.join(__dir__, 'generator/template/darkfish/')
29+
json_index_dir = File.join(__dir__, 'generator/template/json_index/')
30+
31+
@asset_dirs = {
32+
:darkfish => darkfish_dir,
33+
:json_index => json_index_dir,
34+
}
35+
end
36+
37+
##
38+
# GET request entry point. Fills in +res+ for the path, etc. in +req+.
39+
40+
def do_GET req, res
41+
req.path.sub!(/\A\//, '')
42+
43+
case req.path
44+
when '/'
45+
res.body = @generator.generate_servlet_root installed_docs
46+
res.content_type = 'text/html'
47+
when 'js/darkfish.js', 'js/jquery.js', 'js/search.js', %r{^css/}, %r{^images/}, %r{^fonts/}
48+
asset :darkfish, req, res
49+
when 'js/navigation.js', 'js/searcher.js'
50+
asset :json_index, req, res
51+
when 'js/search_index.js'
52+
res.body = "var search_data = #{JSON.dump @generator.json_index.build_index}"
53+
res.content_type = 'application/javascript'
54+
else
55+
show_documentation req, res
56+
end
57+
rescue WEBrick::HTTPStatus::NotFound => e
58+
not_found @generator, req, res, e.message
59+
rescue WEBrick::HTTPStatus::Status
60+
raise
61+
rescue => e
62+
$stderr.puts e.full_message
63+
error e, req, res
64+
end
65+
66+
private
67+
68+
def asset generator_name, req, res
69+
asset_dir = @asset_dirs[generator_name]
70+
71+
asset_path = File.join asset_dir, req.path
72+
73+
res.body = File.read asset_path
74+
75+
res.content_type = case req.path
76+
when /\.css\z/ then 'text/css'
77+
when /\.js\z/ then 'application/javascript'
78+
else 'application/octet-stream'
79+
end
80+
end
81+
82+
PAGE_NAME_SUB_REGEXP = /_([^_]*)\z/
83+
84+
def documentation_page store, generator, path, req, res
85+
text_name = path.chomp '.html'
86+
name = text_name.gsub '/', '::'
87+
88+
content = if klass = store.find_class_or_module(name)
89+
generator.generate_class klass
90+
elsif page = store.find_text_page(name.sub(PAGE_NAME_SUB_REGEXP, '.\1'))
91+
generator.generate_page page
92+
elsif page = store.find_text_page(text_name.sub(PAGE_NAME_SUB_REGEXP, '.\1'))
93+
generator.generate_page page
94+
elsif page = store.find_file_named(text_name.sub(PAGE_NAME_SUB_REGEXP, '.\1'))
95+
generator.generate_page page
96+
end
97+
98+
if content
99+
res.body = content
100+
else
101+
not_found generator, req, res
102+
end
103+
end
104+
105+
def error exception, req, res
106+
backtrace = exception.backtrace.join "\n"
107+
108+
res.content_type = 'text/html'
109+
res.status = 500
110+
res.body = <<-BODY
111+
<!DOCTYPE html>
112+
<html>
113+
<head>
114+
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
115+
116+
<title>Error - #{ERB::Util.html_escape exception.class}</title>
117+
118+
<link type="text/css" media="screen" href="/css/rdoc.css" rel="stylesheet">
119+
</head>
120+
<body>
121+
<h1>Error</h1>
122+
123+
<p>While processing <code>#{ERB::Util.html_escape req.request_uri}</code> the
124+
RDoc (#{ERB::Util.html_escape RDoc::VERSION}) server has encountered a
125+
<code>#{ERB::Util.html_escape exception.class}</code>
126+
exception:
127+
128+
<pre>#{ERB::Util.html_escape exception.message}</pre>
129+
130+
<p>Please report this to the
131+
<a href="https://github.com/ruby/rdoc/issues">RDoc issues tracker</a>. Please
132+
include the RDoc version, the URI above and exception class, message and
133+
backtrace. If you're viewing a gem's documentation, include the gem name and
134+
version. If you're viewing Ruby's documentation, include the version of ruby.
135+
136+
<p>Backtrace:
137+
138+
<pre>#{ERB::Util.html_escape backtrace}</pre>
139+
140+
</body>
141+
</html>
142+
BODY
143+
end
144+
145+
def not_found generator, req, res, message = nil
146+
message ||= "The page <kbd>#{ERB::Util.h req.path}</kbd> was not found"
147+
res.body = generator.generate_servlet_not_found message
148+
res.status = 404
149+
end
150+
151+
def show_documentation req, res
152+
# Clear all the previous data
153+
@rdoc.store.classes_hash.clear
154+
@rdoc.store.modules_hash.clear
155+
@rdoc.store.files_hash.clear
156+
157+
# RDoc instance use last_modified list to avoid reparsing files
158+
# We need to clear it to force reparsing
159+
@rdoc.last_modified.clear
160+
161+
# Reparse the files
162+
@rdoc.parse_files(@rdoc.options.files)
163+
164+
# Regenerate the documentation and asserts
165+
@generator.generate_for_server
166+
167+
case req.path
168+
when nil, '', 'index.html'
169+
res.body = @generator.generate_index
170+
when 'table_of_contents.html'
171+
res.body = @generator.generate_table_of_contents
172+
else
173+
documentation_page @rdoc.store, @generator, req.path, req, res
174+
end
175+
ensure
176+
res.content_type ||= 'text/html'
177+
end
178+
end

rdoc.gemspec

+1
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat
210210
"lib/rdoc/ri/task.rb",
211211
"lib/rdoc/ri/servlet.rb",
212212
"lib/rdoc/rubygems_hook.rb",
213+
"lib/rdoc/server.rb",
213214
"lib/rdoc/single_class.rb",
214215
"lib/rdoc/stats.rb",
215216
"lib/rdoc/stats/normal.rb",

test/rdoc/test_rdoc_options.rb

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ def test_to_yaml
8282
'title' => nil,
8383
'visibility' => :protected,
8484
'webcvs' => nil,
85+
'server' => false,
8586
'skip_tests' => true,
8687
}
8788

0 commit comments

Comments
 (0)