Skip to content

Commit

Permalink
Add RDoc::Server and --server flag
Browse files Browse the repository at this point in the history
  • Loading branch information
st0012 committed Aug 5, 2024
1 parent 8d8f344 commit f0e98cf
Show file tree
Hide file tree
Showing 7 changed files with 240 additions and 2 deletions.
1 change: 1 addition & 0 deletions lib/rdoc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ def self.home
autoload :Store, "#{__dir__}/rdoc/store"
autoload :Task, "#{__dir__}/rdoc/task"
autoload :Text, "#{__dir__}/rdoc/text"
autoload :Server, "#{__dir__}/rdoc/server"

autoload :Markdown, "#{__dir__}/rdoc/markdown"
autoload :Markup, "#{__dir__}/rdoc/markup"
Expand Down
16 changes: 16 additions & 0 deletions lib/rdoc/generator/darkfish.rb
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,22 @@ def generate
raise
end

def generate_for_server
write_style_sheet
generate_index
generate_class_files
generate_file_files
generate_table_of_contents

copy_static
rescue => e
debug_msg "%s: %s\n %s" % [
e.class.name, e.message, e.backtrace.join("\n ")
]

raise
end

##
# Copies static files from the static_path into the output directory

Expand Down
14 changes: 14 additions & 0 deletions lib/rdoc/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,11 @@ class RDoc::Options

attr_reader :visibility

##
# Whether server mode is enabled or not

attr_reader :server

##
# Indicates if files of test suites should be skipped
attr_accessor :skip_tests
Expand Down Expand Up @@ -392,6 +397,7 @@ def init_ivars # :nodoc:
@encoding = Encoding::UTF_8
@charset = @encoding.name
@skip_tests = true
@server = false
end

def init_with map # :nodoc:
Expand Down Expand Up @@ -1116,6 +1122,14 @@ def parse argv

opt.separator nil

opt.on(
"--server",
"-s",
"[Experimental] Run WEBrick server with generated documentation. Will use ./tmp for file output."
) do
@server = true
end

opt.on("--help", "-h", "Display this help") do
RDoc::RDoc::GENERATORS.each_key do |generator|
setup_generator generator
Expand Down
31 changes: 29 additions & 2 deletions lib/rdoc/rdoc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ def document options
exit
end

unless @options.coverage_report then
unless @options.coverage_report || @options.server
@last_modified = setup_output_dir @options.op_dir, @options.force_update
end

Expand Down Expand Up @@ -496,9 +496,16 @@ def document options

@generator = gen_klass.new @store, @options

generate
if @options.server
start_server
else
generate
end
end

# Don't need to run stats for server mode
return if @options.server

if @stats and (@options.coverage_report or not @options.quiet) then
puts
puts @stats.summary.accept RDoc::Markup::ToRdoc.new
Expand All @@ -507,6 +514,26 @@ def document options
exit @stats.fully_documented? if @options.coverage_report
end

def start_server
begin
require 'webrick'
rescue LoadError
abort "webrick is not found. You may need to `gem install webrick` to install webrick."
end

# Change the output directory to tmp so it doesn't overwrite the current documentation
Dir.chdir "tmp" do
server = WEBrick::HTTPServer.new :Port => 8080

server.mount '/', RDoc::Server, self

trap 'INT' do server.shutdown end
trap 'TERM' do server.shutdown end

server.start
end
end

##
# Generates documentation for +file_info+ (from #parse_files) into the
# output dir using the generator selected
Expand Down
178 changes: 178 additions & 0 deletions lib/rdoc/server.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
# frozen_string_literal: true
require 'erb'
require 'time'
require 'json'

class RDoc::Server < WEBrick::HTTPServlet::AbstractServlet
##
# Creates an instance of this servlet that shares cached data between
# requests.

def self.get_instance server, rdoc # :nodoc:
new server, rdoc
end

##
# Creates a new WEBrick servlet.
#
# +server+ is provided automatically by WEBrick when mounting.
# +rdoc+ is the RDoc::RDoc instance to display documentation from.

def initialize server, rdoc
super server

@rdoc = rdoc
@generator = rdoc.generator
@generator.file_output = false

darkfish_dir = File.join(__dir__, 'generator/template/darkfish/')
json_index_dir = File.join(__dir__, 'generator/template/json_index/')

@asset_dirs = {
:darkfish => darkfish_dir,
:json_index => json_index_dir,
}
end

##
# GET request entry point. Fills in +res+ for the path, etc. in +req+.

