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'
属性
将资产类型映射到其在文件系统上的路径
用于渲染选项的 RDoc::Options
实例
公共类方法
创建一个新的 WEBrick servlet。
当将 servlet 挂载到 / 以外的位置时使用 mount_path
。
使用 extra_doc_dirs
来添加额外的文档目录。
server
在挂载时由 WEBrick 自动提供。stores
和 cache
由 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
公共实例方法
通过 res
为 generator_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
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
使用来自 store
的 req
的类、模块或页面填充 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
为给定的 store
在 res
上创建 JSON 搜索索引。generator
必须响应 #json_index 来构建。req
被忽略。
# File rdoc/servlet.rb, line 171 def documentation_search store, generator, req, res json_index = @cache[store].fetch :json_index do @cache[store][:json_index] = JSON.dump generator.json_index.build_index end res.content_type = 'application/javascript' res.body = "var search_data = #{json_index}" end
返回 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
为在 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
为 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
在 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
返回已安装文档的数组。
每个条目包含文档名称(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
为 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 路径。请参见 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
在 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
在 res
上为根页面生成搜索索引。req
被忽略。
# File rdoc/servlet.rb, line 345 def root_search req, res search_index = [] info = [] installed_docs.map do |name, href, exists, type, path| next unless exists search_index << name case type when :gem gemspec = path.gsub(%r%/doc/([^/]*?)/ri$%, '/specifications/\1.gemspec') spec = Gem::Specification.load gemspec path = spec.full_name comment = spec.summary when :system then path = 'ruby' comment = 'Documentation for the Ruby standard library' when :site then path = 'site' comment = 'Documentation for non-gem libraries' when :home then path = 'home' comment = 'Documentation from your home directory' when :extra comment = name end info << [name, '', path, '', comment] end index = { :index => { :searchIndex => search_index, :longSearchIndex => search_index, :info => info, } } res.body = "var search_data = #{JSON.dump index};" res.content_type = 'application/javascript' end
在 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
为给定的 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