class RDoc::Servlet

这是一个 WEBrick servlet,允许您浏览 ri 文档。

您可以通过 'ri --server' 或使用 RubyGems 2.0 或更新版本,'gem server' 来显示文档。对于 ri,服务器默认在端口 8214 上运行。对于 RubyGems,服务器默认在端口 8808 上运行。

您可以通过将其挂载在 WEBrick 服务器上来在您自己的项目中使用此 servlet

require 'webrick'

server = WEBrick::HTTPServer.new Port: 8000

server.mount '/', RDoc::Servlet

如果想将 servlet 挂载到根目录以外的其他位置,请在挂载时提供基本路径

server.mount '/rdoc', RDoc::Servlet, '/rdoc'

属性

asset_dirs[R]

将资产类型映射到其在文件系统上的路径

options[R]

用于渲染选项的 RDoc::Options 实例

公共类方法

new(server, stores, cache, mount_path = nil, extra_doc_dirs = []) 点击以切换源代码

创建一个新的 WEBrick servlet。

当将 servlet 挂载到 / 以外的位置时使用 mount_path

使用 extra_doc_dirs 来添加额外的文档目录。

server 在挂载时由 WEBrick 自动提供。storescache 由 servlet 自动提供。

调用超类方法
# File rdoc/servlet.rb, line 69
def initialize server, stores, cache, mount_path = nil, extra_doc_dirs = []
  super server

  @cache      = cache
  @mount_path = mount_path
  @extra_doc_dirs = extra_doc_dirs
  @stores     = stores

  @options = RDoc::Options.new
  @options.op_dir = '.'

  darkfish_dir = nil

  # HACK dup
  $LOAD_PATH.each do |path|
    darkfish_dir = File.join path, 'rdoc/generator/template/darkfish/'
    next unless File.directory? darkfish_dir
    @options.template_dir = darkfish_dir
    break
  end

  @asset_dirs = {
    :darkfish   => darkfish_dir,
    :json_index =>
      File.expand_path('../generator/template/json_index/', __FILE__),
  }
end

公共实例方法

asset(generator_name, req, res) 点击以切换源代码

通过 resgenerator_name 提供 req 中路径处的资产。

# File rdoc/servlet.rb, line 100
def asset generator_name, req, res
  asset_dir = @asset_dirs[generator_name]

  asset_path = File.join asset_dir, req.path

  if_modified_since req, res, asset_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
do_GET(req, res) 点击以切换源代码

GET 请求入口点。为 req 中的路径等填充 res