def do_GET req, res
req.path.sub!(/\A\//, '')

case req.path
when '/'
res.body = @generator.generate_servlet_root installed_docs
res.content_type = 'text/html'
when 'js/darkfish.js', 'js/jquery.js', 'js/search.js', %r{^css/}, %r{^images/}, %r{^fonts/}
asset :darkfish, req, res
when 'js/navigation.js', 'js/searcher.js'
asset :json_index, req, res
when 'js/search_index.js'
res.body = "var search_data = #{JSON.dump @generator.json_index.build_index}"
res.content_type = 'application/javascript'
else
show_documentation req, res
end
rescue WEBrick::HTTPStatus::NotFound => e
not_found @generator, req, res, e.message
rescue WEBrick::HTTPStatus::Status
raise
rescue => e
$stderr.puts e.full_message
error e, req, res
end

private

def asset generator_name, req, res
asset_dir = @asset_dirs[generator_name]

asset_path = File.join asset_dir, req.path

res.body = File.read asset_path

res.content_type = case req.path
when /\.css\z/ then 'text/css'
when /\.js\z/ then 'application/javascript'
else 'application/octet-stream'
end
end

PAGE_NAME_SUB_REGEXP = /_([^_]*)\z/

def documentation_page store, generator, path, req, res
text_name = path.chomp '.html'
name = text_name.gsub '/', '::'

content = if klass = store.find_class_or_module(name)
generator.generate_class klass
elsif page = store.find_text_page(name.sub(PAGE_NAME_SUB_REGEXP, '.\1'))
generator.generate_page page
elsif page = store.find_text_page(text_name.sub(PAGE_NAME_SUB_REGEXP, '.\1'))
generator.generate_page page
elsif page = store.find_file_named(text_name.sub(PAGE_NAME_SUB_REGEXP, '.\1'))
generator.generate_page page
end

if content
res.body = content
else
not_found generator, req, res
end
end

def error exception, req, res
backtrace = exception.backtrace.join "\n"

res.content_type = 'text/html'
res.status = 500
res.body = <<-BODY
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
<title>Error - #{ERB::Util.html_escape exception.class}</title>
<link type="text/css" media="screen" href="/css/rdoc.css" rel="stylesheet">
</head>
<body>
<h1>Error</h1>
<p>While processing <code>#{ERB::Util.html_escape req.request_uri}</code> the
RDoc (#{ERB::Util.html_escape RDoc::VERSION}) server has encountered a
<code>#{ERB::Util.html_escape exception.class}</code>
exception:
<pre>#{ERB::Util.html_escape exception.message}</pre>
<p>Please report this to the
<a href="https://github.com/ruby/rdoc/issues">RDoc issues tracker</a>. Please
include the RDoc version, the URI above and exception class, message and
backtrace. If you're viewing a gem's documentation, include the gem name and
version. If you're viewing Ruby's documentation, include the version of ruby.
<p>Backtrace:
<pre>#{ERB::Util.html_escape backtrace}</pre>
</body>
</html>
BODY
end

def not_found generator, req, res, message = nil
message ||= "The page <kbd>#{ERB::Util.h req.path}</kbd> was not found"
res.body = generator.generate_servlet_not_found message
res.status = 404
end

def show_documentation req, res
# Clear all the previous data
@rdoc.store.classes_hash.clear
@rdoc.store.modules_hash.clear
@rdoc.store.files_hash.clear

# RDoc instance use last_modified list to avoid reparsing files
# We need to clear it to force reparsing
@rdoc.last_modified.clear

# Reparse the files
@rdoc.parse_files(@rdoc.options.files)

# Regenerate the documentation and asserts
@generator.generate_for_server

case req.path
when nil, '', 'index.html'
res.body = @generator.generate_index
when 'table_of_contents.html'
res.body = @generator.generate_table_of_contents
else
documentation_page @rdoc.store, @generator, req.path, req, res
end
ensure
res.content_type ||= 'text/html'
end
end
1 change: 1 addition & 0 deletions rdoc.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat
"lib/rdoc/ri/task.rb",
"lib/rdoc/ri/servlet.rb",
"lib/rdoc/rubygems_hook.rb",
"lib/rdoc/server.rb",
"lib/rdoc/single_class.rb",
"lib/rdoc/stats.rb",
"lib/rdoc/stats/normal.rb",
Expand Down
1 change: 1 addition & 0 deletions test/rdoc/test_rdoc_options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ def test_to_yaml
'title' => nil,
'visibility' => :protected,
'webcvs' => nil,
'server' => false,
'skip_tests' => true,
}

Expand Down

0 comments on commit f0e98cf

Please sign in to comment.