diff options
Diffstat (limited to 'lib/rubygems/server.rb')
-rw-r--r-- | lib/rubygems/server.rb | 192 |
1 files changed, 188 insertions, 4 deletions
diff --git a/lib/rubygems/server.rb b/lib/rubygems/server.rb index 2c617ff144..44bee74abf 100644 --- a/lib/rubygems/server.rb +++ b/lib/rubygems/server.rb @@ -17,6 +17,7 @@ require 'rubygems/doc_manager' # name/version/platform index # * "/quick/" - Individual gemspecs # * "/gems" - Direct access to download the installable gems +# * "/rdoc?q=" - Search for installed rdoc documentation # * legacy indexes: # * "/Marshal.#{Gem.marshal_version}" - Full SourceIndex dump of metadata # for installed gems @@ -32,9 +33,20 @@ require 'rubygems/doc_manager' class Gem::Server + include ERB::Util include Gem::UserInteraction - DOC_TEMPLATE = <<-'WEBPAGE' + SEARCH = <<-SEARCH + <form class="headerSearch" name="headerSearchForm" method="get" action="/rdoc"> + <div id="search" style="float:right"> + <span>Filter/Search</span> + <input id="q" type="text" style="width:10em" name="q"/> + <button type="submit" style="display:none" /> + </div> + </form> + SEARCH + + DOC_TEMPLATE = <<-'DOC_TEMPLATE' <?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" @@ -47,6 +59,7 @@ class Gem::Server </head> <body> <div id="fileHeader"> +<%= SEARCH %> <h1>RubyGems Documentation Index</h1> </div> <!-- banner header --> @@ -114,10 +127,10 @@ class Gem::Server </div> </body> </html> - WEBPAGE + DOC_TEMPLATE # CSS is copy & paste from rdoc-style.css, RDoc V1.0.1 - 20041108 - RDOC_CSS = <<-RDOCCSS + RDOC_CSS = <<-RDOC_CSS body { font-family: Verdana,Arial,Helvetica,sans-serif; font-size: 90%; @@ -325,7 +338,92 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; } .ruby-comment { color: #b22222; font-weight: bold; background: transparent; } .ruby-regexp { color: #ffa07a; background: transparent; } .ruby-value { color: #7fffd4; background: transparent; } - RDOCCSS + RDOC_CSS + + RDOC_NO_DOCUMENTATION = <<-'NO_DOC' +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Found documentation</title> + <link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" /> + </head> + <body> + <div id="fileHeader"> +<%= SEARCH %> + <h1>No documentation found</h1> + </div> + + <div id="bodyContent"> + <div id="contextContent"> + <div id="description"> + <p>No gems matched <%= h query.inspect %></p> + + <p> + Back to <a href="/">complete gem index</a> + </p> + + </div> + </div> + </div> + <div id="validator-badges"> + <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p> + </div> + </body> +</html> + NO_DOC + + RDOC_SEARCH_TEMPLATE = <<-'RDOC_SEARCH' +<?xml version="1.0" encoding="iso-8859-1"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>Found documentation</title> + <link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" /> + </head> + <body> + <div id="fileHeader"> +<%= SEARCH %> + <h1>Found documentation</h1> + </div> + <!-- banner header --> + + <div id="bodyContent"> + <div id="contextContent"> + <div id="description"> + <h1>Summary</h1> + <p><%=doc_items.length%> documentation topics found.</p> + <h1>Topics</h1> + + <dl> + <% doc_items.each do |doc_item| %> + <dt> + <b><%=doc_item[:name]%></b> + <a href="<%=doc_item[:url]%>">[rdoc]</a> + </dt> + <dd> + <%=doc_item[:summary]%> + <br/> + <br/> + </dd> + <% end %> + </dl> + + <p> + Back to <a href="/">complete gem index</a> + </p> + + </div> + </div> + </div> + <div id="validator-badges"> + <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p> + </div> + </body> +</html> + RDOC_SEARCH def self.run(options) new(options[:gemdir], options[:port], options[:daemon]).run @@ -533,6 +631,90 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; } res.body = result end + ## + # Can be used for quick navigation to the rdoc documentation. You can then + # define a search shortcut for your browser. E.g. in Firefox connect + # 'shortcut:rdoc' to http://localhost:8808/rdoc?q=%s template. Then you can + # directly open the ActionPack documentation by typing 'rdoc actionp'. If + # there are multiple hits for the search term, they are presented as a list + # with links. + # + # Search algorithm aims for an intuitive search: + # 1. first try to find the gems and documentation folders which name + # starts with the search term + # 2. search for entries, that *contain* the search term + # 3. show all the gems + # + # If there is only one search hit, user is immediately redirected to the + # documentation for the particular gem, otherwise a list with results is + # shown. + # + # === Additional trick - install documentation for ruby core + # + # Note: please adjust paths accordingly use for example 'locate yaml.rb' and + # 'gem environment' to identify directories, that are specific for your + # local installation + # + # 1. install ruby sources + # cd /usr/src + # sudo apt-get source ruby + # + # 2. generate documentation + # rdoc -o /usr/lib/ruby/gems/1.8/doc/core/rdoc \ + # /usr/lib/ruby/1.8 ruby1.8-1.8.7.72 + # + # By typing 'rdoc core' you can now access the core documentation + + def rdoc(req, res) + query = req.query['q'] + show_rdoc_for_pattern("#{query}*", res) && return + show_rdoc_for_pattern("*#{query}*", res) && return + + template = ERB.new RDOC_NO_DOCUMENTATION + + res['content-type'] = 'text/html' + res.body = template.result binding + end + + ## + # Returns true and prepares http response, if rdoc for the requested gem + # name pattern was found. + # + # The search is based on the file system content, not on the gems metadata. + # This allows additional documentation folders like 'core' for the ruby core + # documentation - just put it underneath the main doc folder. + + def show_rdoc_for_pattern(pattern, res) + found_gems = Dir.glob("#{@gem_dir}/doc/#{pattern}").select {|path| + File.exist? File.join(path, 'rdoc/index.html') + } + case found_gems.length + when 0 + return false + when 1 + new_path = File.basename(found_gems[0]) + res.status = 302 + res['Location'] = "/doc_root/#{new_path}/rdoc/index.html" + return true + else + doc_items = [] + found_gems.each do |file_name| + base_name = File.basename(file_name) + doc_items << { + :name => base_name, + :url => "/doc_root/#{base_name}/rdoc/index.html", + :summary => '' + } + end + + template = ERB.new(RDOC_SEARCH_TEMPLATE) + res['content-type'] = 'text/html' + result = template.result binding + res.body = result + return true + end + end + def run @server.listen nil, @port @@ -564,6 +746,8 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; } @server.mount_proc "/", method(:root) + @server.mount_proc "/rdoc", method(:rdoc) + paths = { "/gems" => "/cache/", "/doc_root" => "/doc/" } paths.each do |mount_point, mount_dir| @server.mount(mount_point, WEBrick::HTTPServlet::FileHandler, |