# File rdoc/servlet.rb, line 119
def do_GET req, res
  req.path.sub!(/\A#{Regexp.escape @mount_path}/, '') if @mount_path

  case req.path
  when '/' then
    root req, res
  when '/js/darkfish.js', '/js/jquery.js', '/js/search.js',
       %r%^/css/%, %r%^/images/%, %r%^/fonts/% then
    asset :darkfish, req, res
  when '/js/navigation.js', '/js/searcher.js' then
    asset :json_index, req, res
  when '/js/search_index.js' then
    root_search req, res
  else
    show_documentation req, res
  end
rescue WEBrick::HTTPStatus::NotFound => e
  generator = generator_for RDoc::Store.new

  not_found generator, req, res, e.message
rescue WEBrick::HTTPStatus::Status
  raise
rescue => e
  error e, req, res
end
documentation_page(store, generator, path, req, res) 点击以切换源代码

使用来自 storereq 的类、模块或页面填充 res

path 相对于 mount_path,用于确定类、模块或页面名称(/RDoc/Servlet.html 变为 RDoc::Servlet)。generator 用于创建页面。

# File rdoc/servlet.rb, line 152
def documentation_page store, generator, path, req, res
  text_name = path.chomp '.html'
  name = text_name.gsub '/', '::'

  if klass = store.find_class_or_module(name) then
    res.body = generator.generate_class klass
  elsif page = store.find_text_page(name.sub(/_([^_]*)\z/, '.\1')) then
    res.body = generator.generate_page page
  elsif page = store.find_text_page(text_name.sub(/_([^_]*)\z/, '.\1')) then
    res.body = generator.generate_page page
  else
    not_found generator, req, res
  end
end
documentation_source(path) 点击以切换源代码

返回 RDoc::Store 和相对于 mount_path 的文档路径,路径为 path

# File rdoc/servlet.rb, line 185
def documentation_source path
  _, source_name, path = path.split '/', 3

  store = @stores[source_name]
  return store, path if store

  store = store_for source_name

  store.load_all

  @stores[source_name] = store

  return store, path
end
error(exception, req, res) 点击以切换源代码

为在 res 上处理 req 时出现的 exception 生成错误页面。

# File rdoc/servlet.rb, line 203
  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="#{@mount_path}/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
generator_for(store) 点击以切换源代码

store 实例化一个 Darkfish 生成器

# File rdoc/servlet.rb, line 246
def generator_for store
  generator = RDoc::Generator::Darkfish.new store, @options
  generator.file_output = false
  generator.asset_rel_path = '..'

  rdoc = RDoc::RDoc.new
  rdoc.store     = store
  rdoc.generator = generator
  rdoc.options   = @options

  @options.main_page = store.main
  @options.title     = store.title

  generator
end
if_modified_since(req, res, path = nil) 点击以切换源代码

req 上为 path 处理 If-Modified-Since HTTP 标头。如果文件未被修改,则返回未修改的响应。如果文件已被修改,则将 Last-Modified 标头添加到 res

# File rdoc/servlet.rb, line 267
def if_modified_since req, res, path = nil
  last_modified = File.stat(path).mtime if path

  res['last-modified'] = last_modified.httpdate

  return unless ims = req['if-modified-since']

  ims = Time.parse ims

  unless ims < last_modified then
    res.body = ''
    raise WEBrick::HTTPStatus::NotModified
  end
end
installed_docs() 点击以切换源代码

返回已安装文档的数组。

每个条目包含文档名称(gem 名称、“Ruby 文档”等)、相对于挂载点的路径、文档是否存在、文档类型(请参见 RDoc::RI::Paths#each)以及文档的 RDoc::Store 的文件系统。

# File rdoc/servlet.rb, line 290
def installed_docs
  extra_counter = 0
  ri_paths.map do |path, type|
    store = RDoc::Store.new path, type
    exists = File.exist? store.cache_path

    case type
    when :gem then
      gem_path = path[%r%/([^/]*)/ri$%, 1]
      [gem_path, "#{gem_path}/", exists, type, path]
    when :system then
      ['Ruby Documentation', 'ruby/', exists, type, path]
    when :site then
      ['Site Documentation', 'site/', exists, type, path]
    when :home then
      ['Home Documentation', 'home/', exists, type, path]
    when :extra then
      extra_counter += 1
      store.load_cache if exists
      title = store.title || "Extra Documentation"
      [title, "extra-#{extra_counter}/", exists, type, path]
    end
  end
end
not_found(generator, req, res, message = nil) 点击以切换源代码

res 上的 req 返回由 generator 构建的 404 页面。

# File rdoc/servlet.rb, line 318
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
ri_paths(&block) 点击以切换源代码

枚举 ri 路径。请参见 RDoc::RI::Paths#each

# File rdoc/servlet.rb, line 327
def ri_paths &block
  RDoc::RI::Paths.each true, true, true, :all, *@extra_doc_dirs, &block #TODO: pass extra_dirs
end
root(req, res) 点击以切换源代码

res 上生成根页面。req 被忽略。

# File rdoc/servlet.rb, line 334
def root req, res
  generator = RDoc::Generator::Darkfish.new nil, @options

  res.body = generator.generate_servlet_root installed_docs

  res.content_type = 'text/html'
end
show_documentation(req, res) 点击以切换源代码

res 上显示 req 的文档,无论是 HTML 还是某些资产。

# File rdoc/servlet.rb, line 395
def show_documentation req, res
  store, path = documentation_source req.path

  if_modified_since req, res, store.cache_path

  generator = generator_for store

  case path
  when nil, '', 'index.html' then
    res.body = generator.generate_index
  when 'table_of_contents.html' then
    res.body = generator.generate_table_of_contents
  when 'js/search_index.js' then
    documentation_search store, generator, req, res
  else
    documentation_page store, generator, path, req, res
  end
ensure
  res.content_type ||= 'text/html'
end
store_for(source_name) 点击以切换源代码

为给定的 source_name(“ruby”或 gem 名称)返回 RDoc::Store

# File rdoc/servlet.rb, line 419
def store_for source_name
  case source_name
  when 'home' then
    RDoc::Store.new RDoc::RI::Paths.home_dir, :home
  when 'ruby' then
    RDoc::Store.new RDoc::RI::Paths.system_dir, :system
  when 'site' then
    RDoc::Store.new RDoc::RI::Paths.site_dir, :site
  when /\Aextra-(\d+)\z/ then
    index = $1.to_i - 1
    ri_dir = installed_docs[index][4]
    RDoc::Store.new ri_dir, :extra
  else
    ri_dir, type = ri_paths.find do |dir, dir_type|
      next unless dir_type == :gem

      source_name == dir[%r%/([^/]*)/ri$%, 1]
    end

    raise WEBrick::HTTPStatus::NotFound,
          "Could not find gem \"#{ERB::Util.html_escape(source_name)}\". Are you sure you installed it?" unless ri_dir

    store = RDoc::Store.new ri_dir, type

    return store if File.exist? store.cache_path

    raise WEBrick::HTTPStatus::NotFound,
          "Could not find documentation for \"#{ERB::Util.html_escape(source_name)}\". Please run `gem rdoc --ri gem_name`"

  end
end