#!/usr/bin/env ruby DOC_TEMPLATE = <<-WEBPAGE RubyGems Documentation Index

RubyGems Documentation Index

Summary

There are %gem_count% gems installed:

START:specs IFNOT:is_last %name%, ENDIF:is_last IF:is_last %name%. ENDIF:is_last END:specs

Gems

START:specs
IF:first_name_entry ENDIF:first_name_entry %name% %version% IF:rdoc_installed [rdoc] ENDIF:rdoc_installed IFNOT:rdoc_installed [rdoc] ENDIF:rdoc_installed IF:homepage [www] ENDIF:homepage IFNOT:homepage [www] ENDIF:homepage IF:has_deps - depends on START:dependencies IFNOT:is_last %name%, ENDIF:is_last IF:is_last %name%. ENDIF:is_last END:dependencies ENDIF:has_deps
%summary% IF:executables
IF:only_one_executable Executable is ENDIF:only_one_executable IFNOT:only_one_executable Executables are ENDIF:only_one_executable START:executables IFNOT:is_last %executable%, ENDIF:is_last IF:is_last %executable%. ENDIF:is_last END:executables ENDIF:executables

END:specs

[Validate]

WEBPAGE # CSS is copy & paste from rdoc-style.css, RDoc V1.0.1 - 20041108 RDOC_CSS = <<-RDOCCSS body { font-family: Verdana,Arial,Helvetica,sans-serif; font-size: 90%; margin: 0; margin-left: 40px; padding: 0; background: white; } h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; } h1 { font-size: 150%; } h2,h3,h4 { margin-top: 1em; } a { background: #eef; color: #039; text-decoration: none; } a:hover { background: #039; color: #eef; } /* Override the base stylesheet's Anchor inside a table cell */ td > a { background: transparent; color: #039; text-decoration: none; } /* and inside a section title */ .section-title > a { background: transparent; color: #eee; text-decoration: none; } /* === Structural elements =================================== */ div#index { margin: 0; margin-left: -40px; padding: 0; font-size: 90%; } div#index a { margin-left: 0.7em; } div#index .section-bar { margin-left: 0px; padding-left: 0.7em; background: #ccc; font-size: small; } div#classHeader, div#fileHeader { width: auto; color: white; padding: 0.5em 1.5em 0.5em 1.5em; margin: 0; margin-left: -40px; border-bottom: 3px solid #006; } div#classHeader a, div#fileHeader a { background: inherit; color: white; } div#classHeader td, div#fileHeader td { background: inherit; color: white; } div#fileHeader { background: #057; } div#classHeader { background: #048; } .class-name-in-header { font-size: 180%; font-weight: bold; } div#bodyContent { padding: 0 1.5em 0 1.5em; } div#description { padding: 0.5em 1.5em; background: #efefef; border: 1px dotted #999; } div#description h1,h2,h3,h4,h5,h6 { color: #125;; background: transparent; } div#validator-badges { text-align: center; } div#validator-badges img { border: 0; } div#copyright { color: #333; background: #efefef; font: 0.75em sans-serif; margin-top: 5em; margin-bottom: 0; padding: 0.5em 2em; } /* === Classes =================================== */ table.header-table { color: white; font-size: small; } .type-note { font-size: small; color: #DEDEDE; } .xxsection-bar { background: #eee; color: #333; padding: 3px; } .section-bar { color: #333; border-bottom: 1px solid #999; margin-left: -20px; } .section-title { background: #79a; color: #eee; padding: 3px; margin-top: 2em; margin-left: -30px; border: 1px solid #999; } .top-aligned-row { vertical-align: top } .bottom-aligned-row { vertical-align: bottom } /* --- Context section classes ----------------------- */ .context-row { } .context-item-name { font-family: monospace; font-weight: bold; color: black; } .context-item-value { font-size: small; color: #448; } .context-item-desc { color: #333; padding-left: 2em; } /* --- Method classes -------------------------- */ .method-detail { background: #efefef; padding: 0; margin-top: 0.5em; margin-bottom: 1em; border: 1px dotted #ccc; } .method-heading { color: black; background: #ccc; border-bottom: 1px solid #666; padding: 0.2em 0.5em 0 0.5em; } .method-signature { color: black; background: inherit; } .method-name { font-weight: bold; } .method-args { font-style: italic; } .method-description { padding: 0 0.5em 0 0.5em; } /* --- Source code sections -------------------- */ a.source-toggle { font-size: 90%; } div.method-source-code { background: #262626; color: #ffdead; margin: 1em; padding: 0.5em; border: 1px dashed #999; overflow: hidden; } div.method-source-code pre { color: #ffdead; overflow: hidden; } /* --- Ruby keyword styles --------------------- */ .standalone-code { background: #221111; color: #ffdead; overflow: hidden; } .ruby-constant { color: #7fffd4; background: transparent; } .ruby-keyword { color: #00ffff; background: transparent; } .ruby-ivar { color: #eedd82; background: transparent; } .ruby-operator { color: #00ffee; background: transparent; } .ruby-identifier { color: #ffdead; background: transparent; } .ruby-node { color: #ffa07a; background: transparent; } .ruby-comment { color: #b22222; font-weight: bold; background: transparent; } .ruby-regexp { color: #ffa07a; background: transparent; } .ruby-value { color: #7fffd4; background: transparent; } RDOCCSS ## # gem_server and gem_server.cgi are equivalent programs that allow # users to serve gems for consumption by `gem --remote-install`. # # gem_server starts an HTTP server on the given port, and serves the folowing: # * "/" - Browsing of gem spec files for installed gems # * "/yaml" - Full yaml dump of metadata for installed gems # * "/gems" - Direct access to download the installable gems # # Usage: gem_server [-p portnum] [-d gem_path] # port_num:: The TCP port the HTTP server will bind to # gem_path:: # Root gem directory containing both "cache" and "specifications" # subdirectories. if __FILE__ == $0 require 'rubygems' Gem.manage_gems require 'webrick' require 'yaml' require 'optparse' require 'rdoc/template' Socket.do_not_reverse_lookup=true options = {} ARGV.options do |opts| opts.on_tail("--help", "show this message") {puts opts; exit} opts.on('-pPORT','--port=PORT', "Specify the port to listen on") { |options[:port]| } opts.on('-dGEMDIR','--dir=GEMDIR', "Specify the directory from which to serve Gems") { |options[:gemdir]| } opts.parse! end s = WEBrick::HTTPServer.new(:Port => options[:port] || 8808) s.mount_proc("/yaml") { |req, res| fn = File.join(options[:gemdir] || Gem.dir, "specifications") res['content-type'] = 'text/plain' res['date'] = File.stat(fn).mtime res.body << Gem::SourceIndex.from_installed_gems(fn).to_yaml } s.mount_proc("/rdoc-style.css") { |req, res| fn = File.join(options[:gemdir] || Gem.dir, "specifications") res['content-type'] = 'text/css' res['date'] = File.stat(fn).mtime res.body << RDOC_CSS } s.mount_proc("/") { |req, res| specs = [] specifications_dir = File.join(options[:gemdir] || Gem.dir, "specifications") total_file_count = 0 Gem::SourceIndex.from_installed_gems(specifications_dir).each do |path, spec| total_file_count += spec.files.size deps = spec.dependencies.collect { |dep| { "name" => dep.name, "version" => dep.version_requirements.to_s, } } deps = deps.sort_by { |dep| [dep["name"].downcase, dep["version"]] } deps.last["is_last"] = true unless deps.empty? # executables executables = spec.executables.sort.collect { |exec| {"executable" => exec} } executables = nil if executables.empty? executables.last["is_last"] = true if executables specs << { "authors" => spec.authors.sort.join(", "), "date" => spec.date.to_s, "dependencies" => deps, "doc_path" => ('/doc_root/' + spec.full_name + '/rdoc/index.html'), "executables" => executables, "only_one_executable" => (executables && executables.size==1), "full_name" => spec.full_name, "has_deps" => !deps.empty?, "homepage" => spec.homepage, "name" => spec.name, "rdoc_installed" => Gem::DocManager.new(spec).rdoc_installed?, "summary" => spec.summary, "version" => spec.version.to_s, } end specs = specs.sort_by { |spec| [spec["name"].downcase, spec["version"]] } specs.last["is_last"] = true # tag all specs with first_name_entry last_spec = nil specs.each do |spec| is_first = last_spec.nil? || (last_spec["name"].downcase != spec["name"].downcase) spec["first_name_entry"] = is_first last_spec = spec end # create page from template template = TemplatePage.new(DOC_TEMPLATE) res['content-type'] = 'text/html' template.write_html_on( res.body, { "gem_count" => specs.size.to_s, "specs" => specs, "total_file_count" => total_file_count.to_s, } ) } { "/gems" => "/cache/", "/doc_root" => "/doc/", }.each do |mount_point, mount_dir| s.mount( mount_point, WEBrick::HTTPServlet::FileHandler, File.join(options[:gemdir] || Gem.dir, mount_dir), true) end trap("INT") { s.shutdown; exit! } s.start end