[前][次][番号順一覧][スレッド一覧]

ruby-changes:11996

From: drbrain <ko1@a...>
Date: Wed, 10 Jun 2009 06:39:49 +0900 (JST)
Subject: [ruby-changes:11996] Ruby:r23659 (trunk): Update to RubyGems 1.3.4 r2223

drbrain	2009-06-10 06:38:59 +0900 (Wed, 10 Jun 2009)

  New Revision: 23659

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=23659

  Log:
    Update to RubyGems 1.3.4 r2223

  Added directories:
    trunk/test/rubygems/foo/
  Added files:
    trunk/lib/gauntlet_rubygems.rb
    trunk/lib/rubygems/commands/setup_command.rb
    trunk/lib/rubygems/package_task.rb
    trunk/lib/rubygems/text.rb
    trunk/test/rubygems/foo/discover.rb
    trunk/test/rubygems/rubygems_plugin.rb
    trunk/test/rubygems/test_gem_package_task.rb
  Modified files:
    trunk/ChangeLog
    trunk/bin/gem
    trunk/gem_prelude.rb
    trunk/lib/rbconfig/datadir.rb
    trunk/lib/rubygems/builder.rb
    trunk/lib/rubygems/command.rb
    trunk/lib/rubygems/command_manager.rb
    trunk/lib/rubygems/commands/check_command.rb
    trunk/lib/rubygems/commands/cleanup_command.rb
    trunk/lib/rubygems/commands/contents_command.rb
    trunk/lib/rubygems/commands/generate_index_command.rb
    trunk/lib/rubygems/commands/install_command.rb
    trunk/lib/rubygems/commands/query_command.rb
    trunk/lib/rubygems/commands/rdoc_command.rb
    trunk/lib/rubygems/commands/search_command.rb
    trunk/lib/rubygems/commands/server_command.rb
    trunk/lib/rubygems/commands/sources_command.rb
    trunk/lib/rubygems/commands/specification_command.rb
    trunk/lib/rubygems/commands/uninstall_command.rb
    trunk/lib/rubygems/commands/unpack_command.rb
    trunk/lib/rubygems/commands/update_command.rb
    trunk/lib/rubygems/commands/which_command.rb
    trunk/lib/rubygems/config_file.rb
    trunk/lib/rubygems/defaults.rb
    trunk/lib/rubygems/dependency.rb
    trunk/lib/rubygems/dependency_installer.rb
    trunk/lib/rubygems/dependency_list.rb
    trunk/lib/rubygems/doc_manager.rb
    trunk/lib/rubygems/exceptions.rb
    trunk/lib/rubygems/ext/builder.rb
    trunk/lib/rubygems/ext/configure_builder.rb
    trunk/lib/rubygems/ext/ext_conf_builder.rb
    trunk/lib/rubygems/ext/rake_builder.rb
    trunk/lib/rubygems/format.rb
    trunk/lib/rubygems/gem_openssl.rb
    trunk/lib/rubygems/gem_path_searcher.rb
    trunk/lib/rubygems/gem_runner.rb
    trunk/lib/rubygems/indexer.rb
    trunk/lib/rubygems/install_update_options.rb
    trunk/lib/rubygems/installer.rb
    trunk/lib/rubygems/local_remote_options.rb
    trunk/lib/rubygems/old_format.rb
    trunk/lib/rubygems/package/f_sync_dir.rb
    trunk/lib/rubygems/package/tar_header.rb
    trunk/lib/rubygems/package/tar_input.rb
    trunk/lib/rubygems/package/tar_output.rb
    trunk/lib/rubygems/package/tar_reader/entry.rb
    trunk/lib/rubygems/package/tar_reader.rb
    trunk/lib/rubygems/package/tar_writer.rb
    trunk/lib/rubygems/platform.rb
    trunk/lib/rubygems/remote_fetcher.rb
    trunk/lib/rubygems/require_paths_builder.rb
    trunk/lib/rubygems/requirement.rb
    trunk/lib/rubygems/rubygems_version.rb
    trunk/lib/rubygems/security.rb
    trunk/lib/rubygems/server.rb
    trunk/lib/rubygems/source_index.rb
    trunk/lib/rubygems/source_info_cache.rb
    trunk/lib/rubygems/source_info_cache_entry.rb
    trunk/lib/rubygems/spec_fetcher.rb
    trunk/lib/rubygems/specification.rb
    trunk/lib/rubygems/test_utilities.rb
    trunk/lib/rubygems/timer.rb
    trunk/lib/rubygems/uninstaller.rb
    trunk/lib/rubygems/user_interaction.rb
    trunk/lib/rubygems/validator.rb
    trunk/lib/rubygems/version.rb
    trunk/lib/rubygems/version_option.rb
    trunk/lib/rubygems.rb
    trunk/test/rubygems/gem_installer_test_case.rb
    trunk/test/rubygems/gem_package_tar_test_case.rb
    trunk/test/rubygems/gemutilities.rb
    trunk/test/rubygems/insure_session.rb
    trunk/test/rubygems/mockgemui.rb
    trunk/test/rubygems/simple_gem.rb
    trunk/test/rubygems/test_gem.rb
    trunk/test/rubygems/test_gem_command.rb
    trunk/test/rubygems/test_gem_command_manager.rb
    trunk/test/rubygems/test_gem_commands_cert_command.rb
    trunk/test/rubygems/test_gem_commands_contents_command.rb
    trunk/test/rubygems/test_gem_commands_environment_command.rb
    trunk/test/rubygems/test_gem_commands_generate_index_command.rb
    trunk/test/rubygems/test_gem_commands_install_command.rb
    trunk/test/rubygems/test_gem_commands_pristine_command.rb
    trunk/test/rubygems/test_gem_commands_query_command.rb
    trunk/test/rubygems/test_gem_commands_server_command.rb
    trunk/test/rubygems/test_gem_commands_sources_command.rb
    trunk/test/rubygems/test_gem_commands_specification_command.rb
    trunk/test/rubygems/test_gem_commands_uninstall_command.rb
    trunk/test/rubygems/test_gem_commands_unpack_command.rb
    trunk/test/rubygems/test_gem_commands_update_command.rb
    trunk/test/rubygems/test_gem_dependency.rb
    trunk/test/rubygems/test_gem_dependency_installer.rb
    trunk/test/rubygems/test_gem_dependency_list.rb
    trunk/test/rubygems/test_gem_doc_manager.rb
    trunk/test/rubygems/test_gem_ext_configure_builder.rb
    trunk/test/rubygems/test_gem_ext_ext_conf_builder.rb
    trunk/test/rubygems/test_gem_format.rb
    trunk/test/rubygems/test_gem_gem_path_searcher.rb
    trunk/test/rubygems/test_gem_gem_runner.rb
    trunk/test/rubygems/test_gem_indexer.rb
    trunk/test/rubygems/test_gem_install_update_options.rb
    trunk/test/rubygems/test_gem_installer.rb
    trunk/test/rubygems/test_gem_local_remote_options.rb
    trunk/test/rubygems/test_gem_package_tar_header.rb
    trunk/test/rubygems/test_gem_package_tar_input.rb
    trunk/test/rubygems/test_gem_package_tar_output.rb
    trunk/test/rubygems/test_gem_package_tar_writer.rb
    trunk/test/rubygems/test_gem_platform.rb
    trunk/test/rubygems/test_gem_remote_fetcher.rb
    trunk/test/rubygems/test_gem_server.rb
    trunk/test/rubygems/test_gem_source_index.rb
    trunk/test/rubygems/test_gem_source_info_cache.rb
    trunk/test/rubygems/test_gem_spec_fetcher.rb
    trunk/test/rubygems/test_gem_specification.rb
    trunk/test/rubygems/test_gem_uninstaller.rb
    trunk/test/rubygems/test_gem_version.rb
    trunk/test/rubygems/test_gem_version_option.rb
    trunk/test/rubygems/test_kernel.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 23658)
+++ ChangeLog	(revision 23659)
@@ -1,3 +1,7 @@
+Wed Jun 10 06:28:15 2009  Eric Hodel  <drbrain@s...>
+
+	* lib/rubygems*: Upgrade to RubyGems 1.3.4 r2223.
+
 Tue Jun  9 22:38:09 2009  Tadayoshi Funaba  <tadf@d...>
 
 	* lib/cmath.rb (log10): raised exception when the given number is
Index: gem_prelude.rb
===================================================================
--- gem_prelude.rb	(revision 23658)
+++ gem_prelude.rb	(revision 23659)
@@ -2,12 +2,15 @@
 # vim: filetype=ruby
 # THIS FILE WAS AUTOGENERATED, DO NOT EDIT
 
-# NOTICE: Ruby is during initialization here. 
-#   * Encoding.default_external does not reflects -E.
-#   * Should not expect Encoding.default_internal.
-#   * Locale encoding is available.
+# NOTICE: Ruby is during initialization here.
+# * Encoding.default_external does not reflects -E.
+# * Should not expect Encoding.default_internal.
+# * Locale encoding is available.
+
 if defined?(Gem) then
 
+  # :stopdoc:
+
   module Kernel
 
     def gem(gem_name, *version_requirements)
@@ -18,20 +21,17 @@
 
   module Gem
 
-    class LoadError < ::LoadError
-    end
-
     ConfigMap = {
-      :sitedir => RbConfig::CONFIG["sitedir"],
-      :ruby_version => RbConfig::CONFIG["ruby_version"],
-      :rubylibprefix => RbConfig::CONFIG["rubylibprefix"],
-      :libdir => RbConfig::CONFIG["libdir"],
-      :sitelibdir => RbConfig::CONFIG["sitelibdir"],
-      :arch => RbConfig::CONFIG["arch"],
-      :bindir => RbConfig::CONFIG["bindir"],
-      :EXEEXT => RbConfig::CONFIG["EXEEXT"],
-      :RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"],
-      :ruby_install_name => RbConfig::CONFIG["ruby_install_name"]
+      :EXEEXT            => RbConfig::CONFIG["EXEEXT"],
+      :RUBY_SO_NAME      => RbConfig::CONFIG["RUBY_SO_NAME"],
+      :arch              => RbConfig::CONFIG["arch"],
+      :bindir            => RbConfig::CONFIG["bindir"],
+      :libdir            => RbConfig::CONFIG["libdir"],
+      :ruby_install_name => RbConfig::CONFIG["ruby_install_name"],
+      :ruby_version      => RbConfig::CONFIG["ruby_version"],
+      :rubylibprefix     => RbConfig::CONFIG["rubylibprefix"],
+      :sitedir           => RbConfig::CONFIG["sitedir"],
+      :sitelibdir        => RbConfig::CONFIG["sitelibdir"],
     }
 
     def self.dir
@@ -67,24 +67,30 @@
     end
 
     def self.set_home(home)
+      home = home.gsub File::ALT_SEPARATOR, File::SEPARATOR if File::ALT_SEPARATOR
       @gem_home = home
-      ensure_gem_subdirectories(@gem_home)
     end
 
     def self.set_paths(gpaths)
       if gpaths
         @gem_path = gpaths.split(File::PATH_SEPARATOR)
+
+        if File::ALT_SEPARATOR then
+          @gem_path.map! do |path|
+            path.gsub File::ALT_SEPARATOR, File::SEPARATOR
+          end
+        end
+
         @gem_path << Gem.dir
       else
+        # TODO: should this be Gem.default_path instead?
         @gem_path = [Gem.dir]
       end
+
       @gem_path.uniq!
-      @gem_path.each do |gp| ensure_gem_subdirectories(gp) end
     end
 
-    def self.ensure_gem_subdirectories(path)
-    end
-
+    # begin rubygems/defaults
   
     @post_install_hooks   ||= []
     @post_uninstall_hooks ||= []
@@ -106,8 +112,13 @@
       if defined? RUBY_FRAMEWORK_VERSION then
         File.join File.dirname(ConfigMap[:sitedir]), 'Gems',
                   ConfigMap[:ruby_version]
+      # 1.9.2dev reverted to 1.8 style path
+      elsif RUBY_VERSION > '1.9' and RUBY_VERSION < '1.9.2' then
+        File.join(ConfigMap[:libdir], ConfigMap[:ruby_install_name], 'gems',
+                  ConfigMap[:ruby_version])
       else
-        ConfigMap[:sitelibdir].sub(%r'/site_ruby/(?=[^/]+)', '/gems/')
+        File.join(ConfigMap[:libdir], ruby_engine, 'gems',
+                  ConfigMap[:ruby_version])
       end
     end
   
@@ -123,15 +134,25 @@
     # Default gem load path
   
     def self.default_path
-      [user_dir, default_dir]
+      if File.exist?(Gem.user_home)
+        [user_dir, default_dir]
+      else
+        [default_dir]
+      end
     end
   
     ##
     # Deduce Ruby's --program-prefix and --program-suffix from its install name
   
     def self.default_exec_format
-      baseruby = ConfigMap[:BASERUBY] || 'ruby'
-      ConfigMap[:RUBY_INSTALL_NAME].sub(baseruby, '%s') rescue '%s'
+      exec_format = ConfigMap[:ruby_install_name].sub('ruby', '%s') rescue '%s'
+  
+      unless exec_format =~ /%s/ then
+        raise Gem::Exception,
+          "[BUG] invalid exec_format #{exec_format.inspect}, no %s"
+      end
+  
+      exec_format
     end
   
     ##
@@ -171,7 +192,9 @@
     end
   
   
+    # end rubygems/defaults
 
+    ##
     # Methods before this line will be removed when QuickLoader is replaced
     # with the real RubyGems
 
@@ -179,7 +202,7 @@
 
     begin
       verbose, debug = $VERBOSE, $DEBUG
-      $DEBUG = $VERBOSE = nil
+      $VERBOSE = $DEBUG = nil
 
       begin
         require 'rubygems/defaults/operating_system'
@@ -226,14 +249,14 @@
 
       def push_gem_version_on_load_path(gem_name, *version_requirements)
         if version_requirements.empty?
-          unless GemPaths.has_key?(gem_name)
-            raise Gem::LoadError.new("Could not find RubyGem #{gem_name} (>= 0)\n")
+          unless GemPaths.has_key?(gem_name) then
+            raise Gem::LoadError, "Could not find RubyGem #{gem_name} (>= 0)\n"
           end
 
           # highest version gems already active
           return false
         else
-          if version_requirements.length > 1
+          if version_requirements.length > 1 then
             QuickLoader.load_full_rubygems_library
             return gem(gem_name, *version_requirements)
           end
@@ -241,26 +264,24 @@
           requirement, version = version_requirements[0].split
           requirement.strip!
 
-          if loaded_version = GemVersions[gem_name]
+          if loaded_version = GemVersions[gem_name] then
             case requirement
-            when ">", ">="
-              if (loaded_version <=> Gem.calculate_integers_for_gem_version(version)) >= 0
-                return false
-              end
-            when "~>"
-              required_version = Gem.calculate_integers_for_gem_version(version)
-              if (loaded_version[0] == required_version[0])
-                return false
-              end
+            when ">", ">=" then
+              return false if
+                (loaded_version <=> Gem.integers_for(version)) >= 0
+            when "~>" then
+              required_version = Gem.integers_for version
+
+              return false if loaded_version.first == required_version.first
             end
           end
 
           QuickLoader.load_full_rubygems_library
-          gem(gem_name, *version_requirements)
+          gem gem_name, *version_requirements
         end
       end
 
-      def calculate_integers_for_gem_version(gem_version)
+      def integers_for(gem_version)
         numbers = gem_version.split(".").collect {|n| n.to_i}
         numbers.pop while numbers.last == 0
         numbers << 0 if numbers.empty?
@@ -270,16 +291,20 @@
       def push_all_highest_version_gems_on_load_path
         Gem.path.each do |path|
           gems_directory = File.join(path, "gems")
-          if File.exist?(gems_directory)
+
+          if File.exist?(gems_directory) then
             Dir.entries(gems_directory).each do |gem_directory_name|
               next if gem_directory_name == "." || gem_directory_name == ".."
+
               dash = gem_directory_name.rindex("-")
               next if dash.nil?
+
               gem_name = gem_directory_name[0...dash]
               current_version = GemVersions[gem_name]
-              new_version = calculate_integers_for_gem_version(gem_directory_name[dash+1..-1])
-              if current_version
-                if (current_version <=> new_version) == -1
+              new_version = integers_for(gem_directory_name[dash+1..-1])
+
+              if current_version then
+                if (current_version <=> new_version) == -1 then
                   GemVersions[gem_name] = new_version
                   GemPaths[gem_name] = File.join(gems_directory, gem_directory_name)
                 end
@@ -309,7 +334,7 @@
         # "tag" the first require_path inserted into the $LOAD_PATH to enable
         # indexing correctly with rubygems proper when it inserts an explicitly
         # gem version
-        unless require_paths.empty?
+        unless require_paths.empty? then
           require_paths.first.instance_variable_set(:@gem_prelude_index, true)
         end
         # gem directories must come after -I and ENV['RUBYLIB']
@@ -318,8 +343,9 @@
 
       def const_missing(constant)
         QuickLoader.load_full_rubygems_library
-        if Gem.const_defined?(constant)
-          Gem.const_get(constant)
+
+        if Gem.const_defined?(constant) then
+          Gem.const_get constant
         else
           super
         end
@@ -338,7 +364,7 @@
 
   begin
     Gem.push_all_highest_version_gems_on_load_path
-    $" << File.join(Gem::ConfigMap[:rubylibprefix], 
+    $" << File.join(Gem::ConfigMap[:rubylibprefix],
                     Gem::ConfigMap[:ruby_version], "rubygems.rb")
   rescue Exception => e
     puts "Error loading gem paths on load path in gem_prelude"
Index: lib/rubygems/user_interaction.rb
===================================================================
--- lib/rubygems/user_interaction.rb	(revision 23658)
+++ lib/rubygems/user_interaction.rb	(revision 23659)
@@ -4,357 +4,387 @@
 # See LICENSE.txt for permissions.
 #++
 
-module Gem
+##
+# Module that defines the default UserInteraction.  Any class including this
+# module will have access to the +ui+ method that returns the default UI.
 
+module Gem::DefaultUserInteraction
+
   ##
-  # Module that defines the default UserInteraction.  Any class including this
-  # module will have access to the +ui+ method that returns the default UI.
+  # The default UI is a class variable of the singleton class for this
+  # module.
 
-  module DefaultUserInteraction
+  @ui = nil
 
-    ##
-    # The default UI is a class variable of the singleton class for this
-    # module.
+  ##
+  # Return the default UI.
 
-    @ui = nil
+  def self.ui
+    @ui ||= Gem::ConsoleUI.new
+  end
 
-    ##
-    # Return the default UI.
+  ##
+  # Set the default UI.  If the default UI is never explicitly set, a simple
+  # console based UserInteraction will be used automatically.
 
-    def self.ui
-      @ui ||= Gem::ConsoleUI.new
-    end
+  def self.ui=(new_ui)
+    @ui = new_ui
+  end
 
-    ##
-    # Set the default UI.  If the default UI is never explicitly set, a simple
-    # console based UserInteraction will be used automatically.
+  ##
+  # Use +new_ui+ for the duration of +block+.
 
-    def self.ui=(new_ui)
-      @ui = new_ui
-    end
+  def self.use_ui(new_ui)
+    old_ui = @ui
+    @ui = new_ui
+    yield
+  ensure
+    @ui = old_ui
+  end
 
-    ##
-    # Use +new_ui+ for the duration of +block+.
+  ##
+  # See DefaultUserInteraction::ui
 
-    def self.use_ui(new_ui)
-      old_ui = @ui
-      @ui = new_ui
-      yield
-    ensure
-      @ui = old_ui
-    end
+  def ui
+    Gem::DefaultUserInteraction.ui
+  end
 
-    ##
-    # See DefaultUserInteraction::ui
+  ##
+  # See DefaultUserInteraction::ui=
 
-    def ui
-      DefaultUserInteraction.ui
-    end
+  def ui=(new_ui)
+    Gem::DefaultUserInteraction.ui = new_ui
+  end
 
-    ##
-    # See DefaultUserInteraction::ui=
+  ##
+  # See DefaultUserInteraction::use_ui
 
-    def ui=(new_ui)
-      DefaultUserInteraction.ui = new_ui
-    end
+  def use_ui(new_ui, &block)
+    Gem::DefaultUserInteraction.use_ui(new_ui, &block)
+  end
 
-    ##
-    # See DefaultUserInteraction::use_ui
+end
 
-    def use_ui(new_ui, &block)
-      DefaultUserInteraction.use_ui(new_ui, &block)
-    end
+##
+# Make the default UI accessable without the "ui." prefix.  Classes
+# including this module may use the interaction methods on the default UI
+# directly.  Classes may also reference the ui and ui= methods.
+#
+# Example:
+#
+#   class X
+#     include Gem::UserInteraction
+#
+#     def get_answer
+#       n = ask("What is the meaning of life?")
+#     end
+#   end
 
-  end
+module Gem::UserInteraction
 
+  include Gem::DefaultUserInteraction
+
   ##
-  # Make the default UI accessable without the "ui." prefix.  Classes
-  # including this module may use the interaction methods on the default UI
-  # directly.  Classes may also reference the ui and ui= methods.
-  #
-  # Example:
-  #
-  #   class X
-  #     include Gem::UserInteraction
-  #
-  #     def get_answer
-  #       n = ask("What is the meaning of life?")
-  #     end
-  #   end
+  # :method: alert
 
-  module UserInteraction
+  ##
+  # :method: alert_error
 
-    include DefaultUserInteraction
+  ##
+  # :method: alert_warning
 
-    [:alert,
-     :alert_error,
-     :alert_warning,
-     :ask,
-     :ask_yes_no,
-     :choose_from_list,
-     :say,
-     :terminate_interaction ].each do |methname|
-      class_eval %{
-        def #{methname}(*args)
-          ui.#{methname}(*args)
-        end
-      }, __FILE__, __LINE__
-    end
-  end
+  ##
+  # :method: ask
 
   ##
-  # StreamUI implements a simple stream based user interface.
+  # :method: ask_yes_no
 
-  class StreamUI
+  ##
+  # :method: choose_from_list
 
-    attr_reader :ins, :outs, :errs
+  ##
+  # :method: say
 
-    def initialize(in_stream, out_stream, err_stream=STDERR)
-      @ins = in_stream
-      @outs = out_stream
-      @errs = err_stream
-    end
+  ##
+  # :method: terminate_interaction
 
-    ##
-    # Choose from a list of options.  +question+ is a prompt displayed above
-    # the list.  +list+ is a list of option strings.  Returns the pair
-    # [option_name, option_index].
+  [:alert,
+   :alert_error,
+   :alert_warning,
+   :ask,
+   :ask_yes_no,
+   :choose_from_list,
+   :say,
+   :terminate_interaction ].each do |methname|
+    class_eval %{
+      def #{methname}(*args)
+        ui.#{methname}(*args)
+      end
+    }, __FILE__, __LINE__
+  end
+end
 
-    def choose_from_list(question, list)
-      @outs.puts question
+##
+# Gem::StreamUI implements a simple stream based user interface.
 
-      list.each_with_index do |item, index|
-        @outs.puts " #{index+1}. #{item}"
-      end
+class Gem::StreamUI
 
-      @outs.print "> "
-      @outs.flush
+  attr_reader :ins, :outs, :errs
 
-      result = @ins.gets
+  def initialize(in_stream, out_stream, err_stream=STDERR)
+    @ins = in_stream
+    @outs = out_stream
+    @errs = err_stream
+  end
 
-      return nil, nil unless result
+  ##
+  # Choose from a list of options.  +question+ is a prompt displayed above
+  # the list.  +list+ is a list of option strings.  Returns the pair
+  # [option_name, option_index].
 
-      result = result.strip.to_i - 1
-      return list[result], result
+  def choose_from_list(question, list)
+    @outs.puts question
+
+    list.each_with_index do |item, index|
+      @outs.puts " #{index+1}. #{item}"
     end
 
-    ##
-    # Ask a question.  Returns a true for yes, false for no.  If not connected
-    # to a tty, raises an exception if default is nil, otherwise returns
-    # default.
+    @outs.print "> "
+    @outs.flush
 
-    def ask_yes_no(question, default=nil)
-      unless @ins.tty? then
-        if default.nil? then
-          raise Gem::OperationNotSupportedError,
-                "Not connected to a tty and no default specified"
-        else
-          return default
-        end
+    result = @ins.gets
+
+    return nil, nil unless result
+
+    result = result.strip.to_i - 1
+    return list[result], result
+  end
+
+  ##
+  # Ask a question.  Returns a true for yes, false for no.  If not connected
+  # to a tty, raises an exception if default is nil, otherwise returns
+  # default.
+
+  def ask_yes_no(question, default=nil)
+    unless @ins.tty? then
+      if default.nil? then
+        raise Gem::OperationNotSupportedError,
+              "Not connected to a tty and no default specified"
+      else
+        return default
       end
+    end
 
-      qstr = case default
-             when nil
-               'yn'
-             when true
-               'Yn'
-             else
-               'yN'
-             end
+    qstr = case default
+           when nil
+             'yn'
+           when true
+             'Yn'
+           else
+             'yN'
+           end
 
-      result = nil
+    result = nil
 
-      while result.nil?
-        result = ask("#{question} [#{qstr}]")
-        result = case result
-        when /^[Yy].*/
-          true
-        when /^[Nn].*/
-          false
-        when /^$/
-          default
-        else
-          nil
-        end
+    while result.nil?
+      result = ask("#{question} [#{qstr}]")
+      result = case result
+      when /^[Yy].*/
+        true
+      when /^[Nn].*/
+        false
+      when /^$/
+        default
+      else
+        nil
       end
-
-      return result
     end
 
-    ##
-    # Ask a question.  Returns an answer if connected to a tty, nil otherwise.
+    return result
+  end
 
-    def ask(question)
-      return nil if not @ins.tty?
+  ##
+  # Ask a question.  Returns an answer if connected to a tty, nil otherwise.
 
-      @outs.print(question + "  ")
-      @outs.flush
+  def ask(question)
+    return nil if not @ins.tty?
 
-      result = @ins.gets
-      result.chomp! if result
-      result
-    end
+    @outs.print(question + "  ")
+    @outs.flush
 
-    ##
-    # Display a statement.
+    result = @ins.gets
+    result.chomp! if result
+    result
+  end
 
-    def say(statement="")
-      @outs.puts statement
-    end
+  ##
+  # Display a statement.
 
-    ##
-    # Display an informational alert.  Will ask +question+ if it is not nil.
+  def say(statement="")
+    @outs.puts statement
+  end
 
-    def alert(statement, question=nil)
-      @outs.puts "INFO:  #{statement}"
-      ask(question) if question
-    end
+  ##
+  # Display an informational alert.  Will ask +question+ if it is not nil.
 
-    ##
-    # Display a warning in a location expected to get error messages.  Will
-    # ask +question+ if it is not nil.
+  def alert(statement, question=nil)
+    @outs.puts "INFO:  #{statement}"
+    ask(question) if question
+  end
 
-    def alert_warning(statement, question=nil)
-      @errs.puts "WARNING:  #{statement}"
-      ask(question) if question
-    end
+  ##
+  # Display a warning in a location expected to get error messages.  Will
+  # ask +question+ if it is not nil.
 
-    ##
-    # Display an error message in a location expected to get error messages.
-    # Will ask +question+ if it is not nil.
+  def alert_warning(statement, question=nil)
+    @errs.puts "WARNING:  #{statement}"
+    ask(question) if question
+  end
 
-    def alert_error(statement, question=nil)
-      @errs.puts "ERROR:  #{statement}"
-      ask(question) if question
-    end
+  ##
+  # Display an error message in a location expected to get error messages.
+  # Will ask +question+ if it is not nil.
 
-    ##
-    # Terminate the application with exit code +status+, running any exit
-    # handlers that might have been defined.
+  def alert_error(statement, question=nil)
+    @errs.puts "ERROR:  #{statement}"
+    ask(question) if question
+  end
 
-    def terminate_interaction(status = 0)
-      raise Gem::SystemExitException, status
-    end
+  ##
+  # Display a debug message on the same location as error messages.
 
-    ##
-    # Return a progress reporter object chosen from the current verbosity.
+  def debug(statement)
+    @errs.puts statement
+  end
 
-    def progress_reporter(*args)
-      case Gem.configuration.verbose
-      when nil, false
-        SilentProgressReporter.new(@outs, *args)
-      when true
-        SimpleProgressReporter.new(@outs, *args)
-      else
-        VerboseProgressReporter.new(@outs, *args)
-      end
-    end
+  ##
+  # Terminate the application with exit code +status+, running any exit
+  # handlers that might have been defined.
 
-    ##
-    # An absolutely silent progress reporter.
+  def terminate_interaction(status = 0)
+    raise Gem::SystemExitException, status
+  end
 
-    class SilentProgressReporter
-      attr_reader :count
+  ##
+  # Return a progress reporter object chosen from the current verbosity.
 
-      def initialize(out_stream, size, initial_message, terminal_message = nil)
-      end
+  def progress_reporter(*args)
+    case Gem.configuration.verbose
+    when nil, false
+      SilentProgressReporter.new(@outs, *args)
+    when true
+      SimpleProgressReporter.new(@outs, *args)
+    else
+      VerboseProgressReporter.new(@outs, *args)
+    end
+  end
 
-      def updated(message)
-      end
+  ##
+  # An absolutely silent progress reporter.
 
-      def done
-      end
+  class SilentProgressReporter
+    attr_reader :count
+
+    def initialize(out_stream, size, initial_message, terminal_message = nil)
     end
 
-    ##
-    # A basic dotted progress reporter.
+    def updated(message)
+    end
 
-    class SimpleProgressReporter
-      include DefaultUserInteraction
+    def done
+    end
+  end
 
-      attr_reader :count
+  ##
+  # A basic dotted progress reporter.
 
-      def initialize(out_stream, size, initial_message,
-                     terminal_message = "complete")
-        @out = out_stream
-        @total = size
-        @count = 0
-        @terminal_message = terminal_message
+  class SimpleProgressReporter
 
-        @out.puts initial_message
-      end
+    include Gem::DefaultUserInteraction
 
-      ##
-      # Prints out a dot and ignores +message+.
+    attr_reader :count
 
-      def updated(message)
-        @count += 1
-        @out.print "."
-        @out.flush
-      end
+    def initialize(out_stream, size, initial_message,
+                   terminal_message = "complete")
+      @out = out_stream
+      @total = size
+      @count = 0
+      @terminal_message = terminal_message
 
-      ##
-      # Prints out the terminal message.
+      @out.puts initial_message
+    end
 
-      def done
-        @out.puts "\n#{@terminal_message}"
-      end
+    ##
+    # Prints out a dot and ignores +message+.
 
+    def updated(message)
+      @count += 1
+      @out.print "."
+      @out.flush
     end
 
     ##
-    # A progress reporter that prints out messages about the current progress.
+    # Prints out the terminal message.
 
-    class VerboseProgressReporter
-      include DefaultUserInteraction
+    def done
+      @out.puts "\n#{@terminal_message}"
+    end
 
-      attr_reader :count
+  end
 
-      def initialize(out_stream, size, initial_message,
-                     terminal_message = 'complete')
-        @out = out_stream
-        @total = size
-        @count = 0
-        @terminal_message = terminal_message
+  ##
+  # A progress reporter that prints out messages about the current progress.
 
-        @out.puts initial_message
-      end
+  class VerboseProgressReporter
 
-      ##
-      # Prints out the position relative to the total and the +message+.
+    include Gem::DefaultUserInteraction
 
-      def updated(message)
-        @count += 1
-        @out.puts "#{@count}/#{@total}: #{message}"
-      end
+    attr_reader :count
 
-      ##
-      # Prints out the terminal message.
+    def initialize(out_stream, size, initial_message,
+                   terminal_message = 'complete')
+      @out = out_stream
+      @total = size
+      @count = 0
+      @terminal_message = terminal_message
 
-      def done
-        @out.puts @terminal_message
-      end
+      @out.puts initial_message
     end
-  end
 
-  ##
-  # Subclass of StreamUI that instantiates the user interaction using STDIN,
-  # STDOUT, and STDERR.
+    ##
+    # Prints out the position relative to the total and the +message+.
 
-  class ConsoleUI < StreamUI
-    def initialize
-      super(STDIN, STDOUT, STDERR)
+    def updated(message)
+      @count += 1
+      @out.puts "#{@count}/#{@total}: #{message}"
     end
-  end
 
-  ##
-  # SilentUI is a UI choice that is absolutely silent.
+    ##
+    # Prints out the terminal message.
 
-  class SilentUI
-    def method_missing(sym, *args, &block)
-      self
+    def done
+      @out.puts @terminal_message
     end
   end
 
 end
 
+##
+# Subclass of StreamUI that instantiates the user interaction using STDIN,
+# STDOUT, and STDERR.
+
+class Gem::ConsoleUI < Gem::StreamUI
+  def initialize
+    super STDIN, STDOUT, STDERR
+  end
+end
+
+##
+# SilentUI is a UI choice that is absolutely silent.
+
+class Gem::SilentUI
+  def method_missing(sym, *args, &block)
+    self
+  end
+end
+
Index: lib/rubygems/command.rb
===================================================================
--- lib/rubygems/command.rb	(revision 23658)
+++ lib/rubygems/command.rb	(revision 23659)
@@ -5,402 +5,507 @@
 #++
 
 require 'optparse'
-
 require 'rubygems/user_interaction'
 
-module Gem
+##
+# Base class for all Gem commands.  When creating a new gem command, define
+# #new, #execute, #arguments, #defaults_str, #description and #usage
+# (as appropriate).  See the above mentioned methods for details.
+#
+# A very good example to look at is Gem::Commands::ContentsCommand
 
-  # Base class for all Gem commands.  When creating a new gem command, define
-  # #arguments, #defaults_str, #description and #usage (as appropriate).
-  class Command
+class Gem::Command
 
-    include UserInteraction
+  include Gem::UserInteraction
 
-    # The name of the command.
-    attr_reader :command
+  ##
+  # The name of the command.
 
-    # The options for the command.
-    attr_reader :options
+  attr_reader :command
 
-    # The default options for the command.
-    attr_accessor :defaults
+  ##
+  # The options for the command.
 
-    # The name of the command for command-line invocation.
-    attr_accessor :program_name
+  attr_reader :options
 
-    # A short description of the command.
-    attr_accessor :summary
+  ##
+  # The default options for the command.
 
-    # Initializes a generic gem command named +command+.  +summary+ is a short
-    # description displayed in `gem help commands`.  +defaults+ are the
-    # default options.  Defaults should be mirrored in #defaults_str, unless
-    # there are none.
-    #
-    # Use add_option to add command-line switches.
-    def initialize(command, summary=nil, defaults={})
-      @command = command
-      @summary = summary
-      @program_name = "gem #{command}"
-      @defaults = defaults
-      @options = defaults.dup
-      @option_groups = Hash.new { |h,k| h[k] = [] }
-      @parser = nil
-      @when_invoked = nil
-    end
+  attr_accessor :defaults
 
-    # True if +long+ begins with the characters from +short+.
-    def begins?(long, short)
-      return false if short.nil?
-      long[0, short.length] == short
-    end
+  ##
+  # The name of the command for command-line invocation.
 
-    # Override to provide command handling.
-    def execute
-      fail "Generic command has no actions"
-    end
+  attr_accessor :program_name
 
-    # Get all gem names from the command line.
-    def get_all_gem_names
-      args = options[:args]
+  ##
+  # A short description of the command.
 
-      if args.nil? or args.empty? then
-        raise Gem::CommandLineError,
-              "Please specify at least one gem name (e.g. gem build GEMNAME)"
-      end
+  attr_accessor :summary
 
-      gem_names = args.select { |arg| arg !~ /^-/ }
-    end
+  ##
+  # Arguments used when building gems
 
-    # Get the single gem name from the command line.  Fail if there is no gem
-    # name or if there is more than one gem name given.
-    def get_one_gem_name
-      args = options[:args]
+  def self.build_args
+    @build_args ||= []
+  end
+  
+  def self.build_args=(value)
+    @build_args = value
+  end
 
-      if args.nil? or args.empty? then
-        raise Gem::CommandLineError,
-             "Please specify a gem name on the command line (e.g. gem build GEMNAME)"
-      end
+  def self.common_options
+    @common_options ||= []
+  end
 
-      if args.size > 1 then
-        raise Gem::CommandLineError,
-              "Too many gem names (#{args.join(', ')}); please specify only one"
-      end
+  def self.add_common_option(*args, &handler)
+    Gem::Command.common_options << [args, handler]
+  end
 
-      args.first
-    end
+  def self.extra_args
+    @extra_args ||= []
+  end
 
-    # Get a single optional argument from the command line.  If more than one
-    # argument is given, return only the first. Return nil if none are given.
-    def get_one_optional_argument
-      args = options[:args] || []
-      args.first
+  def self.extra_args=(value)
+    case value
+    when Array
+      @extra_args = value
+    when String
+      @extra_args = value.split
     end
+  end
 
-    # Override to provide details of the arguments a command takes.
-    # It should return a left-justified string, one argument per line.
-    def arguments
-      ""
-    end
+  ##
+  # Return an array of extra arguments for the command.  The extra arguments
+  # come from the gem configuration file read at program startup.
 
-    # Override to display the default values of the command
-    # options. (similar to +arguments+, but displays the default
-    # values).
-    def defaults_str
-      ""
-    end
+  def self.specific_extra_args(cmd)
+    specific_extra_args_hash[cmd]
+  end
 
-    # Override to display a longer description of what this command does.
-    def description
-      nil
-    end
+  ##
+  # Add a list of extra arguments for the given command.  +args+ may be an
+  # array or a string to be split on white space.
 
-    # Override to display the usage for an individual gem command.
-    def usage
-      program_name
-    end
+  def self.add_specific_extra_args(cmd,args)
+    args = args.split(/\s+/) if args.kind_of? String
+    specific_extra_args_hash[cmd] = args
+  end
 
-    # Display the help message for the command.
-    def show_help
-      parser.program_name = usage
-      say parser
-    end
+  ##
+  # Accessor for the specific extra args hash (self initializing).
 
-    # Invoke the command with the given list of arguments.
-    def invoke(*args)
-      handle_options(args)
-      if options[:help]
-        show_help
-      elsif @when_invoked
-        @when_invoked.call(options)
-      else
-        execute
-      end
+  def self.specific_extra_args_hash
+    @specific_extra_args_hash ||= Hash.new do |h,k|
+      h[k] = Array.new
     end
+  end
 
-    # Call the given block when invoked.
-    #
-    # Normal command invocations just executes the +execute+ method of
-    # the command.  Specifying an invocation block allows the test
-    # methods to override the normal action of a command to determine
-    # that it has been invoked correctly.
-    def when_invoked(&block)
-      @when_invoked = block
-    end
+  ##
+  # Initializes a generic gem command named +command+.  +summary+ is a short
+  # description displayed in `gem help commands`.  +defaults+ are the default
+  # options.  Defaults should be mirrored in #defaults_str, unless there are
+  # none.
+  #
+  # When defining a new command subclass, use add_option to add command-line
+  # switches.
+  #
+  # Unhandled arguments (gem names, files, etc.) are left in
+  # <tt>options[:args]</tt>.
 
-    # Add a command-line option and handler to the command.
-    #
-    # See OptionParser#make_switch for an explanation of +opts+.
-    #
-    # +handler+ will be called with two values, the value of the argument and
-    # the options hash.
-    def add_option(*opts, &handler) # :yields: value, options
-      group_name = Symbol === opts.first ? opts.shift : :options
+  def initialize(command, summary=nil, defaults={})
+    @command = command
+    @summary = summary
+    @program_name = "gem #{command}"
+    @defaults = defaults
+    @options = defaults.dup
+    @option_groups = Hash.new { |h,k| h[k] = [] }
+    @parser = nil
+    @when_invoked = nil
+  end
 
-      @option_groups[group_name] << [opts, handler]
-    end
+  ##
+  # True if +long+ begins with the characters from +short+.
 
-    # Remove previously defined command-line argument +name+.
-    def remove_option(name)
-      @option_groups.each do |_, option_list|
-        option_list.reject! { |args, _| args.any? { |x| x =~ /^#{name}/ } }
-      end
-    end
+  def begins?(long, short)
+    return false if short.nil?
+    long[0, short.length] == short
+  end
 
-    # Merge a set of command options with the set of default options
-    # (without modifying the default option hash).
-    def merge_options(new_options)
-      @options = @defaults.clone
-      new_options.each do |k,v| @options[k] = v end
-    end
+  ##
+  # Override to provide command handling.
+  #
+  # #options will be filled in with your parsed options, unparsed options will
+  # be left in <tt>options[:args]</tt>.
+  #
+  # See also: #get_all_gem_names, #get_one_gem_name,
+  # #get_one_optional_argument
 
-    # True if the command handles the given argument list.
-    def handles?(args)
-      begin
-        parser.parse!(args.dup)
-        return true
-      rescue
-        return false
-      end
+  def execute
+    raise Gem::Exception, "generic command has no actions"
+  end
+
+  ##
+  # Get all gem names from the command line.
+
+  def get_all_gem_names
+    args = options[:args]
+
+    if args.nil? or args.empty? then
+      raise Gem::CommandLineError,
+            "Please specify at least one gem name (e.g. gem build GEMNAME)"
     end
 
-    # Handle the given list of arguments by parsing them and recording
-    # the results.
-    def handle_options(args)
-      args = add_extra_args(args)
-      @options = @defaults.clone
-      parser.parse!(args)
-      @options[:args] = args
+    gem_names = args.select { |arg| arg !~ /^-/ }
+  end
+
+  ##
+  # Get the single gem name from the command line.  Fail if there is no gem
+  # name or if there is more than one gem name given.
+
+  def get_one_gem_name
+    args = options[:args]
+
+    if args.nil? or args.empty? then
+      raise Gem::CommandLineError,
+            "Please specify a gem name on the command line (e.g. gem build GEMNAME)"
     end
 
-    def add_extra_args(args)
-      result = []
-      s_extra = Command.specific_extra_args(@command)
-      extra = Command.extra_args + s_extra
-      while ! extra.empty?
-        ex = []
-        ex << extra.shift
-        ex << extra.shift if extra.first.to_s =~ /^[^-]/
-        result << ex if handles?(ex)
-      end
-      result.flatten!
-      result.concat(args)
-      result
+    if args.size > 1 then
+      raise Gem::CommandLineError,
+            "Too many gem names (#{args.join(', ')}); please specify only one"
     end
 
-    private
+    args.first
+  end
 
-    # Create on demand parser.
-    def parser
-      create_option_parser if @parser.nil?
-      @parser
-    end
+  ##
+  # Get a single optional argument from the command line.  If more than one
+  # argument is given, return only the first. Return nil if none are given.
 
-    def create_option_parser
-      @parser = OptionParser.new
+  def get_one_optional_argument
+    args = options[:args] || []
+    args.first
+  end
 
-      @parser.separator("")
-      regular_options = @option_groups.delete :options
+  ##
+  # Override to provide details of the arguments a command takes.  It should
+  # return a left-justified string, one argument per line.
+  #
+  # For example:
+  #
+  #   def usage
+  #     "#{program_name} FILE [FILE ...]"
+  #   end
+  #   
+  #   def arguments
+  #     "FILE          name of file to find"
+  #   end
 
-      configure_options "", regular_options
+  def arguments
+    ""
+  end
 
-      @option_groups.sort_by { |n,_| n.to_s }.each do |group_name, option_list|
-        configure_options group_name, option_list
-      end
+  ##
+  # Override to display the default values of the command options. (similar to
+  # +arguments+, but displays the default values).
+  #
+  # For example:
+  #
+  #   def defaults_str
+  #     --no-gems-first --no-all
+  #   end
 
-      configure_options "Common", Command.common_options
+  def defaults_str
+    ""
+  end
 
-      @parser.separator("")
-      unless arguments.empty?
-        @parser.separator("  Arguments:")
-        arguments.split(/\n/).each do |arg_desc|
-          @parser.separator("    #{arg_desc}")
-        end
-        @parser.separator("")
-      end
+  ##
+  # Override to display a longer description of what this command does.
 
-      @parser.separator("  Summary:")
-      wrap(@summary, 80 - 4).split("\n").each do |line|
-        @parser.separator("    #{line.strip}")
-      end
+  def description
+    nil
+  end
 
-      if description then
-        formatted = description.split("\n\n").map do |chunk|
-          wrap(chunk, 80 - 4)
-        end.join("\n")
+  ##
+  # Override to display the usage for an individual gem command.
+  #
+  # The text "[options]" is automatically appended to the usage text.
 
-        @parser.separator ""
-        @parser.separator "  Description:"
-        formatted.split("\n").each do |line|
-          @parser.separator "    #{line.rstrip}"
-        end
-      end
+  def usage
+    program_name
+  end
 
-      unless defaults_str.empty?
-        @parser.separator("")
-        @parser.separator("  Defaults:")
-        defaults_str.split(/\n/).each do |line|
-          @parser.separator("    #{line}")
-        end
-      end
+  ##
+  # Display the help message for the command.
+
+  def show_help
+    parser.program_name = usage
+    say parser
+  end
+
+  ##
+  # Invoke the command with the given list of arguments.
+
+  def invoke(*args)
+    handle_options(args)
+    if options[:help]
+      show_help
+    elsif @when_invoked
+      @when_invoked.call(options)
+    else
+      execute
     end
+  end
 
-    def configure_options(header, option_list)
-      return if option_list.nil? or option_list.empty?
+  ##
+  # Call the given block when invoked.
+  #
+  # Normal command invocations just executes the +execute+ method of the
+  # command.  Specifying an invocation block allows the test methods to
+  # override the normal action of a command to determine that it has been
+  # invoked correctly.
 
-      header = header.to_s.empty? ? '' : "#{header} "
-      @parser.separator "  #{header}Options:"
+  def when_invoked(&block)
+    @when_invoked = block
+  end
 
-      option_list.each do |args, handler|
-        dashes = args.select { |arg| arg =~ /^-/ }
-        @parser.on(*args) do |value|
-          handler.call(value, @options)
-        end
-      end
+  ##
+  # Add a command-line option and handler to the command.
+  #
+  # See OptionParser#make_switch for an explanation of +opts+.
+  #
+  # +handler+ will be called with two values, the value of the argument and
+  # the options hash.
+  #
+  # If the first argument of add_option is a Symbol, it's used to group
+  # options in output.  See `gem help list` for an example.
 
-      @parser.separator ''
+  def add_option(*opts, &handler) # :yields: value, options
+    group_name = Symbol === opts.first ? opts.shift : :options
+
+    @option_groups[group_name] << [opts, handler]
+  end
+
+  ##
+  # Remove previously defined command-line argument +name+.
+
+  def remove_option(name)
+    @option_groups.each do |_, option_list|
+      option_list.reject! { |args, _| args.any? { |x| x =~ /^#{name}/ } }
     end
+  end
 
-    # Wraps +text+ to +width+
-    def wrap(text, width)
-      text.gsub(/(.{1,#{width}})( +|$\n?)|(.{1,#{width}})/, "\\1\\3\n")
+  ##
+  # Merge a set of command options with the set of default options (without
+  # modifying the default option hash).
+
+  def merge_options(new_options)
+    @options = @defaults.clone
+    new_options.each do |k,v| @options[k] = v end
+  end
+
+  ##
+  # True if the command handles the given argument list.
+
+  def handles?(args)
+    begin
+      parser.parse!(args.dup)
+      return true
+    rescue
+      return false
     end
+  end
 
-    ##################################################################
-    # Class methods for Command.
-    class << self
-      def common_options
-        @common_options ||= []
-      end
+  ##
+  # Handle the given list of arguments by parsing them and recording the
+  # results.
 
-      def add_common_option(*args, &handler)
-        Gem::Command.common_options << [args, handler]
-      end
+  def handle_options(args)
+    args = add_extra_args(args)
+    @options = @defaults.clone
+    parser.parse!(args)
+    @options[:args] = args
+  end
 
-      def extra_args
-        @extra_args ||= []
-      end
+  ##
+  # Adds extra args from ~/.gemrc
 
-      def extra_args=(value)
-        case value
-        when Array
-          @extra_args = value
-        when String
-          @extra_args = value.split
-        end
-      end
+  def add_extra_args(args)
+    result = []
 
-      # Return an array of extra arguments for the command.  The extra
-      # arguments come from the gem configuration file read at program
-      # startup.
-      def specific_extra_args(cmd)
-        specific_extra_args_hash[cmd]
-      end
+    s_extra = Gem::Command.specific_extra_args(@command)
+    extra = Gem::Command.extra_args + s_extra
 
-      # Add a list of extra arguments for the given command.  +args+
-      # may be an array or a string to be split on white space.
-      def add_specific_extra_args(cmd,args)
-        args = args.split(/\s+/) if args.kind_of? String
-        specific_extra_args_hash[cmd] = args
-      end
-
-      # Accessor for the specific extra args hash (self initializing).
-      def specific_extra_args_hash
-        @specific_extra_args_hash ||= Hash.new do |h,k|
-          h[k] = Array.new
-        end
-      end
+    until extra.empty? do
+      ex = []
+      ex << extra.shift
+      ex << extra.shift if extra.first.to_s =~ /^[^-]/
+      result << ex if handles?(ex)
     end
 
-    # ----------------------------------------------------------------
-    # Add the options common to all commands.
+    result.flatten!
+    result.concat(args)
+    result
+  end
 
-    add_common_option('-h', '--help',
-      'Get help on this command') do
-      |value, options|
-      options[:help] = true
+  private
+
+  ##
+  # Create on demand parser.
+
+  def parser
+    create_option_parser if @parser.nil?
+    @parser
+  end
+
+  def create_option_parser
+    @parser = OptionParser.new
+
+    @parser.separator("")
+    regular_options = @option_groups.delete :options
+
+    configure_options "", regular_options
+
+    @option_groups.sort_by { |n,_| n.to_s }.each do |group_name, option_list|
+      configure_options group_name, option_list
     end
 
-    add_common_option('-V', '--[no-]verbose',
-                      'Set the verbose level of output') do |value, options|
-      # Set us to "really verbose" so the progress meter works
-      if Gem.configuration.verbose and value then
-        Gem.configuration.verbose = 1
-      else
-        Gem.configuration.verbose = value
+    configure_options "Common", Gem::Command.common_options
+
+    @parser.separator("")
+    unless arguments.empty?
+      @parser.separator("  Arguments:")
+      arguments.split(/\n/).each do |arg_desc|
+        @parser.separator("    #{arg_desc}")
       end
+      @parser.separator("")
     end
 
-    add_common_option('-q', '--quiet', 'Silence commands') do |value, options|
-      Gem.configuration.verbose = false
+    @parser.separator("  Summary:")
+    wrap(@summary, 80 - 4).split("\n").each do |line|
+      @parser.separator("    #{line.strip}")
     end
 
-    # Backtrace and config-file are added so they show up in the help
-    # commands.  Both options are actually handled before the other
-    # options get parsed.
+    if description then
+      formatted = description.split("\n\n").map do |chunk|
+        wrap(chunk, 80 - 4)
+      end.join("\n")
 
-    add_common_option('--config-file FILE',
-      "Use this config file instead of default") do
+      @parser.separator ""
+      @parser.separator "  Description:"
+      formatted.split("\n").each do |line|
+        @parser.separator "    #{line.rstrip}"
+      end
     end
 
-    add_common_option('--backtrace',
-      'Show stack backtrace on errors') do
+    unless defaults_str.empty?
+      @parser.separator("")
+      @parser.separator("  Defaults:")
+      defaults_str.split(/\n/).each do |line|
+        @parser.separator("    #{line}")
+      end
     end
+  end
 
-    add_common_option('--debug',
-      'Turn on Ruby debugging') do
+  def configure_options(header, option_list)
+    return if option_list.nil? or option_list.empty?
+
+    header = header.to_s.empty? ? '' : "#{header} "
+    @parser.separator "  #{header}Options:"
+
+    option_list.each do |args, handler|
+      dashes = args.select { |arg| arg =~ /^-/ }
+      @parser.on(*args) do |value|
+        handler.call(value, @options)
+      end
     end
 
-    # :stopdoc:
-    HELP = %{
-      RubyGems is a sophisticated package manager for Ruby.  This is a
-      basic help message containing pointers to more information.
+    @parser.separator ''
+  end
 
-        Usage:
-          gem -h/--help
-          gem -v/--version
-          gem command [arguments...] [options...]
+  ##
+  # Wraps +text+ to +width+
 
-        Examples:
-          gem install rake
-          gem list --local
-          gem build package.gemspec
-          gem help install
+  def wrap(text, width) # :doc:
+    text.gsub(/(.{1,#{width}})( +|$\n?)|(.{1,#{width}})/, "\\1\\3\n")
+  end
 
-        Further help:
-          gem help commands            list all 'gem' commands
-          gem help examples            show some examples of usage
-          gem help platforms           show information about platforms
-          gem help <COMMAND>           show help on COMMAND
-                                         (e.g. 'gem help install')
-        Further information:
-          http://rubygems.rubyforge.org
-    }.gsub(/^    /, "")
+  # ----------------------------------------------------------------
+  # Add the options common to all commands.
 
-    # :startdoc:
+  add_common_option('-h', '--help',
+                    'Get help on this command') do |value, options|
+    options[:help] = true
+  end
 
-  end # class
+  add_common_option('-V', '--[no-]verbose',
+                    'Set the verbose level of output') do |value, options|
+    # Set us to "really verbose" so the progress meter works
+    if Gem.configuration.verbose and value then
+      Gem.configuration.verbose = 1
+    else
+      Gem.configuration.verbose = value
+    end
+  end
 
-  # This is where Commands will be placed in the namespace
-  module Commands; end
+  add_common_option('-q', '--quiet', 'Silence commands') do |value, options|
+    Gem.configuration.verbose = false
+  end
 
+  # Backtrace and config-file are added so they show up in the help
+  # commands.  Both options are actually handled before the other
+  # options get parsed.
+
+  add_common_option('--config-file FILE',
+                    'Use this config file instead of default') do
+  end
+
+  add_common_option('--backtrace',
+                    'Show stack backtrace on errors') do
+  end
+
+  add_common_option('--debug',
+                    'Turn on Ruby debugging') do
+  end
+
+  # :stopdoc:
+
+  HELP = %{
+    RubyGems is a sophisticated package manager for Ruby.  This is a
+    basic help message containing pointers to more information.
+
+      Usage:
+        gem -h/--help
+        gem -v/--version
+        gem command [arguments...] [options...]
+
+      Examples:
+        gem install rake
+        gem list --local
+        gem build package.gemspec
+        gem help install
+
+      Further help:
+        gem help commands            list all 'gem' commands
+        gem help examples            show some examples of usage
+        gem help platforms           show information about platforms
+        gem help <COMMAND>           show help on COMMAND
+                                       (e.g. 'gem help install')
+        gem server                   present a web page at
+                                     http://localhost:8808/
+                                     with info about installed gems
+      Further information:
+        http://rubygems.rubyforge.org
+  }.gsub(/^    /, '')
+
+  # :startdoc:
+
 end
+
+##
+# This is where Commands will be placed in the namespace
+
+module Gem::Commands
+end
+
Index: lib/rubygems/dependency.rb
===================================================================
--- lib/rubygems/dependency.rb	(revision 23658)
+++ lib/rubygems/dependency.rb	(revision 23659)
@@ -4,8 +4,6 @@
 # See LICENSE.txt for permissions.
 #++
 
-require 'rubygems'
-
 ##
 # The Dependency class holds a Gem name and a Gem::Requirement
 
@@ -72,7 +70,7 @@
   alias requirements_list requirement_list
 
   def normalize
-    ver = @version_requirement.instance_eval { @version }
+    ver = @version_requirement.instance_variable_get :@version
     @version_requirements = Gem::Requirement.new([ver])
     @version_requirement = nil
   end
@@ -81,6 +79,21 @@
     "#{name} (#{version_requirements}, #{@type || :runtime})"
   end
 
+  def pretty_print(q) # :nodoc:
+    q.group 1, 'Gem::Dependency.new(', ')' do
+      q.pp @name
+      q.text ','
+      q.breakable
+
+      q.pp @version_requirements
+
+      q.text ','
+      q.breakable
+
+      q.pp @type
+    end
+  end
+
   def ==(other) # :nodoc:
     self.class === other &&
       self.name == other.name &&
@@ -89,15 +102,22 @@
   end
 
   ##
-  # Uses this dependency as a pattern to compare to the dependency +other+.
-  # This dependency will match if the name matches the other's name, and other
-  # has only an equal version requirement that satisfies this dependency.
+  # Uses this dependency as a pattern to compare to +other+.  This dependency
+  # will match if the name matches the other's name, and other has only an
+  # equal version requirement that satisfies this dependency.
 
   def =~(other)
-    return false unless self.class === other
+    other = if self.class === other then
+              other
+            else
+              return false unless other.respond_to? :name and
+                                  other.respond_to? :version
 
+              Gem::Dependency.new other.name, other.version
+            end
+
     pattern = @name
-    pattern = /\A#{@name}\Z/ unless Regexp === pattern
+    pattern = /\A#{Regexp.escape @name}\Z/ unless Regexp === pattern
 
     return false unless pattern =~ other.name
 
@@ -111,9 +131,18 @@
     version_requirements.satisfied_by? version
   end
 
-  def hash # :nodoc:
+  ##
+  # A dependency's hash is the sum of the hash of the #name, #type and
+  # #version_requirements
+
+  def hash
     name.hash + type.hash + version_requirements.hash
   end
 
+  def inspect # :nodoc:
+    "<%s type=%p name=%p requirements=%p>" % [self.class, @type, @name,
+      version_requirements.to_s]
+  end
+
 end
 
Index: lib/rubygems/source_info_cache_entry.rb
===================================================================
--- lib/rubygems/source_info_cache_entry.rb	(revision 23658)
+++ lib/rubygems/source_info_cache_entry.rb	(revision 23659)
@@ -13,8 +13,8 @@
   attr_reader :source_index
 
   ##
-  # The size of the of the source entry.  Used to determine if the
-  # source index has changed.
+  # The size of the source entry.  Used to determine if the source index has
+  # changed.
 
   attr_reader :size
 
Index: lib/rubygems/local_remote_options.rb
===================================================================
--- lib/rubygems/local_remote_options.rb	(revision 23658)
+++ lib/rubygems/local_remote_options.rb	(revision 23659)
@@ -23,7 +23,9 @@
         raise OptionParser::InvalidArgument, value
       end
 
-      raise OptionParser::InvalidArgument, value unless uri.scheme == 'http'
+      unless ['http', 'https', 'file'].include?(uri.scheme)
+         raise OptionParser::InvalidArgument, value
+      end
 
       value
     end
@@ -90,7 +92,7 @@
       source << '/' if source !~ /\/\z/
 
       if options[:added_source] then
-        Gem.sources << source
+        Gem.sources << source unless Gem.sources.include?(source)
       else
         options[:added_source] = true
         Gem.sources.replace [source]
@@ -99,10 +101,9 @@
   end
 
   ##
-  # Add the --update-source option
+  # Add the --update-sources option
 
   def add_update_sources_option
-
     add_option(:"Local/Remote", '-u', '--[no-]update-sources',
                'Update local source cache') do |value, options|
       Gem.configuration.update_sources = value
Index: lib/rubygems/timer.rb
===================================================================
--- lib/rubygems/timer.rb	(revision 23658)
+++ lib/rubygems/timer.rb	(revision 23659)
@@ -1,6 +1,6 @@
 #
-# This file defines a $log variable for logging, and a time() method for recording timing
-# information.
+# This file defines a $log variable for logging, and a time() method for
+# recording timing information.
 #
 #--
 # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
@@ -8,18 +8,21 @@
 # See LICENSE.txt for permissions.
 #++
 
+require 'rubygems'
 
+file, lineno = Gem.location_of_caller
+
+warn "#{file}:#{lineno}:Warning: RubyGems' lib/rubygems/timer.rb deprecated and will be removed on or after June 2009."
+
 $log = Object.new
-def $log.debug(str)
-  STDERR.puts str
+
+# :stopdoc:
+def $log.debug(message)
+  Gem.debug message
 end
 
-def time(msg, width=25)
-  t = Time.now
-  return_value = yield
-  elapsed = Time.now.to_f - t.to_f
-  elapsed = sprintf("%3.3f", elapsed)
-  $log.debug "#{msg.ljust(width)}: #{elapsed}s"
-  return_value
+def time(msg, width=25, &block)
+  Gem.time(msg, width, &block)
 end
+# :startdoc:
 
Index: lib/rubygems/install_update_options.rb
===================================================================
--- lib/rubygems/install_update_options.rb	(revision 23658)
+++ lib/rubygems/install_update_options.rb	(revision 23659)
@@ -9,9 +9,12 @@
 
 ##
 # Mixin methods for install and update options for Gem::Commands
+
 module Gem::InstallUpdateOptions
 
+  ##
   # Add the install/update options to the option parser.
+
   def add_install_update_options
     OptionParser.accept Gem::Security::Policy do |value|
       value = Gem::Security::Policies[value]
@@ -92,7 +95,7 @@
 
     add_option(:"Install/Update",       '--[no-]user-install',
                'Install in user\'s home directory instead',
-               'of GEM_HOME. Defaults to using home directory',
+               'of GEM_HOME. Defaults to using home',
                'only if GEM_HOME is not writable.') do |value, options|
       options[:user_install] = value
     end
@@ -102,9 +105,18 @@
                 "dependencies") do |value, options|
       options[:development] = true
     end
+
+    add_option(:"Install/Update", "--prerelease",
+               "Install prerelease versions of a gem if",
+               "available. Defaults to skipping",
+               "prereleases.") do |value, options|
+      options[:prerelease] = true
+    end
   end
 
+  ##
   # Default options for the gem install command.
+
   def install_update_defaults_str
     '--rdoc --no-force --no-test --wrappers'
   end
Index: lib/rubygems/validator.rb
===================================================================
--- lib/rubygems/validator.rb	(revision 23658)
+++ lib/rubygems/validator.rb	(revision 23659)
@@ -6,10 +6,17 @@
 
 require 'find'
 
-require 'rubygems/digest/md5'
+require 'digest'
 require 'rubygems/format'
 require 'rubygems/installer'
 
+# Load test-unit 2.x if it's a gem
+begin
+   Gem.activate('test-unit')
+rescue Gem::LoadError
+   # Ignore - use the test-unit library that's part of the standard library
+end   
+
 ##
 # Validator performs various gem file and gem database validation
 
@@ -33,7 +40,7 @@
     sum_data = gem_data.gsub(/MD5SUM = "([a-z0-9]+)"/,
                              "MD5SUM = \"#{"F" * 32}\"")
 
-    unless Gem::MD5.hexdigest(sum_data) == $1.to_s then
+    unless Digest::MD5.hexdigest(sum_data) == $1.to_s then
       raise Gem::VerificationError, 'invalid checksum for gem file'
     end
   end
@@ -48,7 +55,7 @@
       gem_data = file.read
       verify_gem gem_data
     end
-  rescue Errno::ENOENT
+  rescue Errno::ENOENT, Errno::EINVAL
     raise Gem::VerificationError, "missing gem file #{gem_path}"
   end
 
@@ -56,13 +63,11 @@
 
   def find_files_for_gem(gem_directory)
     installed_files = []
-    Find.find(gem_directory) {|file_name|
-      fn = file_name.slice((gem_directory.size)..(file_name.size-1)).sub(/^\//, "")
-      if(!(fn =~ /CVS/ || File.directory?(fn) || fn == "")) then
-        installed_files << fn
-      end
-
-    }
+    Find.find gem_directory do |file_name|
+      fn = file_name[gem_directory.size..file_name.size-1].sub(/^\//, "")
+      installed_files << fn unless
+        fn =~ /CVS/ || fn.empty? || File.directory?(file_name)
+    end
     installed_files
   end
 
@@ -81,53 +86,82 @@
   #
   # returns a hash of ErrorData objects, keyed on the problem gem's name.
 
-  def alien
-    errors = {}
+  def alien(gems=[])
+    errors = Hash.new { |h,k| h[k] = {} }
 
     Gem::SourceIndex.from_installed_gems.each do |gem_name, gem_spec|
-      errors[gem_name] ||= []
+      next unless gems.include? gem_spec.name unless gems.empty?
 
-      gem_path = File.join(Gem.dir, "cache", gem_spec.full_name) + ".gem"
-      spec_path = File.join(Gem.dir, "specifications", gem_spec.full_name) + ".gemspec"
-      gem_directory = File.join(Gem.dir, "gems", gem_spec.full_name)
+      install_dir = gem_spec.installation_path
+      gem_path = File.join(install_dir, "cache", gem_spec.full_name) + ".gem"
+      spec_path = File.join(install_dir, "specifications",
+                            gem_spec.full_name) + ".gemspec"
+      gem_directory = gem_spec.full_gem_path
 
-      installed_files = find_files_for_gem(gem_directory)
+      unless File.directory? gem_directory then
+        errors[gem_name][gem_spec.full_name] =
+          "Gem registered but doesn't exist at #{gem_directory}"
+        next
+      end
 
       unless File.exist? spec_path then
-        errors[gem_name] << ErrorData.new(spec_path, "Spec file doesn't exist for installed gem")
+        errors[gem_name][spec_path] = "Spec file missing for installed gem"
       end
 
       begin
         verify_gem_file(gem_path)
 
+        good, gone, unreadable = nil, nil, nil, nil
+
         open gem_path, Gem.binary_mode do |file|
           format = Gem::Format.from_file_by_path(gem_path)
-          format.file_entries.each do |entry, data|
-            # Found this file.  Delete it from list
-            installed_files.delete remove_leading_dot_dir(entry['path'])
 
-            next unless data # HACK `gem check -a mkrf`
+          good, gone = format.file_entries.partition { |entry, _|
+            File.exist? File.join(gem_directory, entry['path'])
+          }
 
-            open File.join(gem_directory, entry['path']), Gem.binary_mode do |f|
-              unless Gem::MD5.hexdigest(f.read).to_s ==
-                Gem::MD5.hexdigest(data).to_s then
-                errors[gem_name] << ErrorData.new(entry['path'], "installed file doesn't match original from gem")
+          gone.map! { |entry, _| entry['path'] }
+          gone.sort.each do |path|
+            errors[gem_name][path] = "Missing file"
+          end
+
+          good, unreadable = good.partition { |entry, _|
+            File.readable? File.join(gem_directory, entry['path'])
+          }
+
+          unreadable.map! { |entry, _| entry['path'] }
+          unreadable.sort.each do |path|
+            errors[gem_name][path] = "Unreadable file"
+          end
+
+          good.each do |entry, data|
+            begin
+              next unless data # HACK `gem check -a mkrf`
+
+              open File.join(gem_directory, entry['path']), Gem.binary_mode do |f|
+                unless Digest::MD5.hexdigest(f.read).to_s ==
+                    Digest::MD5.hexdigest(data).to_s then
+                  errors[gem_name][entry['path']] = "Modified from original"
+                end
               end
             end
           end
         end
+
+        installed_files = find_files_for_gem(gem_directory)
+        good.map! { |entry, _| entry['path'] }
+        extras = installed_files - good - unreadable
+
+        extras.each do |extra|
+          errors[gem_name][extra] = "Extra file"
+        end
       rescue Gem::VerificationError => e
-        errors[gem_name] << ErrorData.new(gem_path, e.message)
+        errors[gem_name][gem_path] = e.message
       end
+    end
 
-      # Clean out directories that weren't explicitly included in the gemspec
-      # FIXME: This still allows arbitrary incorrect directories.
-      installed_files.delete_if {|potential_directory|
-        File.directory?(File.join(gem_directory, potential_directory))
-      }
-      if(installed_files.size > 0) then
-        errors[gem_name] << ErrorData.new(gem_path, "Unmanaged files in gem: #{installed_files.inspect}")
-      end
+    errors.each do |name, subhash|
+      errors[name] = subhash.map { |path, msg| ErrorData.new(path, msg) }
     end
 
     errors
@@ -167,7 +201,7 @@
   def unit_test(gem_spec)
     start_dir = Dir.pwd
     Dir.chdir(gem_spec.full_gem_path)
-    $: << File.join(Gem.dir, "gems", gem_spec.full_name)
+    $: << gem_spec.full_gem_path
     # XXX: why do we need this gem_spec when we've already got 'spec'?
     test_files = gem_spec.test_files
 
@@ -200,7 +234,6 @@
     Dir.chdir(start_dir)
   end
 
-  private
   def remove_leading_dot_dir(path)
     path.sub(/^\.\//, "")
   end
Index: lib/rubygems/old_format.rb
===================================================================
--- lib/rubygems/old_format.rb	(revision 23658)
+++ lib/rubygems/old_format.rb	(revision 23659)
@@ -4,145 +4,149 @@
 # See LICENSE.txt for permissions.
 #++
 
+require 'rubygems'
 require 'fileutils'
 require 'yaml'
 require 'zlib'
 
-module Gem
+##
+# The format class knows the guts of the RubyGem .gem file format and provides
+# the capability to read gem files
 
+class Gem::OldFormat
+
+  attr_accessor :spec, :file_entries, :gem_path
+
   ##
-  # The format class knows the guts of the RubyGem .gem file format
-  # and provides the capability to read gem files
+  # Constructs an instance of a Format object, representing the gem's data
+  # structure.
   #
-  class OldFormat
-    attr_accessor :spec, :file_entries, :gem_path
+  # gem:: [String] The file name of the gem
 
-    ##
-    # Constructs an instance of a Format object, representing the gem's
-    # data structure.
-    #
-    # gem:: [String] The file name of the gem
-    #
-    def initialize(gem_path)
-      @gem_path = gem_path
+  def initialize(gem_path)
+    @gem_path = gem_path
+  end
+
+  ##
+  # Reads the named gem file and returns a Format object, representing the
+  # data from the gem file
+  #
+  # file_path:: [String] Path to the gem file
+
+  def self.from_file_by_path(file_path)
+    unless File.exist?(file_path)
+      raise Gem::Exception, "Cannot load gem file [#{file_path}]"
     end
 
-    ##
-    # Reads the named gem file and returns a Format object, representing
-    # the data from the gem file
-    #
-    # file_path:: [String] Path to the gem file
-    #
-    def self.from_file_by_path(file_path)
-      unless File.exist?(file_path)
-        raise Gem::Exception, "Cannot load gem file [#{file_path}]"
-      end
-      File.open(file_path, 'rb') do |file|
-        from_io(file, file_path)
-      end
+    File.open(file_path, 'rb') do |file|
+      from_io(file, file_path)
     end
+  end
 
-    ##
-    # Reads a gem from an io stream and returns a Format object, representing
-    # the data from the gem file
-    #
-    # io:: [IO] Stream from which to read the gem
-    #
-    def self.from_io(io, gem_path="(io)")
-      format = self.new(gem_path)
-      skip_ruby(io)
-      format.spec = read_spec(io)
-      format.file_entries = []
-      read_files_from_gem(io) do |entry, file_data|
-        format.file_entries << [entry, file_data]
+  ##
+  # Reads a gem from an io stream and returns a Format object, representing
+  # the data from the gem file
+  #
+  # io:: [IO] Stream from which to read the gem
+
+  def self.from_io(io, gem_path="(io)")
+    format = self.new(gem_path)
+    skip_ruby(io)
+    format.spec = read_spec(io)
+    format.file_entries = []
+    read_files_from_gem(io) do |entry, file_data|
+      format.file_entries << [entry, file_data]
+    end
+    format
+  end
+
+  private
+
+  ##
+  # Skips the Ruby self-install header.  After calling this method, the
+  # IO index will be set after the Ruby code.
+  #
+  # file:: [IO] The IO to process (skip the Ruby code)
+
+  def self.skip_ruby(file)
+    end_seen = false
+    loop {
+      line = file.gets
+      if(line == nil || line.chomp == "__END__") then
+        end_seen = true
+        break
       end
-      format
+    }
+
+    if end_seen == false then
+      raise Gem::Exception.new("Failed to find end of ruby script while reading gem")
     end
+  end
 
-    private
-    ##
-    # Skips the Ruby self-install header.  After calling this method, the
-    # IO index will be set after the Ruby code.
-    #
-    # file:: [IO] The IO to process (skip the Ruby code)
-    #
-    def self.skip_ruby(file)
-      end_seen = false
-      loop {
-        line = file.gets
-        if(line == nil || line.chomp == "__END__") then
-          end_seen = true
-          break
-        end
-      }
-     if(end_seen == false) then
-       raise Gem::Exception.new("Failed to find end of ruby script while reading gem")
-     end
+  ##
+  # Reads the specification YAML from the supplied IO and constructs
+  # a Gem::Specification from it.  After calling this method, the
+  # IO index will be set after the specification header.
+  #
+  # file:: [IO] The IO to process
+
+  def self.read_spec(file)
+    yaml = ''
+
+    read_until_dashes file do |line|
+      yaml << line
     end
 
-    ##
-    # Reads the specification YAML from the supplied IO and constructs
-    # a Gem::Specification from it.  After calling this method, the
-    # IO index will be set after the specification header.
-    #
-    # file:: [IO] The IO to process
-    #
-    def self.read_spec(file)
-      yaml = ''
-      begin
-        read_until_dashes(file) do |line|
-          yaml << line
-        end
-        Specification.from_yaml(yaml)
-      rescue YAML::Error => e
-        raise Gem::Exception.new("Failed to parse gem specification out of gem file")
-      rescue ArgumentError => e
-        raise Gem::Exception.new("Failed to parse gem specification out of gem file")
-      end
+    Gem::Specification.from_yaml yaml
+  rescue YAML::Error => e
+    raise Gem::Exception, "Failed to parse gem specification out of gem file"
+  rescue ArgumentError => e
+    raise Gem::Exception, "Failed to parse gem specification out of gem file"
+  end
+
+  ##
+  # Reads lines from the supplied IO until a end-of-yaml (---) is
+  # reached
+  #
+  # file:: [IO] The IO to process
+  # block:: [String] The read line
+
+  def self.read_until_dashes(file)
+    while((line = file.gets) && line.chomp.strip != "---") do
+      yield line
     end
+  end
 
-    ##
-    # Reads lines from the supplied IO until a end-of-yaml (---) is
-    # reached
-    #
-    # file:: [IO] The IO to process
-    # block:: [String] The read line
-    #
-    def self.read_until_dashes(file)
-      while((line = file.gets) && line.chomp.strip != "---") do
-        yield line
+  ##
+  # Reads the embedded file data from a gem file, yielding an entry
+  # containing metadata about the file and the file contents themselves
+  # for each file that's archived in the gem.
+  # NOTE: Many of these methods should be extracted into some kind of
+  # Gem file read/writer
+  #
+  # gem_file:: [IO] The IO to process
+
+  def self.read_files_from_gem(gem_file)
+    errstr = "Error reading files from gem"
+    header_yaml = ''
+    begin
+      self.read_until_dashes(gem_file) do |line|
+        header_yaml << line
       end
-    end
+      header = YAML.load(header_yaml)
+      raise Gem::Exception, errstr unless header
 
-
-    ##
-    # Reads the embedded file data from a gem file, yielding an entry
-    # containing metadata about the file and the file contents themselves
-    # for each file that's archived in the gem.
-    # NOTE: Many of these methods should be extracted into some kind of
-    # Gem file read/writer
-    #
-    # gem_file:: [IO] The IO to process
-    #
-    def self.read_files_from_gem(gem_file)
-      errstr = "Error reading files from gem"
-      header_yaml = ''
-      begin
+      header.each do |entry|
+        file_data = ''
         self.read_until_dashes(gem_file) do |line|
-          header_yaml << line
+          file_data << line
         end
-        header = YAML.load(header_yaml)
-        raise Gem::Exception.new(errstr) unless header
-        header.each do |entry|
-          file_data = ''
-          self.read_until_dashes(gem_file) do |line|
-            file_data << line
-          end
-          yield [entry, Zlib::Inflate.inflate(file_data.strip.unpack("m")[0])]
-        end
-      rescue Exception,Zlib::DataError => e
-        raise Gem::Exception.new(errstr)
+        yield [entry, Zlib::Inflate.inflate(file_data.strip.unpack("m")[0])]
       end
+    rescue Zlib::DataError => e
+      raise Gem::Exception, errstr
     end
   end
+
 end
+
Index: lib/rubygems/builder.rb
===================================================================
--- lib/rubygems/builder.rb	(revision 23658)
+++ lib/rubygems/builder.rb	(revision 23659)
@@ -4,81 +4,83 @@
 # See LICENSE.txt for permissions.
 #++
 
-module Gem
+##
+# The Builder class processes RubyGem specification files
+# to produce a .gem file.
 
+class Gem::Builder
+
+  include Gem::UserInteraction
   ##
-  # The Builder class processes RubyGem specification files
-  # to produce a .gem file.
+  # Constructs a builder instance for the provided specification
   #
-  class Builder
+  # spec:: [Gem::Specification] The specification instance
 
-    include UserInteraction
-    ##
-    # Constructs a builder instance for the provided specification
-    #
-    # spec:: [Gem::Specification] The specification instance
-    #
-    def initialize(spec)
-      require "yaml"
-      require "rubygems/package"
-      require "rubygems/security"
+  def initialize(spec)
+    require "yaml"
+    require "rubygems/package"
+    require "rubygems/security"
 
-      @spec = spec
-    end
+    @spec = spec
+  end
 
-    ##
-    # Builds the gem from the specification.  Returns the name of the file
-    # written.
-    #
-    def build
-      @spec.mark_version
-      @spec.validate
-      @signer = sign
-      write_package
-      say success
-      @spec.file_name
-    end
+  ##
+  # Builds the gem from the specification.  Returns the name of the file
+  # written.
 
-    def success
-      <<-EOM
+  def build
+    @spec.mark_version
+    @spec.validate
+    @signer = sign
+    write_package
+    say success
+    @spec.file_name
+  end
+
+  def success
+    <<-EOM
   Successfully built RubyGem
   Name: #{@spec.name}
   Version: #{@spec.version}
   File: #{@spec.full_name+'.gem'}
 EOM
-    end
+  end
 
-    private
+  private
 
-    def sign
-      # if the signing key was specified, then load the file, and swap
-      # to the public key (TODO: we should probably just omit the
-      # signing key in favor of the signing certificate, but that's for
-      # the future, also the signature algorithm should be configurable)
-      signer = nil
-      if @spec.respond_to?(:signing_key) && @spec.signing_key
-        signer = Gem::Security::Signer.new(@spec.signing_key, @spec.cert_chain)
-        @spec.signing_key = nil
-        @spec.cert_chain = signer.cert_chain.map { |cert| cert.to_s }
-      end
-      signer
+  ##
+  # If the signing key was specified, then load the file, and swap to the
+  # public key (TODO: we should probably just omit the signing key in favor of
+  # the signing certificate, but that's for the future, also the signature
+  # algorithm should be configurable)
+
+  def sign
+    signer = nil
+
+    if @spec.respond_to?(:signing_key) and @spec.signing_key then
+      signer = Gem::Security::Signer.new @spec.signing_key, @spec.cert_chain
+      @spec.signing_key = nil
+      @spec.cert_chain = signer.cert_chain.map { |cert| cert.to_s }
     end
 
-    def write_package
-      open @spec.file_name, 'wb' do |gem_io|
-        Gem::Package.open gem_io, 'w', @signer do |pkg|
-          pkg.metadata = @spec.to_yaml
+    signer
+  end
 
-          @spec.files.each do |file|
-            next if File.directory? file
+  def write_package
+    open @spec.file_name, 'wb' do |gem_io|
+      Gem::Package.open gem_io, 'w', @signer do |pkg|
+        pkg.metadata = @spec.to_yaml
 
-            stat = File.stat file
-            mode = stat.mode & 0777
-            size = stat.size
+        @spec.files.each do |file|
+          next if File.directory? file
+          next if file == @spec.file_name # Don't add gem onto itself
 
-            pkg.add_file_simple file, mode, size do |tar_io|
-              tar_io.write open(file, "rb") { |f| f.read }
-            end
+          stat = File.stat file
+          mode = stat.mode & 0777
+          size = stat.size
+
+          pkg.add_file_simple file, mode, size do |tar_io|
+            tar_io.write open(file, "rb") { |f| f.read }
           end
         end
       end
Index: lib/rubygems/format.rb
===================================================================
--- lib/rubygems/format.rb	(revision 23658)
+++ lib/rubygems/format.rb	(revision 23659)
@@ -8,80 +8,80 @@
 
 require 'rubygems/package'
 
-module Gem
+##
+# Gem::Format knows the guts of the RubyGem .gem file format and provides the
+# capability to read gem files
 
+class Gem::Format
+
+  attr_accessor :spec, :file_entries, :gem_path
+
+  extend Gem::UserInteraction
+
   ##
-  # The format class knows the guts of the RubyGem .gem file format
-  # and provides the capability to read gem files
+  # Constructs an instance of a Format object, representing the gem's
+  # data structure.
   #
-  class Format
-    attr_accessor :spec, :file_entries, :gem_path
-    extend Gem::UserInteraction
+  # gem:: [String] The file name of the gem
+  #
+  def initialize(gem_path)
+    @gem_path = gem_path
+  end
 
-    ##
-    # Constructs an instance of a Format object, representing the gem's
-    # data structure.
-    #
-    # gem:: [String] The file name of the gem
-    #
-    def initialize(gem_path)
-      @gem_path = gem_path
+  ##
+  # Reads the named gem file and returns a Format object, representing 
+  # the data from the gem file
+  #
+  # file_path:: [String] Path to the gem file
+
+  def self.from_file_by_path(file_path, security_policy = nil)
+    format = nil
+
+    unless File.exist?(file_path)
+      raise Gem::Exception, "Cannot load gem at [#{file_path}] in #{Dir.pwd}"
     end
 
-    ##
-    # Reads the named gem file and returns a Format object, representing
-    # the data from the gem file
-    #
-    # file_path:: [String] Path to the gem file
-    #
-    def self.from_file_by_path(file_path, security_policy = nil)
-      format = nil
+    # check for old version gem
+    if File.read(file_path, 20).include?("MD5SUM =")
+      require 'rubygems/old_format'
 
-      unless File.exist?(file_path)
-        raise Gem::Exception, "Cannot load gem at [#{file_path}] in #{Dir.pwd}"
+      format = Gem::OldFormat.from_file_by_path(file_path)
+    else
+      open file_path, Gem.binary_mode do |io|
+        format = from_io io, file_path, security_policy
       end
+    end
 
-      # check for old version gem
-      if File.read(file_path, 20).include?("MD5SUM =")
-        require 'rubygems/old_format'
+    return format
+  end
 
-        format = OldFormat.from_file_by_path(file_path)
-      else
-        open file_path, Gem.binary_mode do |io|
-          format = from_io io, file_path, security_policy
-        end
-      end
+  ##
+  # Reads a gem from an io stream and returns a Format object, representing
+  # the data from the gem file
+  #
+  # io:: [IO] Stream from which to read the gem
 
-      return format
-    end
+  def self.from_io(io, gem_path="(io)", security_policy = nil)
+    format = new gem_path
 
-    ##
-    # Reads a gem from an io stream and returns a Format object, representing
-    # the data from the gem file
-    #
-    # io:: [IO] Stream from which to read the gem
-    #
-    def self.from_io(io, gem_path="(io)", security_policy = nil)
-      format = new gem_path
+    Gem::Package.open io, 'r', security_policy do |pkg|
+      format.spec = pkg.metadata
+      format.file_entries = []
 
-      Package.open io, 'r', security_policy do |pkg|
-        format.spec = pkg.metadata
-        format.file_entries = []
+      pkg.each do |entry|
+        size = entry.header.size
+        mode = entry.header.mode
 
-        pkg.each do |entry|
-          size = entry.header.size
-          mode = entry.header.mode
-
-          format.file_entries << [{
-              "size" => size, "mode" => mode, "path" => entry.full_name,
-            },
-            entry.read
-          ]
-        end
+        format.file_entries << [{
+            "size" => size, "mode" => mode, "path" => entry.full_name,
+          },
+          entry.read
+        ]
       end
-
-      format
     end
 
+    format
   end
+
 end
+
Index: lib/rubygems/spec_fetcher.rb
===================================================================
--- lib/rubygems/spec_fetcher.rb	(revision 23658)
+++ lib/rubygems/spec_fetcher.rb	(revision 23659)
@@ -1,6 +1,6 @@
 require 'zlib'
+require 'fileutils'
 
-require 'rubygems'
 require 'rubygems/remote_fetcher'
 require 'rubygems/user_interaction'
 
@@ -26,6 +26,11 @@
 
   attr_reader :specs # :nodoc:
 
+  ##
+  # Cache of prerelease specs
+
+  attr_reader :prerelease_specs # :nodoc:
+
   @fetcher = nil
 
   def self.fetcher
@@ -42,6 +47,7 @@
 
     @specs = {}
     @latest_specs = {}
+    @prerelease_specs = {}
 
     @fetcher = Gem::RemoteFetcher.fetcher
   end
@@ -56,10 +62,10 @@
   ##
   # Fetch specs matching +dependency+.  If +all+ is true, all matching
   # versions are returned.  If +matching_platform+ is false, all platforms are
-  # returned.
+  # returned. If +prerelease+ is true, prerelease versions are included.
 
-  def fetch(dependency, all = false, matching_platform = true)
-    specs_and_sources = find_matching dependency, all, matching_platform
+  def fetch(dependency, all = false, matching_platform = true, prerelease = false)
+    specs_and_sources = find_matching dependency, all, matching_platform, prerelease
 
     specs_and_sources.map do |spec_tuple, source_uri|
       [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri]
@@ -110,10 +116,10 @@
   # versions are returned.  If +matching_platform+ is false, gems for all
   # platforms are returned.
 
-  def find_matching(dependency, all = false, matching_platform = true)
+  def find_matching(dependency, all = false, matching_platform = true, prerelease = false)
     found = {}
 
-    list(all).each do |source_uri, specs|
+    list(all, prerelease).each do |source_uri, specs|
       found[source_uri] = specs.select do |spec_name, version, spec_platform|
         dependency =~ Gem::Dependency.new(spec_name, version) and
           (not matching_platform or Gem::Platform.match(spec_platform))
@@ -155,28 +161,37 @@
 
   ##
   # Returns a list of gems available for each source in Gem::sources.  If
-  # +all+ is true, all versions are returned instead of only latest versions.
+  # +all+ is true, all versions are returned instead of only latest
+  # versions. If +prerelease+ is true, include prerelease versions.
 
-  def list(all = false)
+  def list(all = false, prerelease = false)
+    # TODO: make type the only argument
+    type = if all
+             :all
+           elsif prerelease
+             :prerelease
+           else
+             :latest
+           end
+
     list = {}
 
-    file = all ? 'specs' : 'latest_specs'
+    file = { :latest => 'latest_specs',
+      :prerelease => 'prerelease_specs',
+      :all => 'specs' }[type]
 
+    cache = { :latest => @latest_specs,
+      :prerelease => @prerelease_specs,
+      :all => @specs }[type]
+    
     Gem.sources.each do |source_uri|
       source_uri = URI.parse source_uri
 
-      if all and @specs.include? source_uri then
-        list[source_uri] = @specs[source_uri]
-      elsif not all and @latest_specs.include? source_uri then
-        list[source_uri] = @latest_specs[source_uri]
-      else
-        specs = load_specs source_uri, file
+      unless cache.include? source_uri
+        cache[source_uri] = load_specs source_uri, file
+      end
 
-        cache = all ? @specs : @latest_specs
-
-        cache[source_uri] = specs
-        list[source_uri] = specs
-      end
+      list[source_uri] = cache[source_uri]
     end
 
     list
@@ -206,8 +221,15 @@
       loaded = true
     end
 
-    specs = Marshal.load spec_dump
+    specs = begin
+              Marshal.load spec_dump
+            rescue ArgumentError
+              spec_dump = @fetcher.fetch_path spec_path
+              loaded = true
 
+              Marshal.load spec_dump
+            end
+
     if loaded and @update_cache then
       begin
         FileUtils.mkdir_p cache_dir
Index: lib/rubygems/dependency_installer.rb
===================================================================
--- lib/rubygems/dependency_installer.rb	(revision 23658)
+++ lib/rubygems/dependency_installer.rb	(revision 23659)
@@ -20,8 +20,9 @@
     :force => false,
     :format_executable => false, # HACK dup
     :ignore_dependencies => false,
+    :prerelease => false,
     :security_policy => nil, # HACK NoSecurity requires OpenSSL.  AlmostNo? Low?
-    :wrappers => true
+    :wrappers => true,
   }
 
   ##
@@ -37,6 +38,7 @@
   # :format_executable:: See Gem::Installer#initialize.
   # :ignore_dependencies:: Don't install any dependencies.
   # :install_dir:: See Gem::Installer#install.
+  # :prerelease:: Allow prerelease versions
   # :security_policy:: See Gem::Installer::new and Gem::Security.
   # :user_install:: See Gem::Installer.new
   # :wrappers:: See Gem::Installer::new
@@ -58,6 +60,7 @@
     @force = options[:force]
     @format_executable = options[:format_executable]
     @ignore_dependencies = options[:ignore_dependencies]
+    @prerelease = options[:prerelease]
     @security_policy = options[:security_policy]
     @user_install = options[:user_install]
     @wrappers = options[:wrappers]
@@ -90,10 +93,10 @@
           req
         end
 
-        all = requirements.length > 1 ||
-                (requirements.first != ">=" and requirements.first != ">")
+        all = !@prerelease && (requirements.length > 1 ||
+                (requirements.first != ">=" and requirements.first != ">"))
 
-        found = Gem::SpecFetcher.fetcher.fetch dep, all
+        found = Gem::SpecFetcher.fetcher.fetch dep, all, true, @prerelease
         gems_and_sources.push(*found)
 
       rescue Gem::RemoteFetcher::FetchError => e
Index: lib/rubygems/indexer.rb
===================================================================
--- lib/rubygems/indexer.rb	(revision 23658)
+++ lib/rubygems/indexer.rb	(revision 23659)
@@ -6,6 +6,7 @@
 require 'rubygems/format'
 
 begin
+  gem 'builder'
   require 'builder/xchar'
 rescue LoadError
 end
@@ -18,11 +19,36 @@
   include Gem::UserInteraction
 
   ##
+  # Build indexes for RubyGems older than 1.2.0 when true
+
+  attr_accessor :build_legacy
+
+  ##
+  # Build indexes for RubyGems 1.2.0 and newer when true
+
+  attr_accessor :build_modern
+
+  ##
   # Index install location
 
   attr_reader :dest_directory
 
   ##
+  # Specs index install location
+
+  attr_reader :dest_specs_index
+
+  ##
+  # Latest specs index install location
+
+  attr_reader :dest_latest_specs_index
+
+  ##
+  # Prerelease specs index install location
+
+  attr_reader :dest_prerelease_specs_index
+
+  ##
   # Index build directory
 
   attr_reader :directory
@@ -30,12 +56,21 @@
   ##
   # Create an indexer that will index the gems in +directory+.
 
-  def initialize(directory)
+  def initialize(directory, options = {})
     unless ''.respond_to? :to_xs then
       fail "Gem::Indexer requires that the XML Builder library be installed:" \
            "\n\tgem install builder"
     end
 
+    options = { :build_legacy => true, :build_modern => true }.merge options
+
+    @build_legacy = options[:build_legacy]
+    @build_modern = options[:build_modern]
+
+    @rss_title = options[:rss_title]
+    @rss_host = options[:rss_host]
+    @rss_gems_host = options[:rss_gems_host]
+
     @dest_directory = directory
     @directory = File.join Dir.tmpdir, "gem_generate_index_#{$$}"
 
@@ -54,22 +89,19 @@
     @specs_index = File.join @directory, "specs.#{Gem.marshal_version}"
     @latest_specs_index = File.join @directory,
                                     "latest_specs.#{Gem.marshal_version}"
+    @prerelease_specs_index = File.join(@directory,
+                                        "prerelease_specs.#{Gem.marshal_version}")
 
-    files = [
-      @specs_index,
-      "#{@specs_index}.gz",
-      @latest_specs_index,
-      "#{@latest_specs_index}.gz",
-      @quick_dir,
-      @master_index,
-      "#{@master_index}.Z",
-      @marshal_index,
-      "#{@marshal_index}.Z",
-    ]
+    @dest_specs_index = File.join @dest_directory,
+                                  "specs.#{Gem.marshal_version}"
+    @dest_latest_specs_index = File.join @dest_directory,
+                                         "latest_specs.#{Gem.marshal_version}"
+    @dest_prerelease_specs_index = File.join @dest_directory,
+                                            "prerelease_specs.#{Gem.marshal_version}"
 
-    @files = files.map do |path|
-      path.sub @directory, ''
-    end
+    @rss_index = File.join @directory, 'index.rss'
+
+    @files = []
   end
 
   ##
@@ -91,159 +123,367 @@
   # Build various indicies
 
   def build_indicies(index)
+    # Marshal gemspecs are used by both modern and legacy RubyGems
+    build_marshal_gemspecs index
+    build_legacy_indicies index if @build_legacy
+    build_modern_indicies index if @build_modern
+    build_rss index
+
+    compress_indicies
+  end
+
+  ##
+  # Builds indicies for RubyGems older than 1.2.x
+
+  def build_legacy_indicies(index)
     progress = ui.progress_reporter index.size,
-                                    "Generating quick index gemspecs for #{index.size} gems",
+                                    "Generating YAML quick index gemspecs for #{index.size} gems",
                                     "Complete"
 
-    index.each do |original_name, spec|
-      spec_file_name = "#{original_name}.gemspec.rz"
-      yaml_name = File.join @quick_dir, spec_file_name
-      marshal_name = File.join @quick_marshal_dir, spec_file_name
+    Gem.time 'Generated YAML quick index gemspecs' do
+      index.each do |original_name, spec|
+        spec_file_name = "#{original_name}.gemspec.rz"
+        yaml_name = File.join @quick_dir, spec_file_name
 
-      yaml_zipped = Gem.deflate spec.to_yaml
-      open yaml_name, 'wb' do |io| io.write yaml_zipped end
+        yaml_zipped = Gem.deflate spec.to_yaml
+        open yaml_name, 'wb' do |io| io.write yaml_zipped end
 
-      marshal_zipped = Gem.deflate Marshal.dump(spec)
-      open marshal_name, 'wb' do |io| io.write marshal_zipped end
+        progress.updated original_name
+      end
 
-      progress.updated original_name
+      progress.done
     end
 
-    progress.done
+    say "Generating quick index"
 
-    say "Generating specs index"
-
-    open @specs_index, 'wb' do |io|
-      specs = index.sort.map do |_, spec|
-        platform = spec.original_platform
-        platform = Gem::Platform::RUBY if platform.nil? or platform.empty?
-        [spec.name, spec.version, platform]
+    Gem.time 'Generated quick index' do
+      open @quick_index, 'wb' do |io|
+        io.puts index.sort.map { |_, spec| spec.original_name }
       end
+    end
 
-      specs = compact_specs specs
+    say "Generating latest index"
 
-      Marshal.dump specs, io
+    Gem.time 'Generated latest index' do
+      open @latest_index, 'wb' do |io|
+        io.puts index.latest_specs.sort.map { |spec| spec.original_name }
+      end
     end
 
-    say "Generating latest specs index"
+    # Don't need prerelease legacy index
 
-    open @latest_specs_index, 'wb' do |io|
-      specs = index.latest_specs.sort.map do |spec|
-        platform = spec.original_platform
-        platform = Gem::Platform::RUBY if platform.nil? or platform.empty?
-        [spec.name, spec.version, platform]
+    say "Generating Marshal master index"
+
+    Gem.time 'Generated Marshal master index' do
+      open @marshal_index, 'wb' do |io|
+        io.write index.dump
       end
+    end
 
-      specs = compact_specs specs
+    progress = ui.progress_reporter index.size,
+                                    "Generating YAML master index for #{index.size} gems (this may take a while)",
+                                    "Complete"
 
-      Marshal.dump specs, io
-    end
+    Gem.time 'Generated YAML master index' do
+      open @master_index, 'wb' do |io|
+        io.puts "--- !ruby/object:#{index.class}"
+        io.puts "gems:"
 
-    say "Generating quick index"
+        gems = index.sort_by { |name, gemspec| gemspec.sort_obj }
+        gems.each do |original_name, gemspec|
+          yaml = gemspec.to_yaml.gsub(/^/, '    ')
+          yaml = yaml.sub(/\A    ---/, '') # there's a needed extra ' ' here
+          io.print "  #{original_name}:"
+          io.puts yaml
 
-    quick_index = File.join @quick_dir, 'index'
-    open quick_index, 'wb' do |io|
-      io.puts index.sort.map { |_, spec| spec.original_name }
-    end
+          progress.updated original_name
+        end
+      end
 
-    say "Generating latest index"
-
-    latest_index = File.join @quick_dir, 'latest_index'
-    open latest_index, 'wb' do |io|
-      io.puts index.latest_specs.sort.map { |spec| spec.original_name }
+      progress.done
     end
 
-    say "Generating Marshal master index"
+    @files << @quick_dir
+    @files << @master_index
+    @files << "#{@master_index}.Z"
+    @files << @marshal_index
+    @files << "#{@marshal_index}.Z"
+  end
 
-    open @marshal_index, 'wb' do |io|
-      io.write index.dump
-    end
+  ##
+  # Builds Marshal quick index gemspecs.
 
+  def build_marshal_gemspecs(index)
     progress = ui.progress_reporter index.size,
-                                    "Generating YAML master index for #{index.size} gems (this may take a while)",
+                                    "Generating Marshal quick index gemspecs for #{index.size} gems",
                                     "Complete"
 
-    open @master_index, 'wb' do |io|
-      io.puts "--- !ruby/object:#{index.class}"
-      io.puts "gems:"
+    files = []
 
-      gems = index.sort_by { |name, gemspec| gemspec.sort_obj }
-      gems.each do |original_name, gemspec|
-        yaml = gemspec.to_yaml.gsub(/^/, '    ')
-        yaml = yaml.sub(/\A    ---/, '') # there's a needed extra ' ' here
-        io.print "  #{original_name}:"
-        io.puts yaml
+    Gem.time 'Generated Marshal quick index gemspecs' do
+      (index.gems.merge(index.prerelease_gems)).each do |original_name, spec|
+        spec_file_name = "#{original_name}.gemspec.rz"
+        marshal_name = File.join @quick_marshal_dir, spec_file_name
 
+        marshal_zipped = Gem.deflate Marshal.dump(spec)
+        open marshal_name, 'wb' do |io| io.write marshal_zipped end
+
+        files << marshal_name
+
         progress.updated original_name
       end
+
+      progress.done
     end
 
-    progress.done
+    @files << @quick_marshal_dir
 
-    say "Compressing indicies"
-    # use gzip for future files.
+    files
+  end
 
-    compress quick_index, 'rz'
-    paranoid quick_index, 'rz'
+  ##
+  # Build a single index for RubyGems 1.2 and newer
 
-    compress latest_index, 'rz'
-    paranoid latest_index, 'rz'
+  def build_modern_index(index, file, name)
+    say "Generating #{name} index"
 
-    compress @marshal_index, 'Z'
-    paranoid @marshal_index, 'Z'
+    Gem.time "Generated #{name} index" do
+      open(file, 'wb') do |io|
+        specs = index.map do |*spec|
+          # We have to splat here because latest_specs is an array,
+          # while the others are hashes. See the TODO in source_index.rb
+          spec = spec.flatten.last
+          platform = spec.original_platform
 
-    compress @master_index, 'Z'
-    paranoid @master_index, 'Z'
+          # win32-api-1.0.4-x86-mswin32-60
+          unless String === platform then
+            alert_warning "Skipping invalid platform in gem: #{spec.full_name}"
+            next
+          end
 
-    gzip @specs_index
-    gzip @latest_specs_index
+          platform = Gem::Platform::RUBY if platform.nil? or platform.empty?
+          [spec.name, spec.version, platform]
+        end
+
+        specs = compact_specs(specs)
+        Marshal.dump(specs, io)
+      end
+    end
   end
 
   ##
+  # Builds indicies for RubyGems 1.2 and newer. Handles full, latest, prerelease
+
+  def build_modern_indicies(index)
+    build_modern_index(index.sort, @specs_index, 'specs')
+    build_modern_index(index.latest_specs.sort,
+                       @latest_specs_index,
+                       'latest specs')
+    build_modern_index(index.prerelease_specs.sort,
+                       @prerelease_specs_index,
+                       'prerelease specs')
+
+    @files += [@specs_index,
+               "#{@specs_index}.gz",
+               @latest_specs_index,
+               "#{@latest_specs_index}.gz",
+               @prerelease_specs_index,
+               "#{@prerelease_specs_index}.gz"]
+  end
+
+  ##
+  # Builds an RSS feed for past two days gem releases according to the gem's
+  # date.
+
+  def build_rss(index)
+    if @rss_host.nil? or @rss_gems_host.nil? then
+      if Gem.configuration.really_verbose then
+        alert_warning "no --rss-host or --rss-gems-host, RSS generation disabled"
+      end
+      return
+    end
+
+    require 'cgi'
+    require 'rubygems/text'
+
+    extend Gem::Text
+
+    Gem.time 'Generated rss' do
+      open @rss_index, 'wb' do |io|
+        rss_host = CGI.escapeHTML @rss_host
+        rss_title = CGI.escapeHTML(@rss_title || 'gems')
+
+        io.puts <<-HEADER
+<?xml version="1.0"?>
+<rss version="2.0">
+  <channel>
+    <title>#{rss_title}</title>
+    <link>http://#{rss_host}</link>
+    <description>Recently released gems from http://#{rss_host}</description>
+    <generator>RubyGems v#{Gem::RubyGemsVersion}</generator>
+    <docs>http://cyber.law.harvard.edu/rss/rss.html</docs>
+        HEADER
+
+        today = Gem::Specification::TODAY
+        yesterday = today - 86400
+
+        index = index.select do |_, spec|
+          spec_date = spec.date
+
+          case spec_date
+          when Date
+            Time.parse(spec_date.to_s) >= yesterday
+          when Time
+            spec_date >= yesterday
+          end
+        end
+
+        index = index.select do |_, spec|
+          spec_date = spec.date
+
+          case spec_date
+          when Date
+            Time.parse(spec_date.to_s) <= today
+          when Time
+            spec_date <= today
+          end
+        end
+
+        index.sort_by { |_, spec| [-spec.date.to_i, spec] }.each do |_, spec|
+          gem_path = CGI.escapeHTML "http://#{@rss_gems_host}/gems/#{spec.full_name}.gem"
+          size = File.stat(spec.loaded_from).size rescue next
+
+          description = spec.description || spec.summary || ''
+          authors = Array spec.authors
+          emails = Array spec.email
+          authors = emails.zip(authors).map do |email, author|
+            email += " (#{author})" if author and not author.empty?
+          end.join ', '
+
+          description = description.split(/\n\n+/).map do |chunk|
+            format_text chunk, 78
+          end
+
+          description = description.join "\n\n"
+
+          item = ''
+
+          item << <<-ITEM
+    <item>
+      <title>#{CGI.escapeHTML spec.full_name}</title>
+      <description>
+&lt;pre&gt;#{CGI.escapeHTML description.chomp}&lt;/pre&gt;
+      </description>
+      <author>#{CGI.escapeHTML authors}</author>
+      <guid>#{CGI.escapeHTML spec.full_name}</guid>
+      <enclosure url=\"#{gem_path}\"
+                 length=\"#{size}\" type=\"application/octet-stream\" />
+      <pubDate>#{spec.date.rfc2822}</pubDate>
+          ITEM
+
+          item << <<-ITEM if spec.homepage
+      <link>#{CGI.escapeHTML spec.homepage}</link>
+          ITEM
+
+          item << <<-ITEM
+    </item>
+          ITEM
+
+          io.puts item
+        end
+
+        io.puts <<-FOOTER
+  </channel>
+</rss>
+        FOOTER
+      end
+    end
+
+    @files << @rss_index
+  end
+
+  ##
   # Collect specifications from .gem files from the gem directory.
 
-  def collect_specs
+  def collect_specs(gems = gem_file_list)
     index = Gem::SourceIndex.new
 
-    progress = ui.progress_reporter gem_file_list.size,
-                                    "Loading #{gem_file_list.size} gems from #{@dest_directory}",
+    progress = ui.progress_reporter gems.size,
+                                    "Loading #{gems.size} gems from #{@dest_directory}",
                                     "Loaded all gems"
 
-    gem_file_list.each do |gemfile|
-      if File.size(gemfile.to_s) == 0 then
-        alert_warning "Skipping zero-length gem: #{gemfile}"
-        next
-      end
-
-      begin
-        spec = Gem::Format.from_file_by_path(gemfile).spec
-
-        unless gemfile =~ /\/#{Regexp.escape spec.original_name}.*\.gem\z/i then
-          alert_warning "Skipping misnamed gem: #{gemfile} => #{spec.full_name} (#{spec.original_name})"
+    Gem.time 'loaded' do
+      gems.each do |gemfile|
+        if File.size(gemfile.to_s) == 0 then
+          alert_warning "Skipping zero-length gem: #{gemfile}"
           next
         end
 
-        abbreviate spec
-        sanitize spec
+        begin
+          spec = Gem::Format.from_file_by_path(gemfile).spec
+          spec.loaded_from = gemfile
 
-        index.gems[spec.original_name] = spec
+          unless gemfile =~ /\/#{Regexp.escape spec.original_name}.*\.gem\z/i then
+            expected_name = spec.full_name
+            expected_name << " (#{spec.original_name})" if
+              spec.original_name != spec.full_name
+            alert_warning "Skipping misnamed gem: #{gemfile} should be named #{expected_name}"
+            next
+          end
 
-        progress.updated spec.original_name
+          abbreviate spec
+          sanitize spec
 
-      rescue SignalException => e
-        alert_error "Received signal, exiting"
-        raise
-      rescue Exception => e
-        alert_error "Unable to process #{gemfile}\n#{e.message} (#{e.class})\n\t#{e.backtrace.join "\n\t"}"
+          index.add_spec spec, spec.original_name
+
+          progress.updated spec.original_name
+
+        rescue SignalException => e
+          alert_error "Received signal, exiting"
+          raise
+        rescue Exception => e
+          alert_error "Unable to process #{gemfile}\n#{e.message} (#{e.class})\n\t#{e.backtrace.join "\n\t"}"
+        end
       end
+
+      progress.done
     end
 
-    progress.done
-
     index
   end
 
   ##
+  # Compresses indicies on disk
+  #--
+  # All future files should be compressed using gzip, not deflate
+
+  def compress_indicies
+    say "Compressing indicies"
+
+    Gem.time 'Compressed indicies' do
+      if @build_legacy then
+        compress @quick_index, 'rz'
+        paranoid @quick_index, 'rz'
+
+        compress @latest_index, 'rz'
+        paranoid @latest_index, 'rz'
+
+        compress @marshal_index, 'Z'
+        paranoid @marshal_index, 'Z'
+
+        compress @master_index, 'Z'
+        paranoid @master_index, 'Z'
+      end
+
+      if @build_modern then
+        gzip @specs_index
+        gzip @latest_specs_index
+        gzip @prerelease_specs_index
+      end
+    end
+  end
+
+  ##
   # Compacts Marshal output for the specs index data source by using identical
   # objects as much as possible.
 
@@ -282,7 +522,7 @@
   end
 
   ##
-  # Builds and installs indexicies.
+  # Builds and installs indicies.
 
   def generate_index
     make_temp_directories
@@ -311,7 +551,27 @@
 
     say "Moving index into production dir #{@dest_directory}" if verbose
 
-    @files.each do |file|
+    files = @files.dup
+    files.delete @quick_marshal_dir if files.include? @quick_dir
+
+    if files.include? @quick_marshal_dir and
+       not files.include? @quick_dir then
+      files.delete @quick_marshal_dir
+      quick_marshal_dir = @quick_marshal_dir.sub @directory, ''
+
+      dst_name = File.join @dest_directory, quick_marshal_dir
+
+      FileUtils.mkdir_p File.dirname(dst_name), :verbose => verbose
+      FileUtils.rm_rf dst_name, :verbose => verbose
+      FileUtils.mv @quick_marshal_dir, dst_name, :verbose => verbose,
+                   :force => true
+    end
+
+    files = files.map do |path|
+      path.sub @directory, ''
+    end
+
+    files.each do |file|
       src_name = File.join @directory, file
       dst_name = File.join @dest_directory, file
 
@@ -366,5 +626,87 @@
     string ? string.to_s.to_xs : string
   end
 
+  ##
+  # Perform an in-place update of the repository from newly added gems.  Only
+  # works for modern indicies, and sets #build_legacy to false when run.
+
+  def update_index
+    @build_legacy = false
+
+    make_temp_directories
+
+    specs_mtime = File.stat(@dest_specs_index).mtime
+    newest_mtime = Time.at 0
+
+    updated_gems = gem_file_list.select do |gem|
+      gem_mtime = File.stat(gem).mtime
+      newest_mtime = gem_mtime if gem_mtime > newest_mtime
+      gem_mtime >= specs_mtime
+    end
+
+    if updated_gems.empty? then
+      say 'No new gems'
+      terminate_interaction 0
+    end
+
+    index = collect_specs updated_gems
+
+    files = build_marshal_gemspecs index
+
+    Gem.time 'Updated indexes' do
+      update_specs_index index, @dest_specs_index, @specs_index
+      update_specs_index index, @dest_latest_specs_index, @latest_specs_index
+      update_specs_index(index.prerelease_gems, @dest_prerelease_specs_index,
+                         @prerelease_specs_index)
+    end
+
+    compress_indicies
+
+    verbose = Gem.configuration.really_verbose
+
+    say "Updating production dir #{@dest_directory}" if verbose
+
+    files << @specs_index
+    files << "#{@specs_index}.gz"
+    files << @latest_specs_index
+    files << "#{@latest_specs_index}.gz"
+    files << @prerelease_specs_index
+    files << "#{@prerelease_specs_index}.gz"
+
+    files = files.map do |path|
+      path.sub @directory, ''
+    end
+
+    files.each do |file|
+      src_name = File.join @directory, file
+      dst_name = File.join @dest_directory, File.dirname(file)
+
+      FileUtils.mv src_name, dst_name, :verbose => verbose,
+                   :force => true
+
+      File.utime newest_mtime, newest_mtime, dst_name
+    end
+  end
+
+  ##
+  # Combines specs in +index+ and +source+ then writes out a new copy to
+  # +dest+.  For a latest index, does not ensure the new file is minimal.
+
+  def update_specs_index(index, source, dest)
+    specs_index = Marshal.load Gem.read_binary(source)
+
+    index.each do |_, spec|
+      platform = spec.original_platform
+      platform = Gem::Platform::RUBY if platform.nil? or platform.empty?
+      specs_index << [spec.name, spec.version, platform]
+    end
+
+    specs_index = compact_specs specs_index.uniq.sort
+
+    open dest, 'wb' do |io|
+      Marshal.dump specs_index, io
+    end
+  end
+
 end
 
Index: lib/rubygems/ext/builder.rb
===================================================================
--- lib/rubygems/ext/builder.rb	(revision 23658)
+++ lib/rubygems/ext/builder.rb	(revision 23659)
@@ -4,8 +4,6 @@
 # See LICENSE.txt for permissions.
 #++
 
-require 'rubygems/ext'
-
 class Gem::Ext::Builder
 
   def self.class_name
@@ -15,7 +13,7 @@
 
   def self.make(dest_path, results)
     unless File.exist? 'Makefile' then
-      raise Gem::InstallError, "Makefile not found:\n\n#{results.join "\n"}"
+      raise Gem::InstallError, "Makefile not found:\n\n#{results.join "\n"}" 
     end
 
     mf = File.read('Makefile')
Index: lib/rubygems/ext/configure_builder.rb
===================================================================
--- lib/rubygems/ext/configure_builder.rb	(revision 23658)
+++ lib/rubygems/ext/configure_builder.rb	(revision 23659)
@@ -11,6 +11,7 @@
   def self.build(extension, directory, dest_path, results)
     unless File.exist?('Makefile') then
       cmd = "sh ./configure --prefix=#{dest_path}"
+      cmd << " #{Gem::Command.build_args.join ' '}" unless Gem::Command.build_args.empty?
 
       run cmd, results
     end
Index: lib/rubygems/ext/rake_builder.rb
===================================================================
--- lib/rubygems/ext/rake_builder.rb	(revision 23658)
+++ lib/rubygems/ext/rake_builder.rb	(revision 23659)
@@ -5,17 +5,21 @@
 #++
 
 require 'rubygems/ext/builder'
+require 'rubygems/command'
 
 class Gem::Ext::RakeBuilder < Gem::Ext::Builder
 
   def self.build(extension, directory, dest_path, results)
     if File.basename(extension) =~ /mkrf_conf/i then
       cmd = "#{Gem.ruby} #{File.basename extension}"
-      cmd << " #{ARGV.join " "}" unless ARGV.empty?
+      cmd << " #{Gem::Command.build_args.join " "}" unless Gem::Command.build_args.empty?
       run cmd, results
     end
 
-    cmd = ENV['rake'] || 'rake'
+    # Deal with possible spaces in the path, e.g. C:/Program Files
+    dest_path = '"' + dest_path + '"' if dest_path.include?(' ')
+
+    cmd = ENV['rake'] || "#{Gem.ruby} -rubygems #{Gem.bin_path('rake')}" rescue Gem.default_exec_format % 'rake'
     cmd += " RUBYARCHDIR=#{dest_path} RUBYLIBDIR=#{dest_path}" # ENV is frozen
 
     run cmd, results
Index: lib/rubygems/ext/ext_conf_builder.rb
===================================================================
--- lib/rubygems/ext/ext_conf_builder.rb	(revision 23658)
+++ lib/rubygems/ext/ext_conf_builder.rb	(revision 23659)
@@ -5,12 +5,13 @@
 #++
 
 require 'rubygems/ext/builder'
+require 'rubygems/command'
 
 class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
 
   def self.build(extension, directory, dest_path, results)
     cmd = "#{Gem.ruby} #{File.basename extension}"
-    cmd << " #{ARGV.join ' '}" unless ARGV.empty?
+    cmd << " #{Gem::Command.build_args.join ' '}" unless Gem::Command.build_args.empty?
 
     run cmd, results
 
Index: lib/rubygems/doc_manager.rb
===================================================================
--- lib/rubygems/doc_manager.rb	(revision 23658)
+++ lib/rubygems/doc_manager.rb	(revision 23659)
@@ -41,12 +41,23 @@
 
     begin
       require 'rdoc/rdoc'
+
+      @rdoc_version = if defined? RDoc::VERSION then
+                        Gem::Version.new RDoc::VERSION
+                      else
+                        Gem::Version.new '1.0.1' # HACK parsing is hard
+                      end
+
     rescue LoadError => e
       raise Gem::DocumentError,
-          "ERROR: RDoc documentation generator not installed!"
+          "ERROR: RDoc documentation generator not installed: #{e}"
     end
   end
 
+  def self.rdoc_version
+    @rdoc_version
+  end
+
   ##
   # Updates the RI cache for RDoc 2 if it is installed
 
@@ -94,10 +105,8 @@
   # RI docs generation to fail if run after RDoc).
 
   def generate_ri
-    if @spec.has_rdoc then
-      setup_rdoc
-      install_ri # RDoc bug, ri goes first
-    end
+    setup_rdoc
+    install_ri # RDoc bug, ri goes first
 
     FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
   end
@@ -110,10 +119,8 @@
   # RI docs generation to fail if run after RDoc).
 
   def generate_rdoc
-    if @spec.has_rdoc then
-      setup_rdoc
-      install_rdoc
-    end
+    setup_rdoc
+    install_rdoc
 
     FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir)
   end
@@ -151,8 +158,17 @@
     args << '--quiet'
     args << @spec.require_paths.clone
     args << @spec.extra_rdoc_files
+    args << '--title' << "#{@spec.full_name} Documentation"
     args = args.flatten.map do |arg| arg.to_s end
 
+    if self.class.rdoc_version >= Gem::Version.new('2.4.0') then
+      args.delete '--inline-source'
+      args.delete '--promiscuous'
+      args.delete '-p'
+      args.delete '--one-file'
+      # HACK more
+    end
+
     r = RDoc::RDoc.new
 
     old_pwd = Dir.pwd
@@ -194,20 +210,20 @@
     original_name = [
       @spec.name, @spec.version, @spec.original_platform].join '-'
 
-      doc_dir = File.join @spec.installation_path, 'doc', @spec.full_name
-      unless File.directory? doc_dir then
-        doc_dir = File.join @spec.installation_path, 'doc', original_name
-      end
+    doc_dir = File.join @spec.installation_path, 'doc', @spec.full_name
+    unless File.directory? doc_dir then
+      doc_dir = File.join @spec.installation_path, 'doc', original_name
+    end
 
-      FileUtils.rm_rf doc_dir
+    FileUtils.rm_rf doc_dir
 
-      ri_dir = File.join @spec.installation_path, 'ri', @spec.full_name
+    ri_dir = File.join @spec.installation_path, 'ri', @spec.full_name
 
-      unless File.directory? ri_dir then
-        ri_dir = File.join @spec.installation_path, 'ri', original_name
-      end
+    unless File.directory? ri_dir then
+      ri_dir = File.join @spec.installation_path, 'ri', original_name
+    end
 
-      FileUtils.rm_rf ri_dir
+    FileUtils.rm_rf ri_dir
   end
 
 end
Index: lib/rubygems/gem_runner.rb
===================================================================
--- lib/rubygems/gem_runner.rb	(revision 23658)
+++ lib/rubygems/gem_runner.rb	(revision 23659)
@@ -8,51 +8,71 @@
 require 'rubygems/config_file'
 require 'rubygems/doc_manager'
 
-module Gem
+##
+# Run an instance of the gem program.
+#
+# Gem::GemRunner is only intended for internal use by RubyGems itself.  It
+# does not form any public API and may change at any time for any reason.
+#
+# If you would like to duplicate functionality of `gem` commands, use the
+# classes they call directly.
 
-  ####################################################################
-  # Run an instance of the gem program.
-  #
-  class GemRunner
+class Gem::GemRunner
 
-    def initialize(options={})
-      @command_manager_class = options[:command_manager] || Gem::CommandManager
-      @config_file_class = options[:config_file] || Gem::ConfigFile
-      @doc_manager_class = options[:doc_manager] || Gem::DocManager
+  def initialize(options={})
+    @command_manager_class = options[:command_manager] || Gem::CommandManager
+    @config_file_class = options[:config_file] || Gem::ConfigFile
+    @doc_manager_class = options[:doc_manager] || Gem::DocManager
+  end
+
+  ##
+  # Run the gem command with the following arguments.
+
+  def run(args)
+    start_time = Time.now
+
+    if args.include?('--')
+      # We need to preserve the original ARGV to use for passing gem options
+      # to source gems.  If there is a -- in the line, strip all options after
+      # it...its for the source building process.
+      build_args = args[args.index("--") + 1...args.length]
+      args = args[0...args.index("--")]
     end
 
-    # Run the gem command with the following arguments.
-    def run(args)
-      start_time = Time.now
-      do_configuration(args)
-      cmd = @command_manager_class.instance
-      cmd.command_names.each do |command_name|
-        config_args = Gem.configuration[command_name]
-        config_args = case config_args
-                      when String
-                        config_args.split ' '
-                      else
-                        Array(config_args)
-                      end
-        Command.add_specific_extra_args command_name, config_args
-      end
-      cmd.run(Gem.configuration.args)
-      end_time = Time.now
-      if Gem.configuration.benchmark
-        printf "\nExecution time: %0.2f seconds.\n", end_time-start_time
-        puts "Press Enter to finish"
-        STDIN.gets
-      end
+    Gem::Command.build_args = build_args if build_args
+
+    do_configuration args
+    cmd = @command_manager_class.instance
+
+    cmd.command_names.each do |command_name|
+      config_args = Gem.configuration[command_name]
+      config_args = case config_args
+                    when String
+                      config_args.split ' '
+                    else
+                      Array(config_args)
+                    end
+      Gem::Command.add_specific_extra_args command_name, config_args
     end
 
-    private
+    cmd.run Gem.configuration.args
+    end_time = Time.now
 
-    def do_configuration(args)
-      Gem.configuration = @config_file_class.new(args)
-      Gem.use_paths(Gem.configuration[:gemhome], Gem.configuration[:gempath])
-      Gem::Command.extra_args = Gem.configuration[:gem]
-      @doc_manager_class.configured_args = Gem.configuration[:rdoc]
+    if Gem.configuration.benchmark then
+      printf "\nExecution time: %0.2f seconds.\n", end_time - start_time
+      puts "Press Enter to finish"
+      STDIN.gets
     end
+  end
 
-  end # class
-end # module
+  private
+
+  def do_configuration(args)
+    Gem.configuration = @config_file_class.new(args)
+    Gem.use_paths(Gem.configuration[:gemhome], Gem.configuration[:gempath])
+    Gem::Command.extra_args = Gem.configuration[:gem]
+    @doc_manager_class.configured_args = Gem.configuration[:rdoc]
+  end
+
+end
+
Index: lib/rubygems/config_file.rb
===================================================================
--- lib/rubygems/config_file.rb	(revision 23658)
+++ lib/rubygems/config_file.rb	(revision 23659)
@@ -5,7 +5,6 @@
 #++
 
 require 'yaml'
-require 'rubygems'
 
 # Store the gem command options specified in the configuration file.  The
 # config file object acts much like a hash.
@@ -36,7 +35,8 @@
 
       CSIDL_COMMON_APPDATA = 0x0023
       path = 0.chr * 260
-      SHGetFolderPath = Win32API.new 'shell32', 'SHGetFolderPath', 'PLPLP', 'L', :stdcall
+      SHGetFolderPath = Win32API.new 'shell32', 'SHGetFolderPath', 'PLPLP', 'L',
+                                     :stdcall
       SHGetFolderPath.call nil, CSIDL_COMMON_APPDATA, nil, 1, path
 
       path.strip
Index: lib/rubygems/version_option.rb
===================================================================
--- lib/rubygems/version_option.rb	(revision 23658)
+++ lib/rubygems/version_option.rb	(revision 23659)
@@ -41,6 +41,7 @@
                "Specify version of gem to #{task}", *wrap) do
                  |value, options|
       options[:version] = value
+      options[:prerelease] = true if value.prerelease?
     end
   end
 
Index: lib/rubygems/package_task.rb
===================================================================
--- lib/rubygems/package_task.rb	(revision 0)
+++ lib/rubygems/package_task.rb	(revision 23659)
@@ -0,0 +1,118 @@
+# Copyright (c) 2003, 2004 Jim Weirich, 2009 Eric Hodel
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+require 'rubygems'
+begin
+  gem 'rake'
+rescue Gem::LoadError
+end
+
+require 'rake/packagetask'
+
+##
+# Create a package based upon a Gem::Specification.  Gem packages, as well as
+# zip files and tar/gzipped packages can be produced by this task.
+#
+# In addition to the Rake targets generated by Rake::PackageTask, a
+# Gem::PackageTask will also generate the following tasks:
+#
+# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.gem"</b>]
+#   Create a RubyGems package with the given name and version.
+#
+# Example using a Gem::Specification:
+#
+#   require 'rubygems'
+#   require 'rubygems/package_task'
+#   
+#   spec = Gem::Specification.new do |s|
+#     s.platform = Gem::Platform::RUBY
+#     s.summary = "Ruby based make-like utility."
+#     s.name = 'rake'
+#     s.version = PKG_VERSION
+#     s.requirements << 'none'
+#     s.require_path = 'lib'
+#     s.autorequire = 'rake'
+#     s.files = PKG_FILES
+#     s.description = <<-EOF
+#   Rake is a Make-like program implemented in Ruby. Tasks
+#   and dependencies are specified in standard Ruby syntax.
+#     EOF
+#   end
+#   
+#   Gem::PackageTask.new(spec) do |pkg|
+#     pkg.need_zip = true
+#     pkg.need_tar = true
+#   end
+
+class Gem::PackageTask < Rake::PackageTask
+
+  ##
+  # Ruby Gem::Specification containing the metadata for this package.  The
+  # name, version and package_files are automatically determined from the
+  # gemspec and don't need to be explicitly provided.
+
+  attr_accessor :gem_spec
+
+  ##
+  # Create a Gem Package task library.  Automatically define the gem if a
+  # block is given.  If no block is supplied, then #define needs to be called
+  # to define the task.
+
+  def initialize(gem_spec)
+    init gem_spec
+    yield self if block_given?
+    define if block_given?
+  end
+
+  ##
+  # Initialization tasks without the "yield self" or define operations.
+
+  def init(gem)
+    super gem.name, gem.version
+    @gem_spec = gem
+    @package_files += gem_spec.files if gem_spec.files
+  end
+
+  ##
+  # Create the Rake tasks and actions specified by this Gem::PackageTask.
+  # (+define+ is automatically called if a block is given to +new+).
+
+  def define
+    super
+    task :package => [:gem]
+    desc "Build the gem file #{gem_file}"
+    task :gem => ["#{package_dir}/#{gem_file}"]
+    file "#{package_dir}/#{gem_file}" => [package_dir] + @gem_spec.files do
+      when_writing("Creating #{gem_spec.full_name}.gem") {
+        Gem::Builder.new(gem_spec).build
+        verbose(true) {
+          mv gem_file, "#{package_dir}/#{gem_file}"
+        }
+      }
+    end
+  end
+
+  def gem_file
+    "#{@gem_spec.full_name}.gem"
+  end
+
+end
+
Index: lib/rubygems/specification.rb
===================================================================
--- lib/rubygems/specification.rb	(revision 23658)
+++ lib/rubygems/specification.rb	(revision 23659)
@@ -4,1260 +4,1440 @@
 # See LICENSE.txt for permissions.
 #++
 
-require 'rubygems'
 require 'rubygems/version'
 require 'rubygems/requirement'
 require 'rubygems/platform'
 
 # :stopdoc:
-# Time::today has been deprecated in 0.9.5 and will be removed.
-if RUBY_VERSION < '1.9' then
-  def Time.today
-    t = Time.now
-    t - ((t.to_f + t.gmt_offset) % 86400)
-  end unless defined? Time.today
-end
-
 class Date; end # for ruby_code if date.rb wasn't required
-
 # :startdoc:
 
-module Gem
+##
+# The Specification class contains the metadata for a Gem.  Typically
+# defined in a .gemspec file or a Rakefile, and looks like this:
+#
+#   spec = Gem::Specification.new do |s|
+#     s.name = 'rfoo'
+#     s.version = '1.0'
+#     s.summary = 'Example gem specification'
+#     ...
+#   end
+#
+# For a great way to package gems, use Hoe.
 
+class Gem::Specification
+
   ##
-  # == Gem::Specification
-  #
-  # The Specification class contains the metadata for a Gem.  Typically
-  # defined in a .gemspec file or a Rakefile, and looks like this:
-  #
-  #   spec = Gem::Specification.new do |s|
-  #     s.name = 'rfoo'
-  #     s.version = '1.0'
-  #     s.summary = 'Example gem specification'
-  #     ...
-  #   end
-  #
-  # There are many <em>gemspec attributes</em>, and the best place to learn
-  # about them in the "Gemspec Reference" linked from the RubyGems wiki.
+  # Allows deinstallation of gems with legacy platforms.
 
-  class Specification
+  attr_accessor :original_platform # :nodoc:
 
-    ##
-    # Allows deinstallation of gems with legacy platforms.
+  ##
+  # The the version number of a specification that does not specify one
+  # (i.e. RubyGems 0.7 or earlier).
 
-    attr_accessor :original_platform # :nodoc:
+  NONEXISTENT_SPECIFICATION_VERSION = -1
 
-    ##
-    # The the version number of a specification that does not specify one
-    # (i.e. RubyGems 0.7 or earlier).
+  ##
+  # The specification version applied to any new Specification instances
+  # created.  This should be bumped whenever something in the spec format
+  # changes.
+  #--
+  # When updating this number, be sure to also update #to_ruby.
+  #
+  # NOTE RubyGems < 1.2 cannot load specification versions > 2.
 
-    NONEXISTENT_SPECIFICATION_VERSION = -1
+  CURRENT_SPECIFICATION_VERSION = 3
 
-    ##
-    # The specification version applied to any new Specification instances
-    # created.  This should be bumped whenever something in the spec format
-    # changes.
-    #--
-    # When updating this number, be sure to also update #to_ruby.
-    #
-    # NOTE RubyGems < 1.2 cannot load specification versions > 2.
+  ##
+  # An informal list of changes to the specification.  The highest-valued
+  # key should be equal to the CURRENT_SPECIFICATION_VERSION.
 
-    CURRENT_SPECIFICATION_VERSION = 2
+  SPECIFICATION_VERSION_HISTORY = {
+    -1 => ['(RubyGems versions up to and including 0.7 did not have versioned specifications)'],
+    1  => [
+      'Deprecated "test_suite_file" in favor of the new, but equivalent, "test_files"',
+      '"test_file=x" is a shortcut for "test_files=[x]"'
+    ],
+    2  => [
+      'Added "required_rubygems_version"',
+      'Now forward-compatible with future versions',
+    ],
+    3 => [
+       'Added Fixnum validation to the specification_version'
+    ]
+  }
 
-    ##
-    # An informal list of changes to the specification.  The highest-valued
-    # key should be equal to the CURRENT_SPECIFICATION_VERSION.
+  # :stopdoc:
+  MARSHAL_FIELDS = { -1 => 16, 1 => 16, 2 => 16, 3 => 17 }
 
-    SPECIFICATION_VERSION_HISTORY = {
-      -1 => ['(RubyGems versions up to and including 0.7 did not have versioned specifications)'],
-      1  => [
-        'Deprecated "test_suite_file" in favor of the new, but equivalent, "test_files"',
-        '"test_file=x" is a shortcut for "test_files=[x]"'
-      ],
-      2  => [
-        'Added "required_rubygems_version"',
-        'Now forward-compatible with future versions',
-      ],
-    }
+  now = Time.at(Time.now.to_i)
+  TODAY = now - ((now.to_i + now.gmt_offset) % 86400)
+  # :startdoc:
 
-    # :stopdoc:
-    MARSHAL_FIELDS = { -1 => 16, 1 => 16, 2 => 16 }
+  ##
+  # Optional block used to gather newly defined instances.
 
-    now = Time.at(Time.now.to_i)
-    TODAY = now - ((now.to_i + now.gmt_offset) % 86400)
-    # :startdoc:
+  @@gather = nil
 
-    ##
-    # List of Specification instances.
+  ##
+  # List of attribute names: [:name, :version, ...]
 
-    @@list = []
+  @@required_attributes = []
 
-    ##
-    # Optional block used to gather newly defined instances.
+  ##
+  # List of _all_ attributes and default values:
+  #
+  #   [[:name, nil],
+  #    [:bindir, 'bin'],
+  #    ...]
 
-    @@gather = nil
+  @@attributes = []
 
-    ##
-    # List of attribute names: [:name, :version, ...]
-    @@required_attributes = []
+  @@nil_attributes = []
+  @@non_nil_attributes = [:@original_platform]
 
-    ##
-    # List of _all_ attributes and default values:
-    #
-    #   [[:name, nil],
-    #    [:bindir, 'bin'],
-    #    ...]
+  ##
+  # List of array attributes
 
-    @@attributes = []
+  @@array_attributes = []
 
-    @@nil_attributes = []
-    @@non_nil_attributes = [:@original_platform]
+  ##
+  # Map of attribute names to default values.
 
-    ##
-    # List of array attributes
+  @@default_value = {}
 
-    @@array_attributes = []
+  ##
+  # Names of all specification attributes
 
-    ##
-    # Map of attribute names to default values.
+  def self.attribute_names
+    @@attributes.map { |name, default| name }
+  end
 
-    @@default_value = {}
+  ##
+  # Default values for specification attributes
 
-    ##
-    # Names of all specification attributes
+  def self.attribute_defaults
+    @@attributes.dup
+  end
 
-    def self.attribute_names
-      @@attributes.map { |name, default| name }
-    end
+  ##
+  # The default value for specification attribute +name+
 
-    ##
-    # Default values for specification attributes
+  def self.default_value(name)
+    @@default_value[name]
+  end
 
-    def self.attribute_defaults
-      @@attributes.dup
-    end
+  ##
+  # Required specification attributes
 
-    ##
-    # The default value for specification attribute +name+
+  def self.required_attributes
+    @@required_attributes.dup
+  end
 
-    def self.default_value(name)
-      @@default_value[name]
-    end
+  ##
+  # Is +name+ a required attribute?
 
-    ##
-    # Required specification attributes
+  def self.required_attribute?(name)
+    @@required_attributes.include? name.to_sym
+  end
 
-    def self.required_attributes
-      @@required_attributes.dup
-    end
+  ##
+  # Specification attributes that are arrays (appendable and so-forth)
 
-    ##
-    # Is +name+ a required attribute?
+  def self.array_attributes
+    @@array_attributes.dup
+  end
 
-    def self.required_attribute?(name)
-      @@required_attributes.include? name.to_sym
-    end
+  ##
+  # Specifies the +name+ and +default+ for a specification attribute, and
+  # creates a reader and writer method like Module#attr_accessor.
+  #
+  # The reader method returns the default if the value hasn't been set.
 
-    ##
-    # Specification attributes that are arrays (appendable and so-forth)
-
-    def self.array_attributes
-      @@array_attributes.dup
+  def self.attribute(name, default=nil)
+    ivar_name = "@#{name}".intern
+    if default.nil? then
+      @@nil_attributes << ivar_name
+    else
+      @@non_nil_attributes << [ivar_name, default]
     end
 
-    ##
-    # A list of Specification instances that have been defined in this Ruby
-    # instance.
+    @@attributes << [name, default]
+    @@default_value[name] = default
+    attr_accessor(name)
+  end
 
-    def self.list
-      @@list
-    end
+  ##
+  # Same as :attribute, but ensures that values assigned to the attribute
+  # are array values by applying :to_a to the value.
 
-    ##
-    # Specifies the +name+ and +default+ for a specification attribute, and
-    # creates a reader and writer method like Module#attr_accessor.
-    #
-    # The reader method returns the default if the value hasn't been set.
+  def self.array_attribute(name)
+    @@non_nil_attributes << ["@#{name}".intern, []]
 
-    def self.attribute(name, default=nil)
-      ivar_name = "@#{name}".intern
-      if default.nil? then
-        @@nil_attributes << ivar_name
-      else
-        @@non_nil_attributes << [ivar_name, default]
+    @@array_attributes << name
+    @@attributes << [name, []]
+    @@default_value[name] = []
+    code = %{
+      def #{name}
+        @#{name} ||= []
       end
+      def #{name}=(value)
+        @#{name} = Array(value)
+      end
+    }
 
-      @@attributes << [name, default]
-      @@default_value[name] = default
-      attr_accessor(name)
-    end
+    module_eval code, __FILE__, __LINE__ - 9
+  end
 
-    ##
-    # Same as :attribute, but ensures that values assigned to the attribute
-    # are array values by applying :to_a to the value.
+  ##
+  # Same as attribute above, but also records this attribute as mandatory.
 
-    def self.array_attribute(name)
-      @@non_nil_attributes << ["@#{name}".intern, []]
+  def self.required_attribute(*args)
+    @@required_attributes << args.first
+    attribute(*args)
+  end
 
-      @@array_attributes << name
-      @@attributes << [name, []]
-      @@default_value[name] = []
-      code = %{
-        def #{name}
-          @#{name} ||= []
-        end
-        def #{name}=(value)
-          @#{name} = Array(value)
-        end
-      }
+  ##
+  # Sometimes we don't want the world to use a setter method for a
+  # particular attribute.
+  #
+  # +read_only+ makes it private so we can still use it internally.
 
-      module_eval code, __FILE__, __LINE__ - 9
+  def self.read_only(*names)
+    names.each do |name|
+      private "#{name}="
     end
+  end
 
-    ##
-    # Same as attribute above, but also records this attribute as mandatory.
+  # Shortcut for creating several attributes at once (each with a default
+  # value of +nil+).
 
-    def self.required_attribute(*args)
-      @@required_attributes << args.first
-      attribute(*args)
+  def self.attributes(*args)
+    args.each do |arg|
+      attribute(arg, nil)
     end
+  end
 
-    ##
-    # Sometimes we don't want the world to use a setter method for a
-    # particular attribute.
-    #
-    # +read_only+ makes it private so we can still use it internally.
+  ##
+  # Some attributes require special behaviour when they are accessed.  This
+  # allows for that.
 
-    def self.read_only(*names)
-      names.each do |name|
-        private "#{name}="
-      end
-    end
+  def self.overwrite_accessor(name, &block)
+    remove_method name
+    define_method(name, &block)
+  end
 
-    # Shortcut for creating several attributes at once (each with a default
-    # value of +nil+).
+  ##
+  # Defines a _singular_ version of an existing _plural_ attribute (i.e. one
+  # whose value is expected to be an array).  This means just creating a
+  # helper method that takes a single value and appends it to the array.
+  # These are created for convenience, so that in a spec, one can write
+  #
+  #   s.require_path = 'mylib'
+  #
+  # instead of:
+  #
+  #   s.require_paths = ['mylib']
+  #
+  # That above convenience is available courtesy of:
+  #
+  #   attribute_alias_singular :require_path, :require_paths
 
-    def self.attributes(*args)
-      args.each do |arg|
-        attribute(arg, nil)
-      end
-    end
+  def self.attribute_alias_singular(singular, plural)
+    define_method("#{singular}=") { |val|
+      send("#{plural}=", [val])
+    }
+    define_method("#{singular}") {
+      val = send("#{plural}")
+      val.nil? ? nil : val.first
+    }
+  end
 
-    ##
-    # Some attributes require special behaviour when they are accessed.  This
-    # allows for that.
+  ##
+  # Dump only crucial instance variables.
+  #--
+  # MAINTAIN ORDER!
 
-    def self.overwrite_accessor(name, &block)
-      remove_method name
-      define_method(name, &block)
-    end
+  def _dump(limit)
+    Marshal.dump [
+      @rubygems_version,
+      @specification_version,
+      @name,
+      @version,
+      (Time === @date ? @date : (require 'time'; Time.parse(@date.to_s))),
+      @summary,
+      @required_ruby_version,
+      @required_rubygems_version,
+      @original_platform,
+      @dependencies,
+      @rubyforge_project,
+      @email,
+      @authors,
+      @description,
+      @homepage,
+      @has_rdoc,
+      @new_platform,
+      @licenses
+    ]
+  end
 
-    ##
-    # Defines a _singular_ version of an existing _plural_ attribute (i.e. one
-    # whose value is expected to be an array).  This means just creating a
-    # helper method that takes a single value and appends it to the array.
-    # These are created for convenience, so that in a spec, one can write
-    #
-    #   s.require_path = 'mylib'
-    #
-    # instead of:
-    #
-    #   s.require_paths = ['mylib']
-    #
-    # That above convenience is available courtesy of:
-    #
-    #   attribute_alias_singular :require_path, :require_paths
+  ##
+  # Load custom marshal format, re-initializing defaults as needed
 
-    def self.attribute_alias_singular(singular, plural)
-      define_method("#{singular}=") { |val|
-        send("#{plural}=", [val])
-      }
-      define_method("#{singular}") {
-        val = send("#{plural}")
-        val.nil? ? nil : val.first
-      }
-    end
+  def self._load(str)
+    array = Marshal.load str
 
-    ##
-    # Dump only crucial instance variables.
-    #--
-    # MAINTAIN ORDER!
+    spec = Gem::Specification.new
+    spec.instance_variable_set :@specification_version, array[1]
 
-    def _dump(limit)
-      Marshal.dump [
-        @rubygems_version,
-        @specification_version,
-        @name,
-        @version,
-        (Time === @date ? @date : (require 'time'; Time.parse(@date.to_s))),
-        @summary,
-        @required_ruby_version,
-        @required_rubygems_version,
-        @original_platform,
-        @dependencies,
-        @rubyforge_project,
-        @email,
-        @authors,
-        @description,
-        @homepage,
-        @has_rdoc,
-        @new_platform,
-      ]
+    current_version = CURRENT_SPECIFICATION_VERSION
+
+    field_count = if spec.specification_version > current_version then
+                    spec.instance_variable_set :@specification_version,
+                                               current_version
+                    MARSHAL_FIELDS[current_version]
+                  else
+                    MARSHAL_FIELDS[spec.specification_version]
+                  end
+
+    if array.size < field_count then
+      raise TypeError, "invalid Gem::Specification format #{array.inspect}"
     end
 
-    ##
-    # Load custom marshal format, re-initializing defaults as needed
+    spec.instance_variable_set :@rubygems_version,          array[0]
+    # spec version
+    spec.instance_variable_set :@name,                      array[2]
+    spec.instance_variable_set :@version,                   array[3]
+    spec.instance_variable_set :@date,                      array[4]
+    spec.instance_variable_set :@summary,                   array[5]
+    spec.instance_variable_set :@required_ruby_version,     array[6]
+    spec.instance_variable_set :@required_rubygems_version, array[7]
+    spec.instance_variable_set :@original_platform,         array[8]
+    spec.instance_variable_set :@dependencies,              array[9]
+    spec.instance_variable_set :@rubyforge_project,         array[10]
+    spec.instance_variable_set :@email,                     array[11]
+    spec.instance_variable_set :@authors,                   array[12]
+    spec.instance_variable_set :@description,               array[13]
+    spec.instance_variable_set :@homepage,                  array[14]
+    spec.instance_variable_set :@has_rdoc,                  array[15]
+    spec.instance_variable_set :@new_platform,              array[16]
+    spec.instance_variable_set :@platform,                  array[16].to_s
+    spec.instance_variable_set :@license,                   array[17]
+    spec.instance_variable_set :@loaded,                    false
 
-    def self._load(str)
-      array = Marshal.load str
+    spec
+  end
 
-      spec = Gem::Specification.new
-      spec.instance_variable_set :@specification_version, array[1]
+  ##
+  # List of depedencies that will automatically be activated at runtime.
 
-      current_version = CURRENT_SPECIFICATION_VERSION
+  def runtime_dependencies
+    dependencies.select { |d| d.type == :runtime || d.type == nil }
+  end
 
-      field_count = if spec.specification_version > current_version then
-                      spec.instance_variable_set :@specification_version,
-                                                 current_version
-                      MARSHAL_FIELDS[current_version]
-                    else
-                      MARSHAL_FIELDS[spec.specification_version]
-                    end
+  ##
+  # List of dependencies that are used for development
 
-      if array.size < field_count then
-        raise TypeError, "invalid Gem::Specification format #{array.inspect}"
-      end
+  def development_dependencies
+    dependencies.select { |d| d.type == :development }
+  end
 
-      spec.instance_variable_set :@rubygems_version,          array[0]
-      # spec version
-      spec.instance_variable_set :@name,                      array[2]
-      spec.instance_variable_set :@version,                   array[3]
-      spec.instance_variable_set :@date,                      array[4]
-      spec.instance_variable_set :@summary,                   array[5]
-      spec.instance_variable_set :@required_ruby_version,     array[6]
-      spec.instance_variable_set :@required_rubygems_version, array[7]
-      spec.instance_variable_set :@original_platform,         array[8]
-      spec.instance_variable_set :@dependencies,              array[9]
-      spec.instance_variable_set :@rubyforge_project,         array[10]
-      spec.instance_variable_set :@email,                     array[11]
-      spec.instance_variable_set :@authors,                   array[12]
-      spec.instance_variable_set :@description,               array[13]
-      spec.instance_variable_set :@homepage,                  array[14]
-      spec.instance_variable_set :@has_rdoc,                  array[15]
-      spec.instance_variable_set :@new_platform,              array[16]
-      spec.instance_variable_set :@platform,                  array[16].to_s
-      spec.instance_variable_set :@loaded,                    false
+  def test_suite_file # :nodoc:
+    warn 'test_suite_file deprecated, use test_files'
+    test_files.first
+  end
 
-      spec
-    end
+  def test_suite_file=(val) # :nodoc:
+    warn 'test_suite_file= deprecated, use test_files='
+    @test_files = [] unless defined? @test_files
+    @test_files << val
+  end
 
-    ##
-    # List of depedencies that will automatically be activated at runtime.
+  ##
+  # true when this gemspec has been loaded from a specifications directory.
+  # This attribute is not persisted.
 
-    def runtime_dependencies
-      dependencies.select { |d| d.type == :runtime || d.type == nil }
-    end
+  attr_accessor :loaded
 
-    ##
-    # List of dependencies that are used for development
+  ##
+  # Path this gemspec was loaded from.  This attribute is not persisted.
 
-    def development_dependencies
-      dependencies.select { |d| d.type == :development }
-    end
+  attr_accessor :loaded_from
 
-    def test_suite_file # :nodoc:
-      warn 'test_suite_file deprecated, use test_files'
-      test_files.first
+  ##
+  # Returns an array with bindir attached to each executable in the
+  # executables list
+
+  def add_bindir(executables)
+    return nil if executables.nil?
+
+    if @bindir then
+      Array(executables).map { |e| File.join(@bindir, e) }
+    else
+      executables
     end
+  rescue
+    return nil
+  end
 
-    def test_suite_file=(val) # :nodoc:
-      warn 'test_suite_file= deprecated, use test_files='
-      @test_files = [] unless defined? @test_files
-      @test_files << val
+  ##
+  # Files in the Gem under one of the require_paths
+
+  def lib_files
+    @files.select do |file|
+      require_paths.any? do |path|
+        file.index(path) == 0
+      end
     end
+  end
 
-    ##
-    # true when this gemspec has been loaded from a specifications directory.
-    # This attribute is not persisted.
+  ##
+  # True if this gem was loaded from disk
 
-    attr_accessor :loaded
+  alias :loaded? :loaded
 
-    ##
-    # Path this gemspec was loaded from.  This attribute is not persisted.
+  ##
+  # True if this gem has files in test_files
 
-    attr_accessor :loaded_from
+  def has_unit_tests?
+    not test_files.empty?
+  end
 
-    ##
-    # Returns an array with bindir attached to each executable in the
-    # executables list
+  # :stopdoc:
+  alias has_test_suite? has_unit_tests?
+  # :startdoc:
 
-    def add_bindir(executables)
-      return nil if executables.nil?
+  ##
+  # Specification constructor.  Assigns the default values to the attributes
+  # and yields itself for further initialization.
 
-      if @bindir then
-        Array(executables).map { |e| File.join(@bindir, e) }
-      else
-        executables
-      end
-    rescue
-      return nil
-    end
+  def initialize
+    @new_platform = nil
+    assign_defaults
+    @loaded = false
+    @loaded_from = nil
 
-    ##
-    # Files in the Gem under one of the require_paths
+    yield self if block_given?
 
-    def lib_files
-      @files.select do |file|
-        require_paths.any? do |path|
-          file.index(path) == 0
-        end
-      end
-    end
+    @@gather.call(self) if @@gather
+  end
 
-    ##
-    # True if this gem was loaded from disk
+  ##
+  # Duplicates array_attributes from +other_spec+ so state isn't shared.
 
-    alias :loaded? :loaded
+  def initialize_copy(other_spec)
+    other_ivars = other_spec.instance_variables
+    other_ivars = other_ivars.map { |ivar| ivar.intern } if # for 1.9
+      other_ivars.any? { |ivar| String === ivar }
 
-    ##
-    # True if this gem has files in test_files
-
-    def has_unit_tests?
-      not test_files.empty?
+    self.class.array_attributes.each do |name|
+      name = :"@#{name}"
+      next unless other_ivars.include? name
+      instance_variable_set name, other_spec.instance_variable_get(name).dup
     end
+  end
 
-    alias has_test_suite? has_unit_tests? # :nodoc: deprecated
+  ##
+  # Each attribute has a default value (possibly nil).  Here, we initialize
+  # all attributes to their default value.  This is done through the
+  # accessor methods, so special behaviours will be honored.  Furthermore,
+  # we take a _copy_ of the default so each specification instance has its
+  # own empty arrays, etc.
 
-    ##
-    # Specification constructor.  Assigns the default values to the
-    # attributes, adds this spec to the list of loaded specs (see
-    # Specification.list), and yields itself for further initialization.
+  def assign_defaults
+    @@nil_attributes.each do |name|
+      instance_variable_set name, nil
+    end
 
-    def initialize
-      @new_platform = nil
-      assign_defaults
-      @loaded = false
-      @loaded_from = nil
-      @@list << self
+    @@non_nil_attributes.each do |name, default|
+      value = case default
+              when Time, Numeric, Symbol, true, false, nil then default
+              else default.dup
+              end
 
-      yield self if block_given?
-
-      @@gather.call(self) if @@gather
+      instance_variable_set name, value
     end
 
-    ##
-    # Each attribute has a default value (possibly nil).  Here, we initialize
-    # all attributes to their default value.  This is done through the
-    # accessor methods, so special behaviours will be honored.  Furthermore,
-    # we take a _copy_ of the default so each specification instance has its
-    # own empty arrays, etc.
+    # HACK
+    instance_variable_set :@new_platform, Gem::Platform::RUBY
+  end
 
-    def assign_defaults
-      @@nil_attributes.each do |name|
-        instance_variable_set name, nil
-      end
+  ##
+  # Special loader for YAML files.  When a Specification object is loaded
+  # from a YAML file, it bypasses the normal Ruby object initialization
+  # routine (#initialize).  This method makes up for that and deals with
+  # gems of different ages.
+  #
+  # 'input' can be anything that YAML.load() accepts: String or IO.
 
-      @@non_nil_attributes.each do |name, default|
-        value = case default
-                when Time, Numeric, Symbol, true, false, nil then default
-                else default.dup
-                end
+  def self.from_yaml(input)
+    input = normalize_yaml_input input
+    spec = YAML.load input
 
-        instance_variable_set name, value
-      end
+    if spec && spec.class == FalseClass then
+      raise Gem::EndOfYAMLException
+    end
 
-      # HACK
-      instance_variable_set :@new_platform, Gem::Platform::RUBY
+    unless Gem::Specification === spec then
+      raise Gem::Exception, "YAML data doesn't evaluate to gem specification"
     end
 
-    ##
-    # Special loader for YAML files.  When a Specification object is loaded
-    # from a YAML file, it bypasses the normal Ruby object initialization
-    # routine (#initialize).  This method makes up for that and deals with
-    # gems of different ages.
-    #
-    # 'input' can be anything that YAML.load() accepts: String or IO.
+    unless (spec.instance_variables.include? '@specification_version' or
+            spec.instance_variables.include? :@specification_version) and
+           spec.instance_variable_get :@specification_version
+      spec.instance_variable_set :@specification_version,
+                                 NONEXISTENT_SPECIFICATION_VERSION
+    end
 
-    def self.from_yaml(input)
-      input = normalize_yaml_input input
-      spec = YAML.load input
+    spec
+  end
 
-      if spec && spec.class == FalseClass then
-        raise Gem::EndOfYAMLException
-      end
+  ##
+  # Loads ruby format gemspec from +filename+
 
-      unless Gem::Specification === spec then
-        raise Gem::Exception, "YAML data doesn't evaluate to gem specification"
-      end
+  def self.load(filename)
+    gemspec = nil
+    fail "NESTED Specification.load calls not allowed!" if @@gather
+    @@gather = proc { |gs| gemspec = gs }
+    data = File.read(filename)
+    eval(data)
+    gemspec
+  ensure
+    @@gather = nil
+  end
 
-      unless (spec.instance_variables.include? '@specification_version' or
-              spec.instance_variables.include? :@specification_version) and
-             spec.instance_variable_get :@specification_version
-        spec.instance_variable_set :@specification_version,
-                                   NONEXISTENT_SPECIFICATION_VERSION
-      end
+  ##
+  # Make sure the YAML specification is properly formatted with dashes
 
-      spec
-    end
+  def self.normalize_yaml_input(input)
+    result = input.respond_to?(:read) ? input.read : input
+    result = "--- " + result unless result =~ /^--- /
+    result
+  end
 
-    ##
-    # Loads ruby format gemspec from +filename+
+  ##
+  # Sets the rubygems_version to the current RubyGems version
 
-    def self.load(filename)
-      gemspec = nil
-      fail "NESTED Specification.load calls not allowed!" if @@gather
-      @@gather = proc { |gs| gemspec = gs }
-      data = File.read(filename)
-      eval(data)
-      gemspec
-    ensure
-      @@gather = nil
-    end
+  def mark_version
+    @rubygems_version = Gem::RubyGemsVersion
+  end
 
-    ##
-    # Make sure the YAML specification is properly formatted with dashes
+  ##
+  # Ignore unknown attributes while loading
 
-    def self.normalize_yaml_input(input)
-      result = input.respond_to?(:read) ? input.read : input
-      result = "--- " + result unless result =~ /^--- /
-      result
+  def method_missing(sym, *a, &b) # :nodoc:
+    if @specification_version > CURRENT_SPECIFICATION_VERSION and
+      sym.to_s =~ /=$/ then
+      warn "ignoring #{sym} loading #{full_name}" if $DEBUG
+    else
+      super
     end
+  end
 
-    ##
-    # Sets the rubygems_version to the current RubyGems version
+  ##
+  # Adds a development dependency named +gem+ with +requirements+ to this
+  # Gem.  For example:
+  #
+  #   spec.add_development_dependency 'jabber4r', '> 0.1', '<= 0.5'
+  #
+  # Development dependencies aren't installed by default and aren't
+  # activated when a gem is required.
 
-    def mark_version
-      @rubygems_version = RubyGemsVersion
-    end
+  def add_development_dependency(gem, *requirements)
+    add_dependency_with_type(gem, :development, *requirements)
+  end
 
-    ##
-    # Ignore unknown attributes while loading
+  ##
+  # Adds a runtime dependency named +gem+ with +requirements+ to this Gem.
+  # For example:
+  #
+  #   spec.add_runtime_dependency 'jabber4r', '> 0.1', '<= 0.5'
 
-    def method_missing(sym, *a, &b) # :nodoc:
-      if @specification_version > CURRENT_SPECIFICATION_VERSION and
-         sym.to_s =~ /=$/ then
-        warn "ignoring #{sym} loading #{full_name}" if $DEBUG
-      else
-        super
-      end
-    end
+  def add_runtime_dependency(gem, *requirements)
+    add_dependency_with_type(gem, :runtime, *requirements)
+  end
 
-    ##
-    # Adds a development dependency named +gem+ with +requirements+ to this
-    # Gem.  For example:
-    #
-    #   spec.add_development_dependency 'jabber4r', '> 0.1', '<= 0.5'
-    #
-    # Development dependencies aren't installed by default and aren't
-    # activated when a gem is required.
+  ##
+  # Adds a runtime dependency
 
-    def add_development_dependency(gem, *requirements)
-      add_dependency_with_type(gem, :development, *requirements)
+  alias add_dependency add_runtime_dependency
+
+  ##
+  # Returns the full name (name-version) of this Gem.  Platform information
+  # is included (name-version-platform) if it is specified and not the
+  # default Ruby platform.
+
+  def full_name
+    if platform == Gem::Platform::RUBY or platform.nil? then
+      "#{@name}-#{@version}"
+    else
+      "#{@name}-#{@version}-#{platform}"
     end
+  end
 
-    ##
-    # Adds a runtime dependency named +gem+ with +requirements+ to this Gem.
-    # For example:
-    #
-    #   spec.add_runtime_dependency 'jabber4r', '> 0.1', '<= 0.5'
+  ##
+  # Returns the full name (name-version) of this gemspec using the original
+  # platform.  For use with legacy gems.
 
-    def add_runtime_dependency(gem, *requirements)
-      add_dependency_with_type(gem, :runtime, *requirements)
+  def original_name # :nodoc:
+    if platform == Gem::Platform::RUBY or platform.nil? then
+      "#{@name}-#{@version}"
+    else
+      "#{@name}-#{@version}-#{@original_platform}"
     end
+  end
 
-    ##
-    # Adds a runtime dependency
+  ##
+  # The full path to the gem (install path + full name).
 
-    alias add_dependency add_runtime_dependency
+  def full_gem_path
+    path = File.join installation_path, 'gems', full_name
+    return path if File.directory? path
+    File.join installation_path, 'gems', original_name
+  end
 
-    ##
-    # Returns the full name (name-version) of this Gem.  Platform information
-    # is included (name-version-platform) if it is specified and not the
-    # default Ruby platform.
+  ##
+  # The default (generated) file name of the gem.
 
-    def full_name
-      if platform == Gem::Platform::RUBY or platform.nil? then
-        "#{@name}-#{@version}"
-      else
-        "#{@name}-#{@version}-#{platform}"
-      end
-    end
+  def file_name
+    full_name + ".gem"
+  end
 
-    ##
-    # Returns the full name (name-version) of this gemspec using the original
-    # platform.  For use with legacy gems.
+  ##
+  # The directory that this gem was installed into.
 
-    def original_name # :nodoc:
-      if platform == Gem::Platform::RUBY or platform.nil? then
-        "#{@name}-#{@version}"
-      else
-        "#{@name}-#{@version}-#{@original_platform}"
-      end
+  def installation_path
+    unless @loaded_from then
+      raise Gem::Exception, "spec #{full_name} is not from an installed gem"
     end
 
-    ##
-    # The full path to the gem (install path + full name).
+    File.expand_path File.dirname(File.dirname(@loaded_from))
+  end
 
-    def full_gem_path
-      path = File.join installation_path, 'gems', full_name
-      return path if File.directory? path
-      File.join installation_path, 'gems', original_name
-    end
+  ##
+  # Checks if this specification meets the requirement of +dependency+.
 
-    ##
-    # The default (generated) file name of the gem.
+  def satisfies_requirement?(dependency)
+    return @name == dependency.name &&
+      dependency.version_requirements.satisfied_by?(@version)
+  end
 
-    def file_name
-      full_name + ".gem"
-    end
+  ##
+  # Returns an object you can use to sort specifications in #sort_by.
 
-    ##
-    # The directory that this gem was installed into.
+  def sort_obj
+    [@name, @version, @new_platform == Gem::Platform::RUBY ? -1 : 1]
+  end
 
-    def installation_path
-      path = File.dirname(@loaded_from).split(File::SEPARATOR)[0..-2]
-      path = path.join File::SEPARATOR
-      File.expand_path path
-    end
+  def <=>(other) # :nodoc:
+    sort_obj <=> other.sort_obj
+  end
 
-    ##
-    # Checks if this specification meets the requirement of +dependency+.
+  ##
+  # Tests specs for equality (across all attributes).
 
-    def satisfies_requirement?(dependency)
-      return @name == dependency.name &&
-        dependency.version_requirements.satisfied_by?(@version)
-    end
+  def ==(other) # :nodoc:
+    self.class === other && same_attributes?(other)
+  end
 
-    ##
-    # Returns an object you can use to sort specifications in #sort_by.
+  alias eql? == # :nodoc:
 
-    def sort_obj
-      [@name, @version.to_ints, @new_platform == Gem::Platform::RUBY ? -1 : 1]
-    end
+  ##
+  # True if this gem has the same attributes as +other+.
 
-    def <=>(other) # :nodoc:
-      sort_obj <=> other.sort_obj
+  def same_attributes?(other)
+    @@attributes.each do |name, default|
+      return false unless self.send(name) == other.send(name)
     end
+    true
+  end
 
-    ##
-    # Tests specs for equality (across all attributes).
+  private :same_attributes?
 
-    def ==(other) # :nodoc:
-      self.class === other && same_attributes?(other)
-    end
+  def hash # :nodoc:
+    @@attributes.inject(0) { |hash_code, (name, default_value)|
+      n = self.send(name).hash
+      hash_code + n
+    }
+  end
 
-    alias eql? == # :nodoc:
+  def to_yaml(opts = {}) # :nodoc:
+    mark_version
 
-    ##
-    # True if this gem has the same attributes as +other+.
+    attributes = @@attributes.map { |name,| name.to_s }.sort
+    attributes = attributes - %w[name version platform]
 
-    def same_attributes?(other)
-      @@attributes.each do |name, default|
-        return false unless self.send(name) == other.send(name)
+    yaml = YAML.quick_emit object_id, opts do |out|
+      out.map taguri, to_yaml_style do |map|
+        map.add 'name', @name
+        map.add 'version', @version
+        platform = case @original_platform
+                   when nil, '' then
+                     'ruby'
+                   when String then
+                     @original_platform
+                   else
+                     @original_platform.to_s
+                   end
+        map.add 'platform', platform
+
+        attributes.each do |name|
+          map.add name, instance_variable_get("@#{name}")
+        end
       end
-      true
     end
+  end
 
-    private :same_attributes?
-
-    def hash # :nodoc:
-      @@attributes.inject(0) { |hash_code, (name, default_value)|
-        n = self.send(name).hash
-        hash_code + n
-      }
+  def yaml_initialize(tag, vals) # :nodoc:
+    vals.each do |ivar, val|
+      instance_variable_set "@#{ivar}", val
     end
 
-    def to_yaml(opts = {}) # :nodoc:
-      mark_version
+    @original_platform = @platform # for backwards compatibility
+    self.platform = Gem::Platform.new @platform
+  end
 
-      attributes = @@attributes.map { |name,| name.to_s }.sort
-      attributes = attributes - %w[name version platform]
+  ##
+  # Returns a Ruby code representation of this specification, such that it
+  # can be eval'ed and reconstruct the same specification later.  Attributes
+  # that still have their default values are omitted.
 
-      yaml = YAML.quick_emit object_id, opts do |out|
-        out.map taguri, to_yaml_style do |map|
-          map.add 'name', @name
-          map.add 'version', @version
-          platform = case @original_platform
-                     when nil, '' then
-                       'ruby'
-                     when String then
-                       @original_platform
-                     else
-                       @original_platform.to_s
-                     end
-          map.add 'platform', platform
+  def to_ruby
+    mark_version
+    result = []
+    result << "# -*- encoding: utf-8 -*-"
+    result << nil
+    result << "Gem::Specification.new do |s|"
 
-          attributes.each do |name|
-            map.add name, instance_variable_get("@#{name}")
-          end
-        end
-      end
+    result << "  s.name = #{ruby_code name}"
+    result << "  s.version = #{ruby_code version}"
+    unless platform.nil? or platform == Gem::Platform::RUBY then
+      result << "  s.platform = #{ruby_code original_platform}"
     end
+    result << ""
+    result << "  s.required_rubygems_version = #{ruby_code required_rubygems_version} if s.respond_to? :required_rubygems_version="
 
-    def yaml_initialize(tag, vals) # :nodoc:
-      vals.each do |ivar, val|
-        instance_variable_set "@#{ivar}", val
+    handled = [
+      :dependencies,
+      :name,
+      :platform,
+      :required_rubygems_version,
+      :specification_version,
+      :version,
+    ]
+
+    attributes = @@attributes.sort_by { |attr_name,| attr_name.to_s }
+
+    attributes.each do |attr_name, default|
+      next if handled.include? attr_name
+      current_value = self.send(attr_name)
+      if current_value != default or
+         self.class.required_attribute? attr_name then
+        result << "  s.#{attr_name} = #{ruby_code current_value}"
       end
-
-      @original_platform = @platform # for backwards compatibility
-      self.platform = Gem::Platform.new @platform
     end
 
-    ##
-    # Returns a Ruby code representation of this specification, such that it
-    # can be eval'ed and reconstruct the same specification later.  Attributes
-    # that still have their default values are omitted.
+    result << nil
+    result << "  if s.respond_to? :specification_version then"
+    result << "    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION"
+    result << "    s.specification_version = #{specification_version}"
+    result << nil
 
-    def to_ruby
-      mark_version
-      result = []
-      result << "# -*- encoding: utf-8 -*-"
-      result << nil
-      result << "Gem::Specification.new do |s|"
+    result << "    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then"
 
-      result << "  s.name = #{ruby_code name}"
-      result << "  s.version = #{ruby_code version}"
-      unless platform.nil? or platform == Gem::Platform::RUBY then
-        result << "  s.platform = #{ruby_code original_platform}"
+    unless dependencies.empty? then
+      dependencies.each do |dep|
+        version_reqs_param = dep.requirements_list.inspect
+        dep.instance_variable_set :@type, :runtime if dep.type.nil? # HACK
+        result << "      s.add_#{dep.type}_dependency(%q<#{dep.name}>, #{version_reqs_param})"
       end
-      result << ""
-      result << "  s.required_rubygems_version = #{ruby_code required_rubygems_version} if s.respond_to? :required_rubygems_version="
+    end
 
-      handled = [
-        :dependencies,
-        :name,
-        :platform,
-        :required_rubygems_version,
-        :specification_version,
-        :version,
-      ]
+    result << "    else"
 
-      attributes = @@attributes.sort_by { |attr_name,| attr_name.to_s }
+    unless dependencies.empty? then
+      dependencies.each do |dep|
+        version_reqs_param = dep.requirements_list.inspect
+        result << "      s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
+      end
+    end
 
-      attributes.each do |attr_name, default|
-        next if handled.include? attr_name
-        current_value = self.send(attr_name)
-        if current_value != default or
-           self.class.required_attribute? attr_name then
-          result << "  s.#{attr_name} = #{ruby_code current_value}"
-        end
+    result << '    end'
+
+    result << "  else"
+      dependencies.each do |dep|
+        version_reqs_param = dep.requirements_list.inspect
+        result << "    s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
       end
+    result << "  end"
 
-      result << nil
-      result << "  if s.respond_to? :specification_version then"
-      result << "    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION"
-      result << "    s.specification_version = #{specification_version}"
-      result << nil
+    result << "end"
+    result << nil
 
-      result << "    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then"
+    result.join "\n"
+  end
 
-      unless dependencies.empty? then
-        dependencies.each do |dep|
-          version_reqs_param = dep.requirements_list.inspect
-          dep.instance_variable_set :@type, :runtime if dep.type.nil? # HACK
-          result << "      s.add_#{dep.type}_dependency(%q<#{dep.name}>, #{version_reqs_param})"
-        end
-      end
+  ##
+  # Checks that the specification contains all required fields, and does a
+  # very basic sanity check.
+  #
+  # Raises InvalidSpecificationException if the spec does not pass the
+  # checks..
 
-      result << "    else"
+  def validate
+    extend Gem::UserInteraction
+    normalize
 
-      unless dependencies.empty? then
-        dependencies.each do |dep|
-          version_reqs_param = dep.requirements_list.inspect
-          result << "      s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
-        end
+    if rubygems_version != Gem::RubyGemsVersion then
+      raise Gem::InvalidSpecificationException,
+            "expected RubyGems version #{Gem::RubyGemsVersion}, was #{rubygems_version}"
+    end
+
+    @@required_attributes.each do |symbol|
+      unless self.send symbol then
+        raise Gem::InvalidSpecificationException,
+              "missing value for attribute #{symbol}"
       end
+    end
 
-      result << '    end'
+    unless String === name then
+      raise Gem::InvalidSpecificationException,
+            "invalid value for attribute name: \"#{name.inspect}\""
+    end
 
-      result << "  else"
-        dependencies.each do |dep|
-          version_reqs_param = dep.requirements_list.inspect
-          result << "    s.add_dependency(%q<#{dep.name}>, #{version_reqs_param})"
-        end
-      result << "  end"
+    if require_paths.empty? then
+      raise Gem::InvalidSpecificationException,
+            'specification must have at least one require_path'
+    end
 
-      result << "end"
-      result << nil
+    @files.delete_if            do |file| File.directory? file end
+    @test_files.delete_if       do |file| File.directory? file end
+    @executables.delete_if      do |file|
+      File.directory? File.join(bindir, file)
+    end
+    @extra_rdoc_files.delete_if do |file| File.directory? file end
+    @extensions.delete_if       do |file| File.directory? file end
 
-      result.join "\n"
+    non_files = files.select do |file|
+      !File.file? file
     end
 
-    ##
-    # Checks that the specification contains all required fields, and does a
-    # very basic sanity check.
-    #
-    # Raises InvalidSpecificationException if the spec does not pass the
-    # checks..
+    unless non_files.empty? then
+      non_files = non_files.map { |file| file.inspect }
+      raise Gem::InvalidSpecificationException,
+            "[#{non_files.join ", "}] are not files"
+    end
 
-    def validate
-      extend Gem::UserInteraction
-      normalize
+    unless specification_version.is_a?(Fixnum)
+      raise Gem::InvalidSpecificationException,
+            'specification_version must be a Fixnum (did you mean version?)'
+    end
 
-      if rubygems_version != RubyGemsVersion then
-        raise Gem::InvalidSpecificationException,
-              "expected RubyGems version #{RubyGemsVersion}, was #{rubygems_version}"
-      end
+    case platform
+    when Gem::Platform, Gem::Platform::RUBY then # ok
+    else
+      raise Gem::InvalidSpecificationException,
+            "invalid platform #{platform.inspect}, see Gem::Platform"
+    end
 
-      @@required_attributes.each do |symbol|
-        unless self.send symbol then
-          raise Gem::InvalidSpecificationException,
-                "missing value for attribute #{symbol}"
-        end
-      end
+    unless Array === authors and
+           authors.all? { |author| String === author } then
+      raise Gem::InvalidSpecificationException,
+            'authors must be Array of Strings'
+    end
 
-      if require_paths.empty? then
+    licenses.each { |license|
+      if license.length > 64
         raise Gem::InvalidSpecificationException,
-              "specification must have at least one require_path"
+          "each license must be 64 characters or less"
       end
+    }
 
-      case platform
-      when Gem::Platform, Platform::RUBY then # ok
-      else
-        raise Gem::InvalidSpecificationException,
-              "invalid platform #{platform.inspect}, see Gem::Platform"
-      end
+    # reject FIXME and TODO
 
-      unless Array === authors and
-             authors.all? { |author| String === author } then
-        raise Gem::InvalidSpecificationException,
-              'authors must be Array of Strings'
-      end
+    unless authors.grep(/FIXME|TODO/).empty? then
+      raise Gem::InvalidSpecificationException,
+            '"FIXME" or "TODO" is not an author'
+    end
 
-      # Warnings
+    unless Array(email).grep(/FIXME|TODO/).empty? then
+      raise Gem::InvalidSpecificationException,
+            '"FIXME" or "TODO" is not an email address'
+    end
 
-      %w[author email homepage rubyforge_project summary].each do |attribute|
-        value = self.send attribute
-        alert_warning "no #{attribute} specified" if value.nil? or value.empty?
-      end
+    if description =~ /FIXME|TODO/ then
+      raise Gem::InvalidSpecificationException,
+            '"FIXME" or "TODO" is not a description'
+    end
 
-      alert_warning "RDoc will not be generated (has_rdoc == false)" unless
-        has_rdoc
+    if summary =~ /FIXME|TODO/ then
+      raise Gem::InvalidSpecificationException,
+            '"FIXME" or "TODO" is not a summary'
+    end
 
-      alert_warning "deprecated autorequire specified" if autorequire
+    if homepage and not homepage.empty? and
+       homepage !~ /\A[a-z][a-z\d+.-]*:/i then
+      raise Gem::InvalidSpecificationException,
+            "\"#{homepage}\" is not a URI"
+    end
 
-      executables.each do |executable|
-        executable_path = File.join bindir, executable
-        shebang = File.read(executable_path, 2) == '#!'
+    # Warnings
 
-        alert_warning "#{executable_path} is missing #! line" unless shebang
-      end
+    %w[author description email homepage rubyforge_project summary].each do |attribute|
+      value = self.send attribute
+      alert_warning "no #{attribute} specified" if value.nil? or value.empty?
+    end
 
-      true
+    if summary and not summary.empty? and description == summary then
+      alert_warning 'description and summary are identical'
     end
 
-    ##
-    # Normalize the list of files so that:
-    # * All file lists have redundancies removed.
-    # * Files referenced in the extra_rdoc_files are included in the package
-    #   file list.
-    #
-    # Also, the summary and description are converted to a normal format.
+    alert_warning "deprecated autorequire specified" if autorequire
 
-    def normalize
-      if defined?(@extra_rdoc_files) and @extra_rdoc_files then
-        @extra_rdoc_files.uniq!
-        @files ||= []
-        @files.concat(@extra_rdoc_files)
-      end
-      @files.uniq! if @files
+    executables.each do |executable|
+      executable_path = File.join bindir, executable
+      shebang = File.read(executable_path, 2) == '#!'
+
+      alert_warning "#{executable_path} is missing #! line" unless shebang
     end
 
-    ##
-    # Return a list of all gems that have a dependency on this gemspec.  The
-    # list is structured with entries that conform to:
-    #
-    #   [depending_gem, dependency, [list_of_gems_that_satisfy_dependency]]
+    true
+  end
 
-    def dependent_gems
-      out = []
-      Gem.source_index.each do |name,gem|
-        gem.dependencies.each do |dep|
-          if self.satisfies_requirement?(dep) then
-            sats = []
-            find_all_satisfiers(dep) do |sat|
-              sats << sat
-            end
-            out << [gem, dep, sats]
+  ##
+  # Normalize the list of files so that:
+  # * All file lists have redundancies removed.
+  # * Files referenced in the extra_rdoc_files are included in the package
+  #   file list.
+
+  def normalize
+    if defined?(@extra_rdoc_files) and @extra_rdoc_files then
+      @extra_rdoc_files.uniq!
+      @files ||= []
+      @files.concat(@extra_rdoc_files)
+    end
+    @files.uniq! if @files
+  end
+
+  ##
+  # Return a list of all gems that have a dependency on this gemspec.  The
+  # list is structured with entries that conform to:
+  #
+  #   [depending_gem, dependency, [list_of_gems_that_satisfy_dependency]]
+
+  def dependent_gems
+    out = []
+    Gem.source_index.each do |name,gem|
+      gem.dependencies.each do |dep|
+        if self.satisfies_requirement?(dep) then
+          sats = []
+          find_all_satisfiers(dep) do |sat|
+            sats << sat
           end
+          out << [gem, dep, sats]
         end
       end
-      out
     end
+    out
+  end
 
-    def to_s
-      "#<Gem::Specification name=#{@name} version=#{@version}>"
-    end
+  def to_s # :nodoc:
+    "#<Gem::Specification name=#{@name} version=#{@version}>"
+  end
 
-    def add_dependency_with_type(dependency, type, *requirements)
-      requirements = if requirements.empty? then
-                       Gem::Requirement.default
-                     else
-                       requirements.flatten
-                     end
+  def pretty_print(q) # :nodoc:
+    q.group 2, 'Gem::Specification.new do |s|', 'end' do
+      q.breakable
 
-      unless dependency.respond_to?(:name) &&
-        dependency.respond_to?(:version_requirements)
+      attributes = @@attributes.sort_by { |attr_name,| attr_name.to_s }
 
-        dependency = Dependency.new(dependency, requirements, type)
-      end
+      attributes.each do |attr_name, default|
+        current_value = self.send attr_name
+        if current_value != default or
+           self.class.required_attribute? attr_name then
 
-      dependencies << dependency
-    end
+          q.text "s.#{attr_name} = "
 
-    private :add_dependency_with_type
+          if attr_name == :date then
+            current_value = current_value.utc
 
-    def find_all_satisfiers(dep)
-      Gem.source_index.each do |name,gem|
-        if(gem.satisfies_requirement?(dep)) then
-          yield gem
+            q.text "Time.utc(#{current_value.year}, #{current_value.month}, #{current_value.day})"
+          else
+            q.pp current_value
+          end
+
+          q.breakable
         end
       end
     end
+  end
 
-    private :find_all_satisfiers
+  ##
+  # Adds a dependency on gem +dependency+ with type +type+ that requires
+  # +requirements+.  Valid types are currently <tt>:runtime</tt> and
+  # <tt>:development</tt>.
 
-    ##
-    # Return a string containing a Ruby code representation of the given
-    # object.
+  def add_dependency_with_type(dependency, type, *requirements)
+    requirements = if requirements.empty? then
+                     Gem::Requirement.default
+                   else
+                     requirements.flatten
+                   end
 
-    def ruby_code(obj)
-      case obj
-      when String            then '%q{' + obj + '}'
-      when Array             then obj.inspect
-      when Gem::Version      then obj.to_s.inspect
-      when Date              then '%q{' + obj.strftime('%Y-%m-%d') + '}'
-      when Time              then '%q{' + obj.strftime('%Y-%m-%d') + '}'
-      when Numeric           then obj.inspect
-      when true, false, nil  then obj.inspect
-      when Gem::Platform     then "Gem::Platform.new(#{obj.to_a.inspect})"
-      when Gem::Requirement  then "Gem::Requirement.new(#{obj.to_s.inspect})"
-      else raise Exception, "ruby_code case not handled: #{obj.class}"
-      end
+    unless dependency.respond_to?(:name) &&
+      dependency.respond_to?(:version_requirements)
+
+      dependency = Gem::Dependency.new(dependency, requirements, type)
     end
 
-    private :ruby_code
+    dependencies << dependency
+  end
 
-    # :section: Required gemspec attributes
+  private :add_dependency_with_type
 
-    ##
-    # The version of RubyGems used to create this gem
+  ##
+  # Finds all gems that satisfy +dep+
 
-    required_attribute :rubygems_version, Gem::RubyGemsVersion
+  def find_all_satisfiers(dep)
+    Gem.source_index.each do |_, gem|
+      yield gem if gem.satisfies_requirement? dep
+    end
+  end
 
-    ##
-    # The Gem::Specification version of this gemspec
+  private :find_all_satisfiers
 
-    required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION
+  ##
+  # Return a string containing a Ruby code representation of the given
+  # object.
 
-    ##
-    # This gem's name
+  def ruby_code(obj)
+    case obj
+    when String            then '%q{' + obj + '}'
+    when Array             then obj.inspect
+    when Gem::Version      then obj.to_s.inspect
+    when Date              then '%q{' + obj.strftime('%Y-%m-%d') + '}'
+    when Time              then '%q{' + obj.strftime('%Y-%m-%d') + '}'
+    when Numeric           then obj.inspect
+    when true, false, nil  then obj.inspect
+    when Gem::Platform     then "Gem::Platform.new(#{obj.to_a.inspect})"
+    when Gem::Requirement  then "Gem::Requirement.new(#{obj.to_s.inspect})"
+    else raise Gem::Exception, "ruby_code case not handled: #{obj.class}"
+    end
+  end
 
-    required_attribute :name
+  private :ruby_code
 
-    ##
-    # This gem's version
+  # :section: Required gemspec attributes
 
-    required_attribute :version
+  ##
+  # :attr_accessor: rubygems_version
+  #
+  # The version of RubyGems used to create this gem
 
-    ##
-    # The date this gem was created
+  required_attribute :rubygems_version, Gem::RubyGemsVersion
 
-    required_attribute :date, TODAY
+  ##
+  # :attr_accessor: specification_version
+  #
+  # The Gem::Specification version of this gemspec
 
-    ##
-    # A short summary of this gem's description.  Displayed in `gem list -d`.
+  required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION
 
-    required_attribute :summary
+  ##
+  # :attr_accessor: name
+  #
+  # This gem's name
 
-    ##
-    # Paths in the gem to add to $LOAD_PATH when this gem is activated
+  required_attribute :name
 
-    required_attribute :require_paths, ['lib']
+  ##
+  # :attr_accessor: version
+  #
+  # This gem's version
 
-    # :section: Optional gemspec attributes
+  required_attribute :version
 
-    ##
-    # A contact email for this gem
+  ##
+  # :attr_accessor: date
+  #
+  # The date this gem was created
 
-    attribute :email
+  required_attribute :date, TODAY
 
-    ##
-    # The URL of this gem's home page
+  ##
+  # :attr_accessor: summary
+  #
+  # A short summary of this gem's description.  Displayed in `gem list -d`.
 
-    attribute :homepage
+  required_attribute :summary
 
-    ##
-    # The rubyforge project this gem lives under.  i.e. RubyGems'
-    # rubyforge_project is "rubygems".
+  ##
+  # :attr_accessor: require_paths
+  #
+  # Paths in the gem to add to $LOAD_PATH when this gem is activated
 
-    attribute :rubyforge_project
+  required_attribute :require_paths, ['lib']
 
-    ##
-    # A long description of this gem
+  # :section: Optional gemspec attributes
 
-    attribute :description
+  ##
+  # :attr_accessor: email
+  #
+  # A contact email for this gem
 
-    ##
-    # Autorequire was used by old RubyGems to automatically require a file.
-    # It no longer is supported.
+  attribute :email
 
-    attribute :autorequire
+  ##
+  # :attr_accessor: homepage
+  #
+  # The URL of this gem's home page
 
-    ##
-    # The default executable for this gem.
+  attribute :homepage
 
-    attribute :default_executable
+  ##
+  # :attr_accessor: rubyforge_project
+  #
+  # The rubyforge project this gem lives under.  i.e. RubyGems'
+  # rubyforge_project is "rubygems".
 
-    ##
-    # The path in the gem for executable scripts
+  attribute :rubyforge_project
 
-    attribute :bindir, 'bin'
+  ##
+  # :attr_accessor: description
+  #
+  # A long description of this gem
 
-    ##
-    # True if this gem is RDoc-compliant
+  attribute :description
 
-    attribute :has_rdoc, false
+  ##
+  # :attr_accessor: autorequire
+  #
+  # Autorequire was used by old RubyGems to automatically require a file.
+  # It no longer is supported.
 
-    ##
-    # True if this gem supports RDoc
+  attribute :autorequire
 
-    alias :has_rdoc? :has_rdoc
+  ##
+  # :attr_accessor: default_executable
+  #
+  # The default executable for this gem.
 
-    ##
-    # The ruby of version required by this gem
+  attribute :default_executable
 
-    attribute :required_ruby_version, Gem::Requirement.default
+  ##
+  # :attr_accessor: bindir
+  #
+  # The path in the gem for executable scripts
 
-    ##
-    # The RubyGems version required by this gem
+  attribute :bindir, 'bin'
 
-    attribute :required_rubygems_version, Gem::Requirement.default
+  ##
+  # :attr_accessor: has_rdoc
+  #
+  # Deprecated and ignored, defaults to true.
+  #
+  # Formerly used to indicate this gem was RDoc-capable.
 
-    ##
-    # The platform this gem runs on.  See Gem::Platform for details.
+  attribute :has_rdoc, true
 
-    attribute :platform, Gem::Platform::RUBY
+  ##
+  # True if this gem supports RDoc
 
-    ##
-    # The key used to sign this gem.  See Gem::Security for details.
+  alias :has_rdoc? :has_rdoc
 
-    attribute :signing_key, nil
+  ##
+  # :attr_accessor: required_ruby_version
+  #
+  # The ruby of version required by this gem
 
-    ##
-    # The certificate chain used to sign this gem.  See Gem::Security for
-    # details.
+  attribute :required_ruby_version, Gem::Requirement.default
 
-    attribute :cert_chain, []
+  ##
+  # :attr_accessor: required_rubygems_version
+  #
+  # The RubyGems version required by this gem
 
-    ##
-    # A message that gets displayed after the gem is installed
+  attribute :required_rubygems_version, Gem::Requirement.default
 
-    attribute :post_install_message, nil
+  ##
+  # :attr_accessor: platform
+  #
+  # The platform this gem runs on.  See Gem::Platform for details.
 
-    ##
-    # The list of authors who wrote this gem
+  attribute :platform, Gem::Platform::RUBY
 
-    array_attribute :authors
+  ##
+  # :attr_accessor: signing_key
+  #
+  # The key used to sign this gem.  See Gem::Security for details.
 
-    ##
-    # Files included in this gem
+  attribute :signing_key, nil
 
-    array_attribute :files
+  ##
+  # :attr_accessor: cert_chain
+  #
+  # The certificate chain used to sign this gem.  See Gem::Security for
+  # details.
 
-    ##
-    # Test files included in this gem
+  attribute :cert_chain, []
 
-    array_attribute :test_files
+  ##
+  # :attr_accessor: post_install_message
+  #
+  # A message that gets displayed after the gem is installed
 
-    ##
-    # An ARGV-style array of options to RDoc
+  attribute :post_install_message, nil
 
-    array_attribute :rdoc_options
+  ##
+  # :attr_accessor: authors
+  #
+  # The list of authors who wrote this gem
 
-    ##
-    # Extra files to add to RDoc
+  array_attribute :authors
 
-    array_attribute :extra_rdoc_files
+  ##
+  # :attr_accessor: licenses
+  #
+  # The license(s) for the library.  Each license must be a short name, no
+  # more than 64 characters.
 
-    ##
-    # Executables included in the gem
+  array_attribute :licenses
 
-    array_attribute :executables
+  ##
+  # :attr_accessor: files
+  #
+  # Files included in this gem.  You cannot append to this accessor, you must
+  # assign to it.
+  #
+  # Only add files you can require to this list, not directories, etc.
+  #
+  # Directories are automatically stripped from this list when building a gem,
+  # other non-files cause an error.
 
-    ##
-    # Extensions to build when installing the gem.  See
-    # Gem::Installer#build_extensions for valid values.
+  array_attribute :files
 
-    array_attribute :extensions
+  ##
+  # :attr_accessor: test_files
+  #
+  # Test files included in this gem.  You cannot append to this accessor, you
+  # must assign to it.
 
-    ##
-    # An array or things required by this gem.  Not used by anything
-    # presently.
+  array_attribute :test_files
 
-    array_attribute :requirements
+  ##
+  # :attr_accessor: rdoc_options
+  #
+  # An ARGV-style array of options to RDoc
 
-    ##
-    # A list of Gem::Dependency objects this gem depends on.  Only appendable.
+  array_attribute :rdoc_options
 
-    array_attribute :dependencies
+  ##
+  # :attr_accessor: extra_rdoc_files
+  #
+  # Extra files to add to RDoc
 
-    read_only :dependencies
+  array_attribute :extra_rdoc_files
 
-    # :section: Aliased gemspec attributes
+  ##
+  # :attr_accessor: executables
+  #
+  # Executables included in the gem
 
-    ##
-    # Singular accessor for executables
+  array_attribute :executables
 
-    attribute_alias_singular :executable, :executables
+  ##
+  # :attr_accessor: extensions
+  #
+  # Extensions to build when installing the gem.  See
+  # Gem::Installer#build_extensions for valid values.
 
-    ##
-    # Singular accessor for authors
+  array_attribute :extensions
 
-    attribute_alias_singular :author, :authors
+  ##
+  # :attr_accessor: requirements
+  #
+  # An array or things required by this gem.  Not used by anything
+  # presently.
 
-    ##
-    # Singular accessor for require_paths
+  array_attribute :requirements
 
-    attribute_alias_singular :require_path, :require_paths
+  ##
+  # :attr_reader: dependencies
+  #
+  # A list of Gem::Dependency objects this gem depends on.
 
-    ##
-    # Singular accessor for test_files
+  array_attribute :dependencies
 
-    attribute_alias_singular :test_file, :test_files
+  read_only :dependencies
 
-    overwrite_accessor :version= do |version|
-      @version = Version.create(version)
-    end
+  # :section: Aliased gemspec attributes
 
-    overwrite_accessor :platform do
-      @new_platform
-    end
+  ##
+  # Singular accessor for #executables
 
-    overwrite_accessor :platform= do |platform|
-      if @original_platform.nil? or
-         @original_platform == Gem::Platform::RUBY then
-        @original_platform = platform
-      end
+  attribute_alias_singular :executable, :executables
 
-      case platform
-      when Gem::Platform::CURRENT then
-        @new_platform = Gem::Platform.local
-        @original_platform = @new_platform.to_s
+  ##
+  # Singular accessor for #authors
 
-      when Gem::Platform then
-        @new_platform = platform
+  attribute_alias_singular :author, :authors
 
-      # legacy constants
-      when nil, Gem::Platform::RUBY then
-        @new_platform = Gem::Platform::RUBY
-      when 'mswin32' then # was Gem::Platform::WIN32
-        @new_platform = Gem::Platform.new 'x86-mswin32'
-      when 'mswin64' then
-        @new_platform = Gem::Platform.new 'x86-mswin64'
-      when 'i586-linux' then # was Gem::Platform::LINUX_586
-        @new_platform = Gem::Platform.new 'x86-linux'
-      when 'powerpc-darwin' then # was Gem::Platform::DARWIN
-        @new_platform = Gem::Platform.new 'ppc-darwin'
-      else
-        @new_platform = Gem::Platform.new platform
-      end
+  ##
+  # Singular accessor for #licenses
 
-      @platform = @new_platform.to_s
+  attribute_alias_singular :license, :licenses
 
-      @new_platform
-    end
+  ##
+  # Singular accessor for #require_paths
 
-    overwrite_accessor :required_ruby_version= do |value|
-      @required_ruby_version = Gem::Requirement.create(value)
-    end
+  attribute_alias_singular :require_path, :require_paths
 
-    overwrite_accessor :required_rubygems_version= do |value|
-      @required_rubygems_version = Gem::Requirement.create(value)
-    end
+  ##
+  # Singular accessor for #test_files
 
-    overwrite_accessor :date= do |date|
-      # We want to end up with a Time object with one-day resolution.
-      # This is the cleanest, most-readable, faster-than-using-Date
-      # way to do it.
-      case date
-      when String then
-        @date = if /\A(\d{4})-(\d{2})-(\d{2})\Z/ =~ date then
-                  Time.local($1.to_i, $2.to_i, $3.to_i)
-                else
-                  require 'time'
-                  Time.parse date
-                end
-      when Time then
-        @date = Time.local(date.year, date.month, date.day)
-      when Date then
-        @date = Time.local(date.year, date.month, date.day)
-      else
-        @date = TODAY
-      end
-    end
+  attribute_alias_singular :test_file, :test_files
 
-    overwrite_accessor :date do
-      self.date = nil if @date.nil?  # HACK Sets the default value for date
-      @date
-    end
+  ##
+  # has_rdoc is now ignored
 
-    overwrite_accessor :summary= do |str|
-      @summary = if str then
-                   str.strip.
-                   gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
-                   gsub(/\n[ \t]*/, " ")
-                 end
+  overwrite_accessor :has_rdoc do
+    true
+  end
+
+  ##
+  # has_rdoc is now ignored
+
+  overwrite_accessor :has_rdoc= do |value|
+    @has_rdoc = true
+  end
+
+  overwrite_accessor :version= do |version|
+    @version = Gem::Version.create(version)
+    self.required_rubygems_version = '> 1.3.1' if @version.prerelease?
+    return @version
+  end
+
+  overwrite_accessor :platform do
+    @new_platform
+  end
+
+  overwrite_accessor :platform= do |platform|
+    if @original_platform.nil? or
+       @original_platform == Gem::Platform::RUBY then
+      @original_platform = platform
     end
 
-    overwrite_accessor :description= do |str|
-      @description = if str then
-                       str.strip.
-                       gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
-                       gsub(/\n[ \t]*/, " ")
-                     end
+    case platform
+    when Gem::Platform::CURRENT then
+      @new_platform = Gem::Platform.local
+      @original_platform = @new_platform.to_s
+
+    when Gem::Platform then
+      @new_platform = platform
+
+    # legacy constants
+    when nil, Gem::Platform::RUBY then
+      @new_platform = Gem::Platform::RUBY
+    when 'mswin32' then # was Gem::Platform::WIN32
+      @new_platform = Gem::Platform.new 'x86-mswin32'
+    when 'i586-linux' then # was Gem::Platform::LINUX_586
+      @new_platform = Gem::Platform.new 'x86-linux'
+    when 'powerpc-darwin' then # was Gem::Platform::DARWIN
+      @new_platform = Gem::Platform.new 'ppc-darwin'
+    else
+      @new_platform = Gem::Platform.new platform
     end
 
-    overwrite_accessor :default_executable do
-      begin
-        if defined?(@default_executable) and @default_executable
-          result = @default_executable
-        elsif @executables and @executables.size == 1
-          result = Array(@executables).first
-        else
-          result = nil
-        end
-        result
-      rescue
-        nil
-      end
+    @platform = @new_platform.to_s
+
+    @new_platform
+  end
+
+  overwrite_accessor :required_ruby_version= do |value|
+    @required_ruby_version = Gem::Requirement.create(value)
+  end
+
+  overwrite_accessor :required_rubygems_version= do |value|
+    @required_rubygems_version = Gem::Requirement.create(value)
+  end
+
+  overwrite_accessor :date= do |date|
+    # We want to end up with a Time object with one-day resolution.
+    # This is the cleanest, most-readable, faster-than-using-Date
+    # way to do it.
+    case date
+    when String then
+      @date = if /\A(\d{4})-(\d{2})-(\d{2})\Z/ =~ date then
+                Time.local($1.to_i, $2.to_i, $3.to_i)
+              else
+                require 'time'
+                Time.parse date
+              end
+    when Time then
+      @date = Time.local(date.year, date.month, date.day)
+    when Date then
+      @date = Time.local(date.year, date.month, date.day)
+    else
+      @date = TODAY
     end
+  end
 
-    overwrite_accessor :test_files do
-      # Handle the possibility that we have @test_suite_file but not
-      # @test_files.  This will happen when an old gem is loaded via
-      # YAML.
-      if defined? @test_suite_file then
-        @test_files = [@test_suite_file].flatten
-        @test_suite_file = nil
-      end
-      if defined?(@test_files) and @test_files then
-        @test_files
+  overwrite_accessor :date do
+    self.date = nil if @date.nil?  # HACK Sets the default value for date
+    @date
+  end
+
+  overwrite_accessor :summary= do |str|
+    @summary = if str then
+                 str.strip.
+                 gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
+                 gsub(/\n[ \t]*/, " ")
+               end
+  end
+
+  overwrite_accessor :description= do |str|
+    @description = str.to_s
+  end
+
+  overwrite_accessor :default_executable do
+    begin
+      if defined?(@default_executable) and @default_executable
+        result = @default_executable
+      elsif @executables and @executables.size == 1
+        result = Array(@executables).first
       else
-        @test_files = []
+        result = nil
       end
+      result
+    rescue
+      nil
     end
+  end
 
-    overwrite_accessor :files do
-      result = []
-      result.push(*@files) if defined?(@files)
-      result.push(*@test_files) if defined?(@test_files)
-      result.push(*(add_bindir(@executables)))
-      result.push(*@extra_rdoc_files) if defined?(@extra_rdoc_files)
-      result.push(*@extensions) if defined?(@extensions)
-      result.uniq.compact
+  overwrite_accessor :test_files do
+    # Handle the possibility that we have @test_suite_file but not
+    # @test_files.  This will happen when an old gem is loaded via
+    # YAML.
+    if defined? @test_suite_file then
+      @test_files = [@test_suite_file].flatten
+      @test_suite_file = nil
     end
+    if defined?(@test_files) and @test_files then
+      @test_files
+    else
+      @test_files = []
+    end
+  end
 
+  overwrite_accessor :files do
+    result = []
+    result.push(*@files) if defined?(@files)
+    result.push(*@test_files) if defined?(@test_files)
+    result.push(*(add_bindir(@executables)))
+    result.push(*@extra_rdoc_files) if defined?(@extra_rdoc_files)
+    result.push(*@extensions) if defined?(@extensions)
+    result.uniq.compact
   end
 
 end
Index: lib/rubygems/exceptions.rb
===================================================================
--- lib/rubygems/exceptions.rb	(revision 23658)
+++ lib/rubygems/exceptions.rb	(revision 23659)
@@ -1,5 +1,3 @@
-require 'rubygems'
-
 ##
 # Base exception class for RubyGems.  All exception raised by RubyGems are a
 # subclass of this one.
Index: lib/rubygems/require_paths_builder.rb
===================================================================
--- lib/rubygems/require_paths_builder.rb	(revision 23658)
+++ lib/rubygems/require_paths_builder.rb	(revision 23659)
@@ -1,15 +1,17 @@
-module Gem
-  module RequirePathsBuilder
-    def write_require_paths_file_if_needed(spec = @spec, gem_home = @gem_home)
-      return if spec.require_paths == ["lib"] && (spec.bindir.nil? || spec.bindir == "bin")
-      file_name = File.join(gem_home, 'gems', "#{@spec.full_name}", ".require_paths")
-      file_name.untaint
-      File.open(file_name, "w") do |file|
-        spec.require_paths.each do |path|
-          file.puts path
-        end
-        file.puts spec.bindir if spec.bindir
+require 'rubygems'
+
+module Gem::RequirePathsBuilder
+  def write_require_paths_file_if_needed(spec = @spec, gem_home = @gem_home)
+    return if spec.require_paths == ["lib"] &&
+              (spec.bindir.nil? || spec.bindir == "bin")
+    file_name = File.join(gem_home, 'gems', "#{@spec.full_name}", ".require_paths")
+    file_name.untaint
+    File.open(file_name, "w") do |file|
+      spec.require_paths.each do |path|
+        file.puts path
       end
+      file.puts spec.bindir if spec.bindir
     end
   end
-end
\ No newline at end of file
+end
+
Index: lib/rubygems/text.rb
===================================================================
--- lib/rubygems/text.rb	(revision 0)
+++ lib/rubygems/text.rb	(revision 23659)
@@ -0,0 +1,30 @@
+require 'rubygems'
+
+##
+# A collection of text-wrangling methods
+
+module Gem::Text
+
+  ##
+  # Wraps +text+ to +wrap+ characters and optionally indents by +indent+
+  # characters
+
+  def format_text(text, wrap, indent=0)
+    result = []
+    work = text.dup
+
+    while work.length > wrap do
+      if work =~ /^(.{0,#{wrap}})[ \n]/ then
+        result << $1
+        work.slice!(0, $&.length)
+      else
+        result << work.slice!(0, wrap)
+      end
+    end
+
+    result << work if work.length.nonzero?
+    result.join("\n").gsub(/^/, " " * indent)
+  end
+
+end
+
Index: lib/rubygems/platform.rb
===================================================================
--- lib/rubygems/platform.rb	(revision 23658)
+++ lib/rubygems/platform.rb	(revision 23659)
@@ -1,5 +1,3 @@
-require 'rubygems'
-
 ##
 # Available list of platforms for targeting Gem installations.
 
@@ -105,6 +103,10 @@
   def to_s
     to_a.compact.join '-'
   end
+  
+  def empty?
+    to_s.empty?
+  end
 
   ##
   # Is +other+ equal to this platform?  Two platforms are equal if they have
@@ -143,14 +145,14 @@
     when String then
       # This data is from http://gems.rubyforge.org/gems/yaml on 19 Aug 2007
       other = case other
-              when /^i686-darwin(\d)/ then     ['x86',       'darwin',  $1]
-              when /^i\d86-linux/ then         ['x86',       'linux',   nil]
-              when 'java', 'jruby' then        [nil,         'java',    nil]
-              when /mswin32(\_(\d+))?/ then    ['x86',       'mswin32', $2]
-              when 'powerpc-darwin' then       ['powerpc',   'darwin',  nil]
-              when /powerpc-darwin(\d)/ then   ['powerpc',   'darwin',  $1]
-              when /sparc-solaris2.8/ then     ['sparc',     'solaris', '2.8']
-              when /universal-darwin(\d)/ then ['universal', 'darwin',  $1]
+              when /^i686-darwin(\d)/     then ['x86',       'darwin',  $1    ]
+              when /^i\d86-linux/         then ['x86',       'linux',   nil   ]
+              when 'java', 'jruby'        then [nil,         'java',    nil   ]
+              when /mswin32(\_(\d+))?/    then ['x86',       'mswin32', $2    ]
+              when 'powerpc-darwin'       then ['powerpc',   'darwin',  nil   ]
+              when /powerpc-darwin(\d)/   then ['powerpc',   'darwin',  $1    ]
+              when /sparc-solaris2.8/     then ['sparc',     'solaris', '2.8' ]
+              when /universal-darwin(\d)/ then ['universal', 'darwin',  $1    ]
               else                             other
               end
 
Index: lib/rubygems/version.rb
===================================================================
--- lib/rubygems/version.rb	(revision 23658)
+++ lib/rubygems/version.rb	(revision 23659)
@@ -4,27 +4,81 @@
 # See LICENSE.txt for permissions.
 #++
 
-require 'rubygems'
-
 ##
-# The Version class processes string versions into comparable values
+# The Version class processes string versions into comparable
+# values. A version string should normally be a series of numbers
+# separated by periods. Each part (digits separated by periods) is
+# considered its own number, and these are used for sorting. So for
+# instance, 3.10 sorts higher than 3.2 because ten is greater than
+# two.
+#
+# If any part contains letters (currently only a-z are supported) then
+# that version is considered prerelease. Versions with a prerelease
+# part in the Nth part sort less than versions with N-1 parts. Prerelease
+# parts are sorted alphabetically using the normal Ruby string sorting
+# rules.
+#
+# Prereleases sort between real releases (newest to oldest):
+#
+# 1. 1.0
+# 2. 1.0.b
+# 3. 1.0.a
+# 4. 0.9
 
 class Gem::Version
 
+  class Part
+    include Comparable
+
+    attr_reader :value
+
+    def initialize(value)
+      @value = (value =~ /\A\d+\z/) ? value.to_i : value
+    end
+
+    def to_s
+      self.value.to_s
+    end
+
+    def inspect
+      @value
+    end
+
+    def alpha?
+      String === value
+    end
+
+    def numeric?
+      Fixnum === value
+    end
+
+    def <=>(other)
+      if    self.numeric? && other.alpha? then
+        1
+      elsif self.alpha? && other.numeric? then
+        -1
+      else
+        self.value <=> other.value
+      end
+    end
+
+    def succ
+      self.class.new(self.value.succ)
+    end
+  end
+
   include Comparable
 
-  attr_reader :ints
+  VERSION_PATTERN = '[0-9]+(\.[0-9a-z]+)*'
 
   attr_reader :version
 
-  ##
-  # Returns true if +version+ is a valid version string.
+  def self.correct?(version)
+    pattern = /\A\s*(#{VERSION_PATTERN})*\s*\z/
 
-  def self.correct?(version)
-    case version
-    when Integer, /\A\s*(\d+(\.-?\d+)*)*\s*\z/ then true
-    else false
-    end
+    version.is_a? Integer or
+      version =~ pattern or
+      version.to_s =~ pattern
   end
 
   ##
@@ -47,7 +101,7 @@
 
   ##
   # Constructs a Version from the +version+ string.  A version string is a
-  # series of digits separated by dots.
+  # series of digits or ASCII letters separated by dots.
 
   def initialize(version)
     raise ArgumentError, "Malformed version number string #{version}" unless
@@ -60,46 +114,43 @@
     "#<#{self.class} #{@version.inspect}>"
   end
 
+  ##
   # Dump only the raw version string, not the complete object
+
   def marshal_dump
     [@version]
   end
 
+  ##
   # Load custom marshal format
+
   def marshal_load(array)
     self.version = array[0]
   end
 
+  def parts
+    @parts ||= normalize
+  end
+
   ##
   # Strip ignored trailing zeros.
 
   def normalize
-    @ints = build_array_from_version_string
-
-    return if @ints.length == 1
-
-    @ints.pop while @ints.last == 0
-
-    @ints = [0] if @ints.empty?
+    parts_arr = parse_parts_from_version_string
+    if parts_arr.length != 1
+      parts_arr.pop while parts_arr.last && parts_arr.last.value == 0
+      parts_arr = [Part.new(0)] if parts_arr.empty?
+    end
+    parts_arr
   end
 
   ##
   # Returns the text representation of the version
-  #
-  # return:: [String] version as string
-  #
+
   def to_s
     @version
   end
 
-  ##
-  # Returns an integer array representation of this Version.
-
-  def to_ints
-    normalize unless @ints
-    @ints
-  end
-
   def to_yaml_properties
     ['@version']
   end
@@ -109,6 +160,23 @@
     normalize
   end
 
+  ##
+  # A version is considered a prerelease if any part contains a letter.
+
+  def prerelease?
+    parts.any? { |part| part.alpha? }
+  end
+  
+  ##
+  # The release for this version (e.g. 1.2.0.a -> 1.2.0)
+  # Non-prerelease versions return themselves
+  def release
+    return self unless prerelease?
+    rel_parts = parts.dup
+    rel_parts.pop while rel_parts.any? { |part| part.alpha? }
+    self.class.new(rel_parts.join('.'))
+  end
+
   def yaml_initialize(tag, values)
     self.version = values['version']
   end
@@ -120,9 +188,16 @@
   def <=>(other)
     return nil unless self.class === other
     return 1 unless other
-    @ints <=> other.ints
+    mine, theirs = balance(self.parts.dup, other.parts.dup)
+    mine <=> theirs
   end
 
+  def balance(a, b)
+    a << Part.new(0) while a.size < b.size
+    b << Part.new(0) while b.size < a.size
+    [a, b]
+  end
+
   ##
   # A Version is only eql? to another version if it has the same version
   # string.  "1.0" is not the same version as "1".
@@ -135,24 +210,33 @@
     @version.hash
   end
 
-  # Return a new version object where the next to the last revision
-  # number is one greater. (e.g.  5.3.1 => 5.4)
+  ##
+  # Return a new version object where the next to the last revision number is
+  # one greater. (e.g.  5.3.1 => 5.4)
+  #
+  # Pre-release (alpha) parts are ignored. (e.g 5.3.1.b2 => 5.4)
+
   def bump
-    ints = build_array_from_version_string
-    ints.pop if ints.size > 1
-    ints[-1] += 1
-    self.class.new(ints.join("."))
+    parts = parse_parts_from_version_string
+    parts.pop while parts.any? { |part| part.alpha? }
+    parts.pop if parts.size > 1
+    parts[-1] = parts[-1].succ
+    self.class.new(parts.join("."))
   end
 
-  def build_array_from_version_string
-    @version.to_s.scan(/\d+/).map { |s| s.to_i }
+  def parse_parts_from_version_string # :nodoc:
+    @version.to_s.scan(/[0-9a-z]+/i).map { |s| Part.new(s) }
   end
-  private :build_array_from_version_string
 
+  def pretty_print(q) # :nodoc:
+    q.text "Gem::Version.new(#{@version.inspect})"
+  end
+
   #:stopdoc:
 
   require 'rubygems/requirement'
 
+  ##
   # Gem::Requirement's original definition is nested in Version.
   # Although an inappropriate place, current gems specs reference the nested
   # class name explicitly.  To remain compatible with old software loading
Index: lib/rubygems/source_index.rb
===================================================================
--- lib/rubygems/source_index.rb	(revision 23658)
+++ lib/rubygems/source_index.rb	(revision 23659)
@@ -4,12 +4,14 @@
 # See LICENSE.txt for permissions.
 #++
 
-require 'rubygems'
 require 'rubygems/user_interaction'
 require 'rubygems/specification'
+
+# :stopdoc:
 module Gem
-  autoload(:SpecFetcher, 'rubygems/spec_fetcher')
+  autoload :SpecFetcher, 'rubygems/spec_fetcher'
 end
+# :startdoc:
 
 ##
 # The SourceIndex object indexes all the gems available from a
@@ -28,7 +30,7 @@
 
   include Gem::UserInteraction
 
-  attr_reader :gems # :nodoc:
+  attr_reader :gems, :prerelease_gems # :nodoc:
 
   ##
   # Directories to use to refresh this SourceIndex when calling refresh!
@@ -81,13 +83,15 @@
     # loaded spec.
 
     def load_specification(file_name)
+      return nil unless file_name and File.exist? file_name
+
+      spec_code = if RUBY_VERSION < '1.9' then
+                    File.read file_name
+                  else
+                    File.read file_name, :encoding => 'UTF-8'
+                  end.untaint
+
       begin
-        spec_code = if RUBY_VERSION < '1.9' then
-                      File.read file_name
-                    else
-                      File.read file_name, :encoding => 'UTF-8'
-                    end.untaint
-
         gemspec = eval spec_code, binding, file_name
 
         if gemspec.is_a?(Gem::Specification)
@@ -104,24 +108,33 @@
         alert_warning "#{e.inspect}\n#{spec_code}"
         alert_warning "Invalid .gemspec format in '#{file_name}'"
       end
+
       return nil
     end
 
   end
 
   ##
-  # Constructs a source index instance from the provided
-  # specifications
-  #
-  # specifications::
-  #   [Hash] hash of [Gem name, Gem::Specification] pairs
+  # Constructs a source index instance from the provided specifications, which
+  # is a Hash of gem full names and Gem::Specifications.
+  #--
+  # TODO merge @gems and @prerelease_gems and provide a separate method
+  # #prerelease_gems
 
   def initialize(specifications={})
-    @gems = specifications
+    @gems, @prerelease_gems = [{}, {}]
+    specifications.each{ |full_name, spec| add_spec spec }
     @spec_dirs = nil
   end
 
   ##
+  # Both regular and prerelease gems
+
+  def all_gems
+    @gems.merge @prerelease_gems
+  end
+
+  ##
   # Reconstruct the source index from the specifications in +spec_dirs+.
 
   def load_gems_in(*spec_dirs)
@@ -170,14 +183,29 @@
       result[name] << spec
     end
 
+    # TODO: why is this a hash while @gems is an array? Seems like
+    # structural similarity would be good.
     result.values.flatten
   end
 
   ##
+  # An array including only the prerelease gemspecs
+
+  def prerelease_specs
+    @prerelease_gems.values
+  end
+
+  ##
   # Add a gem specification to the source index.
 
-  def add_spec(gem_spec)
-    @gems[gem_spec.full_name] = gem_spec
+  def add_spec(gem_spec, name = gem_spec.full_name)
+    # No idea why, but the Indexer wants to insert them using original_name
+    # instead of full_name. So we make it an optional arg.
+    if gem_spec.version.prerelease?
+      @prerelease_gems[name] = gem_spec
+    else
+      @gems[name] = gem_spec
+    end
   end
 
   ##
@@ -193,7 +221,11 @@
   # Remove a gem specification named +full_name+.
 
   def remove_spec(full_name)
-    @gems.delete(full_name)
+    if @gems.key? full_name then
+      @gems.delete full_name
+    else
+      @prerelease_gems.delete full_name
+    end
   end
 
   ##
@@ -215,18 +247,18 @@
   # change in the index.
 
   def index_signature
-    require 'rubygems/digest/sha2'
+    require 'digest'
 
-    Gem::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s
+    Digest::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s
   end
 
   ##
   # The signature for the given gem specification.
 
   def gem_signature(gem_full_name)
-    require 'rubygems/digest/sha2'
+    require 'digest'
 
-    Gem::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s
+    Digest::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s
   end
 
   def size
@@ -238,7 +270,7 @@
   # Find a gem by an exact match on the short name.
 
   def find_name(gem_name, version_requirement = Gem::Requirement.default)
-    dep = Gem::Dependency.new(/^#{gem_name}$/, version_requirement)
+    dep = Gem::Dependency.new gem_name, version_requirement
     search dep
   end
 
@@ -257,7 +289,7 @@
 
     # TODO - Remove support and warning for legacy arguments after 2008/11
     unless Gem::Dependency === gem_pattern
-      warn "#{Gem.location_of_caller.join ':'}:Warning: Gem::SourceIndex#search support for #{gem_pattern.class} patterns is deprecated"
+      warn "#{Gem.location_of_caller.join ':'}:Warning: Gem::SourceIndex#search support for #{gem_pattern.class} patterns is deprecated, use #find_name"
     end
 
     case gem_pattern
@@ -282,7 +314,7 @@
       version_requirement = Gem::Requirement.create version_requirement
     end
 
-    specs = @gems.values.select do |spec|
+    specs = all_gems.values.select do |spec|
       spec.name =~ gem_pattern and
         version_requirement.satisfied_by? spec.version
     end
@@ -376,7 +408,7 @@
   end
 
   def ==(other) # :nodoc:
-    self.class === other and @gems == other.gems
+    self.class === other and @gems == other.gems 
   end
 
   def dump
@@ -545,15 +577,15 @@
 
 end
 
+# :stopdoc:
 module Gem
 
-  # :stopdoc:
-
+  ##
   # Cache is an alias for SourceIndex to allow older YAMLized source index
   # objects to load properly.
+
   Cache = SourceIndex
 
-  # :startdoc:
-
 end
+# :startdoc:
 
Index: lib/rubygems/package/tar_header.rb
===================================================================
--- lib/rubygems/package/tar_header.rb	(revision 23658)
+++ lib/rubygems/package/tar_header.rb	(revision 23659)
@@ -3,8 +3,6 @@
 # See LICENSE.txt for additional licensing information.
 #--
 
-require 'rubygems/package'
-
 ##
 #--
 # struct tarfile_entry_posix {
@@ -26,9 +24,13 @@
 #   char prefix[155];   # ASCII + (Z unless filled)
 # };
 #++
+# A header for a tar file
 
 class Gem::Package::TarHeader
 
+  ##
+  # Fields in the tar header
+
   FIELDS = [
     :checksum,
     :devmajor,
@@ -48,6 +50,9 @@
     :version,
   ]
 
+  ##
+  # Pack format for a tar header
+
   PACK_FORMAT = 'a100' + # name
                 'a8'   + # mode
                 'a8'   + # uid
@@ -65,6 +70,9 @@
                 'a8'   + # devminor
                 'a155'   # prefix
 
+  ##
+  # Unpack format for a tar header
+
   UNPACK_FORMAT = 'A100' + # name
                   'A8'   + # mode
                   'A8'   + # uid
@@ -84,6 +92,9 @@
 
   attr_reader(*FIELDS)
 
+  ##
+  # Creates a tar header from IO +stream+
+
   def self.from(stream)
     header = stream.read 512
     empty = (header == "\0" * 512)
@@ -147,6 +158,9 @@
     #    :empty => empty
   end
 
+  ##
+  # Creates a new TarHeader using +vals+
+
   def initialize(vals)
     unless vals[:name] && vals[:size] && vals[:prefix] && vals[:mode] then
       raise ArgumentError, ":name, :size, :prefix and :mode required"
@@ -171,11 +185,14 @@
     @empty = vals[:empty]
   end
 
+  ##
+  # Is the tar entry empty?
+
   def empty?
     @empty
   end
 
-  def ==(other)
+  def ==(other) # :nodoc:
     self.class === other and
     @checksum == other.checksum and
     @devmajor == other.devmajor and
@@ -195,11 +212,14 @@
     @version  == other.version
   end
 
-  def to_s
+  def to_s # :nodoc:
     update_checksum
     header
   end
 
+  ##
+  # Updates the TarHeader's checksum
+
   def update_checksum
     header = header " " * 8
     @checksum = oct calculate_checksum(header), 6
Index: lib/rubygems/package/f_sync_dir.rb
===================================================================
--- lib/rubygems/package/f_sync_dir.rb	(revision 23658)
+++ lib/rubygems/package/f_sync_dir.rb	(revision 23659)
@@ -3,8 +3,6 @@
 # See LICENSE.txt for additional licensing information.
 #--
 
-require 'rubygems/package'
-
 module Gem::Package::FSyncDir
 
   private
Index: lib/rubygems/package/tar_writer.rb
===================================================================
--- lib/rubygems/package/tar_writer.rb	(revision 23658)
+++ lib/rubygems/package/tar_writer.rb	(revision 23659)
@@ -3,22 +3,41 @@
 # See LICENSE.txt for additional licensing information.
 #--
 
-require 'rubygems/package'
+##
+# Allows writing of tar files
 
 class Gem::Package::TarWriter
 
   class FileOverflow < StandardError; end
 
+  ##
+  # IO wrapper that allows writing a limited amount of data
+
   class BoundedStream
 
-    attr_reader :limit, :written
+    ##
+    # Maximum number of bytes that can be written
 
+    attr_reader :limit
+
+    ##
+    # Number of bytes written
+
+    attr_reader :written
+
+    ##
+    # Wraps +io+ and allows up to +limit+ bytes to be written
+
     def initialize(io, limit)
       @io = io
       @limit = limit
       @written = 0
     end
 
+    ##
+    # Writes +data+ onto the IO, raising a FileOverflow exception if the
+    # number of bytes will be more than #limit
+
     def write(data)
       if data.size + @written > @limit
         raise FileOverflow, "You tried to feed more data than fits in the file."
@@ -30,18 +49,30 @@
 
   end
 
+  ##
+  # IO wrapper that provides only #write
+
   class RestrictedStream
 
+    ##
+    # Creates a new RestrictedStream wrapping +io+
+
     def initialize(io)
       @io = io
     end
 
+    ##
+    # Writes +data+ onto the IO
+
     def write(data)
       @io.write data
     end
 
   end
 
+  ##
+  # Creates a new TarWriter, yielding it if a block is given
+
   def self.new(io)
     writer = super
 
@@ -56,12 +87,19 @@
     nil
   end
 
+  ##
+  # Creates a new TarWriter that will write to +io+
+
   def initialize(io)
     @io = io
     @closed = false
   end
 
-  def add_file(name, mode)
+  ##
+  # Adds file +name+ with permissions +mode+, and yields an IO for writing the
+  # file to
+
+  def add_file(name, mode) # :yields: io
     check_closed
 
     raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos=
@@ -90,7 +128,11 @@
     self
   end
 
-  def add_file_simple(name, mode, size)
+  ##
+  # Add file +name+ with permissions +mode+ +size+ bytes long.  Yields an IO
+  # to write the file to.
+
+  def add_file_simple(name, mode, size) # :yields: io
     check_closed
 
     name, prefix = split_name name
@@ -112,10 +154,16 @@
     self
   end
 
+  ##
+  # Raises IOError if the TarWriter is closed
+
   def check_closed
     raise IOError, "closed #{self.class}" if closed?
   end
 
+  ##
+  # Closes the TarWriter
+
   def close
     check_closed
 
@@ -125,16 +173,25 @@
     @closed = true
   end
 
+  ##
+  # Is the TarWriter closed?
+
   def closed?
     @closed
   end
 
+  ##
+  # Flushes the TarWriter's IO
+
   def flush
     check_closed
 
     @io.flush if @io.respond_to? :flush
   end
 
+  ##
+  # Creates a new directory in the tar file +name+ with +mode+
+
   def mkdir(name, mode)
     check_closed
 
@@ -149,6 +206,9 @@
     self
   end
 
+  ##
+  # Splits +name+ into a name and prefix that can fit in the TarHeader
+
   def split_name(name) # :nodoc:
     raise Gem::Package::TooLongFileName if name.size > 256
 
@@ -169,7 +229,7 @@
       name = newname
 
       if name.size > 100 or prefix.size > 155 then
-        raise Gem::Package::TooLongFileName
+        raise Gem::Package::TooLongFileName 
       end
     end
 
Index: lib/rubygems/package/tar_input.rb
===================================================================
--- lib/rubygems/package/tar_input.rb	(revision 23658)
+++ lib/rubygems/package/tar_input.rb	(revision 23659)
@@ -3,8 +3,6 @@
 # See LICENSE.txt for additional licensing information.
 #--
 
-require 'rubygems/package'
-
 class Gem::Package::TarInput
 
   include Gem::Package::FSyncDir
@@ -72,9 +70,9 @@
       # map trust policy from string to actual class (or a serialized YAML
       # file, if that exists)
       if String === security_policy then
-        if Gem::Security::Policy.key? security_policy then
+        if Gem::Security::Policies.key? security_policy then
           # load one of the pre-defined security policies
-          security_policy = Gem::Security::Policy[security_policy]
+          security_policy = Gem::Security::Policies[security_policy]
         elsif File.exist? security_policy then
           # FIXME: this doesn't work yet
           security_policy = YAML.load File.read(security_policy)
@@ -136,10 +134,10 @@
 
   def extract_entry(destdir, entry, expected_md5sum = nil)
     if entry.directory? then
-      dest = File.join(destdir, entry.full_name)
+      dest = File.join destdir, entry.full_name
 
-      if File.dir? dest then
-        @fileops.chmod entry.header.mode, dest, :verbose=>false
+      if File.directory? dest then
+        @fileops.chmod entry.header.mode, dest, :verbose => false
       else
         @fileops.mkdir_p dest, :mode => entry.header.mode, :verbose => false
       end
Index: lib/rubygems/package/tar_output.rb
===================================================================
--- lib/rubygems/package/tar_output.rb	(revision 23658)
+++ lib/rubygems/package/tar_output.rb	(revision 23659)
@@ -3,8 +3,6 @@
 # See LICENSE.txt for additional licensing information.
 #--
 
-require 'rubygems/package'
-
 ##
 # TarOutput is a wrapper to TarWriter that builds gem-format tar file.
 #
@@ -66,8 +64,10 @@
       Zlib::GzipWriter.wrap(sio || inner) do |os|
 
         Gem::Package::TarWriter.new os do |data_tar_writer|
+          # :stopdoc:
           def data_tar_writer.metadata() @metadata end
           def data_tar_writer.metadata=(metadata) @metadata = metadata end
+          # :startdoc:
 
           yield data_tar_writer
 
Index: lib/rubygems/package/tar_reader/entry.rb
===================================================================
--- lib/rubygems/package/tar_reader/entry.rb	(revision 23658)
+++ lib/rubygems/package/tar_reader/entry.rb	(revision 23659)
@@ -3,12 +3,19 @@
 # See LICENSE.txt for additional licensing information.
 #--
 
-require 'rubygems/package'
+##
+# Class for reading entries out of a tar file
 
 class Gem::Package::TarReader::Entry
 
+  ##
+  # Header for this tar entry
+
   attr_reader :header
 
+  ##
+  # Creates a new tar entry for +header+ that will be read from +io+
+
   def initialize(header, io)
     @closed = false
     @header = header
@@ -21,24 +28,39 @@
     raise IOError, "closed #{self.class}" if closed?
   end
 
+  ##
+  # Number of bytes read out of the tar entry
+
   def bytes_read
     @read
   end
 
+  ##
+  # Closes the tar entry
+
   def close
     @closed = true
   end
 
+  ##
+  # Is the tar entry closed?
+
   def closed?
     @closed
   end
 
+  ##
+  # Are we at the end of the tar entry?
+
   def eof?
     check_closed
 
     @read >= @header.size
   end
 
+  ##
+  # Full name of the tar entry
+
   def full_name
     if @header.prefix != "" then
       File.join @header.prefix, @header.name
@@ -47,6 +69,9 @@
     end
   end
 
+  ##
+  # Read one byte from the tar entry
+
   def getc
     check_closed
 
@@ -58,20 +83,33 @@
     ret
   end
 
+  ##
+  # Is this tar entry a directory?
+
   def directory?
     @header.typeflag == "5"
   end
 
+  ##
+  # Is this tar entry a file?
+
   def file?
     @header.typeflag == "0"
   end
 
+  ##
+  # The position in the tar entry
+
   def pos
     check_closed
 
     bytes_read
   end
 
+  ##
+  # Reads +len+ bytes from the tar file entry, or the rest of the entry if
+  # nil
+
   def read(len = nil)
     check_closed
 
@@ -86,6 +124,9 @@
     ret
   end
 
+  ##
+  # Rewinds to the beginning of the tar file entry
+
   def rewind
     check_closed
 
Index: lib/rubygems/package/tar_reader.rb
===================================================================
--- lib/rubygems/package/tar_reader.rb	(revision 23658)
+++ lib/rubygems/package/tar_reader.rb	(revision 23659)
@@ -3,14 +3,21 @@
 # See LICENSE.txt for additional licensing information.
 #--
 
-require 'rubygems/package'
+##
+# TarReader reads tar files and allows iteration over their items
 
 class Gem::Package::TarReader
 
   include Gem::Package
 
+  ##
+  # Raised if the tar IO is not seekable
+
   class UnexpectedEOF < StandardError; end
 
+  ##
+  # Creates a new TarReader on +io+ and yields it to the block, if given.
+
   def self.new(io)
     reader = super
 
@@ -25,14 +32,24 @@
     nil
   end
 
+  ##
+  # Creates a new tar file reader on +io+ which needs to respond to #pos,
+  # #eof?, #read, #getc and #pos=
+
   def initialize(io)
     @io = io
     @init_pos = io.pos
   end
 
+  ##
+  # Close the tar file
+
   def close
   end
 
+  ##
+  # Iterates over files in the tarball yielding each entry
+
   def each
     loop do
       return if @io.eof?
@@ -84,3 +101,5 @@
 
 end
 
+require 'rubygems/package/tar_reader/entry'
+
Index: lib/rubygems/remote_fetcher.rb
===================================================================
--- lib/rubygems/remote_fetcher.rb	(revision 23658)
+++ lib/rubygems/remote_fetcher.rb	(revision 23659)
@@ -55,7 +55,7 @@
   #        HTTP_PROXY_PASS)
   # * <tt>:no_proxy</tt>: ignore environment variables and _don't_ use a proxy
 
-  def initialize(proxy)
+  def initialize(proxy = nil)
     Socket.do_not_reverse_lookup = true
 
     @connections = {}
@@ -86,7 +86,11 @@
 
     FileUtils.mkdir_p cache_dir rescue nil unless File.exist? cache_dir
 
-    source_uri = URI.parse source_uri unless URI::Generic === source_uri
+   # Always escape URI's to deal with potential spaces and such
+    unless URI::Generic === source_uri
+      source_uri = URI.parse(URI.escape(source_uri))
+    end
+
     scheme = source_uri.scheme
 
     # URI.parse gets confused by MS Windows paths with forward slashes.
@@ -101,7 +105,7 @@
 
           remote_gem_path = source_uri + "gems/#{gem_file_name}"
 
-          gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path
+          gem = self.fetch_path remote_gem_path
         rescue Gem::RemoteFetcher::FetchError
           raise if spec.original_platform == spec.platform
 
@@ -112,22 +116,40 @@
 
           remote_gem_path = source_uri + "gems/#{alternate_name}"
 
-          gem = Gem::RemoteFetcher.fetcher.fetch_path remote_gem_path
+          gem = self.fetch_path remote_gem_path
         end
 
         File.open local_gem_path, 'wb' do |fp|
           fp.write gem
         end
       end
-    when nil, 'file' then # TODO test for local overriding cache
+    when 'file' then
       begin
-        FileUtils.cp source_uri.to_s, local_gem_path
+        path = source_uri.path
+        path = File.dirname(path) if File.extname(path) == '.gem'
+
+        remote_gem_path = File.join(path, 'gems', gem_file_name)
+
+        FileUtils.cp(remote_gem_path, local_gem_path)
       rescue Errno::EACCES
         local_gem_path = source_uri.to_s
       end
 
       say "Using local gem #{local_gem_path}" if
         Gem.configuration.really_verbose
+    when nil then # TODO test for local overriding cache
+      begin
+        if Gem.win_platform? && source_uri.scheme && !source_uri.path.include?(':')
+          FileUtils.cp URI.unescape(source_uri.scheme + ':' + source_uri.path), local_gem_path
+        else
+          FileUtils.cp URI.unescape(source_uri.path), local_gem_path
+        end
+      rescue Errno::EACCES
+        local_gem_path = source_uri.to_s
+      end
+
+      say "Using local gem #{local_gem_path}" if
+        Gem.configuration.really_verbose
     else
       raise Gem::InstallError, "unsupported URI scheme #{source_uri.scheme}"
     end
@@ -177,7 +199,7 @@
 
     return nil if env_proxy.nil? or env_proxy.empty?
 
-    uri = URI.parse env_proxy
+    uri = URI.parse(normalize_uri(env_proxy))
 
     if uri and uri.user.nil? and uri.password.nil? then
       # Probably we have http_proxy_* variables?
@@ -233,11 +255,26 @@
   def open_uri_or_path(uri, last_modified = nil, head = false, depth = 0)
     raise "block is dead" if block_given?
 
-    return open(get_file_uri_path(uri)) if file_uri? uri
-
     uri = URI.parse uri unless URI::Generic === uri
-    raise ArgumentError, 'uri is not an HTTP URI' unless URI::HTTP === uri
 
+    # This check is redundant unless Gem::RemoteFetcher is likely
+    # to be used directly, since the scheme is checked elsewhere.
+    # - Daniel Berger
+    unless ['http', 'https', 'file'].include?(uri.scheme)
+     raise ArgumentError, 'uri scheme is invalid'
+    end
+
+    if uri.scheme == 'file'
+      path = uri.path
+
+      # Deal with leading slash on Windows paths
+      if path[0].chr == '/' && path[1].chr =~ /[a-zA-Z]/ && path[2].chr == ':'
+         path = path[1..-1]
+      end
+
+      return Gem.read_binary(path)
+    end
+
     fetch_type = head ? Net::HTTP::Head : Net::HTTP::Get
     response   = request uri, fetch_type, last_modified
 
@@ -326,19 +363,5 @@
     connection.start
   end
 
-  ##
-  # Checks if the provided string is a file:// URI.
-
-  def file_uri?(uri)
-    uri =~ %r{\Afile://}
-  end
-
-  ##
-  # Given a file:// URI, returns its local path.
-
-  def get_file_uri_path(uri)
-    uri.sub(%r{\Afile://}, '')
-  end
-
 end
 
Index: lib/rubygems/installer.rb
===================================================================
--- lib/rubygems/installer.rb	(revision 23658)
+++ lib/rubygems/installer.rb	(revision 23659)
@@ -13,17 +13,28 @@
 require 'rubygems/require_paths_builder'
 
 ##
-# The installer class processes RubyGem .gem files and installs the
-# files contained in the .gem into the Gem.path.
+# The installer class processes RubyGem .gem files and installs the files
+# contained in the .gem into the Gem.path.
 #
 # Gem::Installer does the work of putting files in all the right places on the
 # filesystem including unpacking the gem into its gem dir, installing the
 # gemspec in the specifications dir, storing the cached gem in the cache dir,
 # and installing either wrappers or symlinks for executables.
+#
+# The installer fires pre and post install hooks.  Hooks can be added either
+# through a rubygems_plugin.rb file in an installed gem or via a
+# rubygems/defaults/#{RUBY_ENGINE}.rb or rubygems/defaults/operating_system.rb
+# file.  See Gem.pre_install and Gem.post_install for details.
 
 class Gem::Installer
 
   ##
+  # Paths where env(1) might live.  Some systems are broken and have it in
+  # /bin
+
+  ENV_PATHS = %w[/usr/bin/env /bin/env]
+
+  ##
   # Raised when there is an error while building extensions.
   #
   class ExtensionBuildError < Gem::InstallError; end
@@ -71,8 +82,6 @@
 
   end
 
-  ENV_PATHS = %w[/usr/bin/env /bin/env]
-
   ##
   # Constructs an Installer instance that will install the gem located at
   # +gem+.  +options+ is a Hash with the following keys:
@@ -100,17 +109,17 @@
       :source_index => Gem.source_index,
     }.merge options
 
-    @env_shebang = options[:env_shebang]
-    @force = options[:force]
-    gem_home = options[:install_dir]
-    @gem_home = Pathname.new(gem_home).expand_path
+    @env_shebang         = options[:env_shebang]
+    @force               = options[:force]
+    gem_home             = options[:install_dir]
+    @gem_home            = Pathname.new(gem_home).expand_path
     @ignore_dependencies = options[:ignore_dependencies]
-    @format_executable = options[:format_executable]
-    @security_policy = options[:security_policy]
-    @wrappers = options[:wrappers]
-    @bin_dir = options[:bin_dir]
-    @development = options[:development]
-    @source_index = options[:source_index]
+    @format_executable   = options[:format_executable]
+    @security_policy     = options[:security_policy]
+    @wrappers            = options[:wrappers]
+    @bin_dir             = options[:bin_dir]
+    @development         = options[:development]
+    @source_index        = options[:source_index]
 
     begin
       @format = Gem::Format.from_file_by_path @gem, @security_policy
@@ -121,7 +130,7 @@
     begin
       FileUtils.mkdir_p @gem_home
     rescue Errno::EACCES, Errno::ENOTDIR
-      # We'll divert to ~/.gem below
+      # We'll divert to ~/.gems below
     end
 
     if not File.writable? @gem_home or
@@ -131,7 +140,7 @@
       if options[:user_install] == false then # You don't want to use ~
         raise Gem::FilePermissionError, @gem_home
       elsif options[:user_install].nil? then
-        unless self.class.home_install_warning then
+        unless self.class.home_install_warning or options[:unpack] then
           alert_warning "Installing to ~/.gem since #{@gem_home} and\n\t  #{Gem.bindir} aren't both writable."
           self.class.home_install_warning = true
         end
@@ -392,19 +401,21 @@
     ruby_name = Gem::ConfigMap[:ruby_install_name] if @env_shebang
     path = File.join @gem_dir, @spec.bindir, bin_file_name
     first_line = File.open(path, "rb") {|file| file.gets}
+
     if /\A#!/ =~ first_line then
       # Preserve extra words on shebang line, like "-w".  Thanks RPA.
       shebang = first_line.sub(/\A\#!.*?ruby\S*(?=(\s+\S+))/, "#!#{Gem.ruby}")
       opts = $1
       shebang.strip! # Avoid nasty ^M issues.
     end
-    if !ruby_name
+
+    if not ruby_name then
       "#!#{Gem.ruby}#{opts}"
-    elsif opts
-      %{#!/bin/sh\n'exec' #{ruby_name.dump} '-x' "$0" "$@"\n#{shebang}}
+    elsif opts then
+      "#!/bin/sh\n'exec' #{ruby_name.dump} '-x' \"$0\" \"$@\"\n#{shebang}"
     else
       # Create a plain shebang line.
-      @env_path ||= ENV_PATHS.find {|path| File.executable?(path)}
+      @env_path ||= ENV_PATHS.find {|env_path| File.executable? env_path }
       "#!#{@env_path} #{ruby_name}"
     end
   end
@@ -432,7 +443,7 @@
 end
 
 gem '#{@spec.name}', version
-load '#{bin_file_name}'
+load Gem.bin_path('#{@spec.name}', '#{bin_file_name}', version)
 TEXT
   end
 
@@ -443,10 +454,10 @@
     <<-TEXT
 @ECHO OFF
 IF NOT "%~f0" == "~f0" GOTO :WinNT
-@"#{File.basename(Gem.ruby)}" "#{File.join(bindir, bin_file_name)}" %1 %2 %3 %4 %5 %6 %7 %8 %9
+@"#{File.basename(Gem.ruby).chomp('"')}" "#{File.join(bindir, bin_file_name)}" %1 %2 %3 %4 %5 %6 %7 %8 %9
 GOTO :EOF
 :WinNT
-@"#{File.basename(Gem.ruby)}" "%~dpn0" %*
+@"#{File.basename(Gem.ruby).chomp('"')}" "%~dpn0" %*
 TEXT
   end
 
@@ -531,6 +542,7 @@
         raise Gem::InstallError, msg
       end
 
+      FileUtils.rm_rf(path) if File.exists?(path)
       FileUtils.mkdir_p File.dirname(path)
 
       File.open(path, "wb") do |out|
Index: lib/rubygems/source_info_cache.rb
===================================================================
--- lib/rubygems/source_info_cache.rb	(revision 23658)
+++ lib/rubygems/source_info_cache.rb	(revision 23659)
@@ -286,7 +286,7 @@
       next unless Gem.sources.include? source_uri
       # TODO - Remove this gunk after 2008/11
       unless pattern.kind_of?(Gem::Dependency)
-        pattern = Gem::Dependency.new(pattern, Gem::Requirement.default)
+        pattern = Gem::Dependency.new(pattern, Gem::Requirement.default) 
       end
       sic_entry.source_index.search pattern, platform_only
     end.flatten.compact
@@ -306,7 +306,7 @@
 
       # TODO - Remove this gunk after 2008/11
       unless pattern.kind_of?(Gem::Dependency)
-        pattern = Gem::Dependency.new(pattern, Gem::Requirement.default)
+        pattern = Gem::Dependency.new(pattern, Gem::Requirement.default) 
       end
 
       sic_entry.source_index.search(pattern, only_platform).each do |spec|
Index: lib/rubygems/commands/specification_command.rb
===================================================================
--- lib/rubygems/commands/specification_command.rb	(revision 23658)
+++ lib/rubygems/commands/specification_command.rb	(revision 23659)
@@ -12,7 +12,8 @@
 
   def initialize
     super 'specification', 'Display gem specification (in yaml)',
-          :domain => :local, :version => Gem::Requirement.default
+          :domain => :local, :version => Gem::Requirement.default,
+          :format => :yaml
 
     add_version_option('examine')
     add_platform_option
@@ -22,26 +23,62 @@
       options[:all] = true
     end
 
+    add_option('--ruby', 'Output ruby format') do |value, options|
+      options[:format] = :ruby
+    end
+
+    add_option('--yaml', 'Output RUBY format') do |value, options|
+      options[:format] = :yaml
+    end
+
+    add_option('--marshal', 'Output Marshal format') do |value, options|
+      options[:format] = :marshal
+    end
+
     add_local_remote_options
   end
 
   def arguments # :nodoc:
-    "GEMFILE       name of gem to show the gemspec for"
+    <<-ARGS
+GEMFILE       name of gem to show the gemspec for
+FIELD         name of gemspec field to show
+    ARGS
   end
 
   def defaults_str # :nodoc:
-    "--local --version '#{Gem::Requirement.default}'"
+    "--local --version '#{Gem::Requirement.default}' --yaml"
   end
 
   def usage # :nodoc:
-    "#{program_name} [GEMFILE]"
+    "#{program_name} [GEMFILE] [FIELD]"
   end
 
   def execute
     specs = []
-    gem = get_one_gem_name
+    gem = options[:args].shift
+
+    unless gem then
+      raise Gem::CommandLineError,
+            "Please specify a gem name or file on the command line"
+    end
+
     dep = Gem::Dependency.new gem, options[:version]
 
+    field = get_one_optional_argument
+
+    if field then
+      field = field.intern
+
+      if options[:format] == :ruby then
+        raise Gem::CommandLineError, "--ruby and FIELD are mutually exclusive"
+      end
+
+      unless Gem::Specification.attribute_names.include? field then
+        raise Gem::CommandLineError,
+              "no field %p on Gem::Specification" % field.to_s
+      end
+    end
+
     if local? then
       if File.exist? gem then
         specs << Gem::Format.from_file_by_path(gem).spec rescue nil
@@ -63,8 +100,18 @@
       terminate_interaction 1
     end
 
-    output = lambda { |s| say s.to_yaml; say "\n" }
+    output = lambda do |s|
+      s = s.send field if field
 
+      say case options[:format]
+          when :ruby then s.to_ruby
+          when :marshal then Marshal.dump s
+          else s.to_yaml
+          end
+
+      say "\n"
+    end
+
     if options[:all] then
       specs.each(&output)
     else
Index: lib/rubygems/commands/unpack_command.rb
===================================================================
--- lib/rubygems/commands/unpack_command.rb	(revision 23658)
+++ lib/rubygems/commands/unpack_command.rb	(revision 23659)
@@ -12,7 +12,7 @@
           :version => Gem::Requirement.default,
           :target  => Dir.pwd
 
-    add_option('--target', 'target directory for unpacking') do |value, options|
+    add_option('--target=DIR', 'target directory for unpacking') do |value, options|
       options[:target] = value
     end
 
@@ -35,18 +35,20 @@
   # TODO: allow, e.g., 'gem unpack rake-0.3.1'.  Find a general solution for
   # this, so that it works for uninstall as well.  (And check other commands
   # at the same time.)
+
   def execute
-    gemname = get_one_gem_name
-    path = get_path(gemname, options[:version])
+    get_all_gem_names.each do |name|
+      path = get_path name, options[:version]
 
-    if path then
-      basename = File.basename(path).sub(/\.gem$/, '')
-      target_dir = File.expand_path File.join(options[:target], basename)
-      FileUtils.mkdir_p target_dir
-      Gem::Installer.new(path, :unpack => true).unpack target_dir
-      say "Unpacked gem: '#{target_dir}'"
-    else
-      alert_error "Gem '#{gemname}' not installed."
+      if path then
+        basename = File.basename(path).sub(/\.gem$/, '')
+        target_dir = File.expand_path File.join(options[:target], basename)
+        FileUtils.mkdir_p target_dir
+        Gem::Installer.new(path, :unpack => true).unpack target_dir
+        say "Unpacked gem: '#{target_dir}'"
+      else
+        alert_error "Gem '#{name}' not installed."
+      end
     end
   end
 
Index: lib/rubygems/commands/generate_index_command.rb
===================================================================
--- lib/rubygems/commands/generate_index_command.rb	(revision 23658)
+++ lib/rubygems/commands/generate_index_command.rb	(revision 23659)
@@ -1,55 +1,131 @@
 require 'rubygems/command'
 require 'rubygems/indexer'
 
+##
+# Generates a index files for use as a gem server.
+#
+# See `gem help generate_index`
+
 class Gem::Commands::GenerateIndexCommand < Gem::Command
 
   def initialize
     super 'generate_index',
           'Generates the index files for a gem server directory',
-          :directory => '.'
+          :directory => '.', :build_legacy => true, :build_modern => true
 
     add_option '-d', '--directory=DIRNAME',
                'repository base dir containing gems subdir' do |dir, options|
       options[:directory] = File.expand_path dir
     end
+
+    add_option '--[no-]legacy',
+               'Generate indexes for RubyGems older than',
+               '1.2.0' do |value, options|
+      unless options[:build_modern] or value then
+        raise OptionParser::InvalidOption, 'no indicies will be built'
+      end
+
+      options[:build_legacy] = value
+    end
+
+    add_option '--[no-]modern',
+               'Generate indexes for RubyGems newer',
+               'than 1.2.0' do |value, options|
+      unless options[:build_legacy] or value then
+        raise OptionParser::InvalidOption, 'no indicies will be built'
+      end
+
+      options[:build_modern] = value
+    end
+
+    add_option '--update',
+               'Update modern indexes with gems added',
+               'since the last update' do |value, options|
+      options[:update] = value
+    end
+
+    add_option :RSS, '--rss-gems-host=GEM_HOST',
+               'Host name where gems are served from,',
+               'used for GUID and enclosure values' do |value, options|
+      options[:rss_gems_host] = value
+    end
+
+    add_option :RSS, '--rss-host=HOST',
+               'Host name for more gems information,',
+               'used for RSS feed link' do |value, options|
+      options[:rss_host] = value
+    end
+
+    add_option :RSS, '--rss-title=TITLE',
+               'Set title for RSS feed' do |value, options|
+      options[:rss_title] = value
+    end
   end
 
   def defaults_str # :nodoc:
-    "--directory ."
+    "--directory . --legacy --modern"
   end
 
   def description # :nodoc:
     <<-EOF
 The generate_index command creates a set of indexes for serving gems
 statically.  The command expects a 'gems' directory under the path given to
-the --directory option.  When done, it will generate a set of files like this:
+the --directory option.  The given directory will be the directory you serve
+as the gem repository.
 
-  gems/                                        # .gem files you want to index
+For `gem generate_index --directory /path/to/repo`, expose /path/to/repo via
+your HTTP server configuration (not /path/to/repo/gems).
+
+When done, it will generate a set of files like this:
+
+  gems/*.gem                                   # .gem files you want to
+                                               # index
+
+  specs.<version>.gz                           # specs index
+  latest_specs.<version>.gz                    # latest specs index
+  prerelease_specs.<version>.gz                # prerelease specs index
+  quick/Marshal.<version>/<gemname>.gemspec.rz # Marshal quick index file
+
+  # these files support legacy RubyGems
   quick/index
   quick/index.rz                               # quick index manifest
-  quick/<gemname>.gemspec.rz                   # legacy YAML quick index file
-  quick/Marshal.<version>/<gemname>.gemspec.rz # Marshal quick index file
+  quick/<gemname>.gemspec.rz                   # legacy YAML quick index
+                                               # file
   Marshal.<version>
-  Marshal.<version>.Z # Marshal full index
+  Marshal.<version>.Z                          # Marshal full index
   yaml
-  yaml.Z # legacy YAML full index
+  yaml.Z                                       # legacy YAML full index
 
-The .Z and .rz extension files are compressed with the inflate algorithm.  The
-Marshal version number comes from ruby's Marshal::MAJOR_VERSION and
-Marshal::MINOR_VERSION constants.  It is used to ensure compatibility.  The
-yaml indexes exist for legacy RubyGems clients and fallback in case of Marshal
-version changes.
+The .Z and .rz extension files are compressed with the inflate algorithm.
+The Marshal version number comes from ruby's Marshal::MAJOR_VERSION and
+Marshal::MINOR_VERSION constants.  It is used to ensure compatibility.
+The yaml indexes exist for legacy RubyGems clients and fallback in case of
+Marshal version changes.
+
+If --rss-host and --rss-gem-host are given an RSS feed will be generated at
+index.rss containing gems released in the last two days.
     EOF
   end
 
   def execute
+    if options[:update] and
+       (options[:rss_host] or options[:rss_gems_host]) then
+      alert_error '--update not compatible with RSS generation'
+      terminate_interaction 1
+    end
+
     if not File.exist?(options[:directory]) or
        not File.directory?(options[:directory]) then
       alert_error "unknown directory name #{directory}."
       terminate_interaction 1
     else
-      indexer = Gem::Indexer.new options[:directory]
-      indexer.generate_index
+      indexer = Gem::Indexer.new options.delete(:directory), options
+
+      if options[:update] then
+        indexer.update_index
+      else
+        indexer.generate_index
+      end
     end
   end
 
Index: lib/rubygems/commands/update_command.rb
===================================================================
--- lib/rubygems/commands/update_command.rb	(revision 23658)
+++ lib/rubygems/commands/update_command.rb	(revision 23659)
@@ -16,9 +16,9 @@
     super 'update',
           'Update the named gems (or all installed gems) in the local repository',
       :generate_rdoc => true,
-      :generate_ri => true,
-      :force => false,
-      :test => false
+      :generate_ri   => true,
+      :force         => false,
+      :test          => false
 
     add_install_update_options
 
@@ -80,20 +80,27 @@
 
     gems_to_update.uniq.sort.each do |name|
       next if updated.any? { |spec| spec.name == name }
+      success = false
 
       say "Updating #{name}"
-      installer.install name
+      begin
+        installer.install name
+        success = true
+      rescue Gem::InstallError => e
+        alert_error "Error installing #{name}:\n\t#{e.message}"
+        success = false
+      end
 
       installer.installed_gems.each do |spec|
         updated << spec
-        say "Successfully installed #{spec.full_name}"
+        say "Successfully installed #{spec.full_name}" if success
       end
     end
 
     if gems_to_update.include? "rubygems-update" then
       Gem.source_index.refresh!
 
-      update_gems = Gem.source_index.search 'rubygems-update'
+      update_gems = Gem.source_index.find_name 'rubygems-update'
 
       latest_update_gem = update_gems.sort_by { |s| s.version }.last
 
@@ -106,6 +113,20 @@
         say "Nothing to update"
       else
         say "Gems updated: #{updated.map { |spec| spec.name }.join ', '}"
+
+        if options[:generate_ri] then
+          updated.each do |gem|
+            Gem::DocManager.new(gem, options[:rdoc_args]).generate_ri
+          end
+
+          Gem::DocManager.update_ri_cache
+        end
+
+        if options[:generate_rdoc] then
+          updated.each do |gem|
+            Gem::DocManager.new(gem, options[:rdoc_args]).generate_rdoc
+          end
+        end
       end
     end
   end
Index: lib/rubygems/commands/sources_command.rb
===================================================================
--- lib/rubygems/commands/sources_command.rb	(revision 23658)
+++ lib/rubygems/commands/sources_command.rb	(revision 23659)
@@ -3,9 +3,12 @@
 require 'rubygems/remote_fetcher'
 require 'rubygems/source_info_cache'
 require 'rubygems/spec_fetcher'
+require 'rubygems/local_remote_options'
 
 class Gem::Commands::SourcesCommand < Gem::Command
 
+  include Gem::LocalRemoteOptions
+
   def initialize
     super 'sources',
           'Manage the sources and cache file RubyGems uses to search for gems'
@@ -30,6 +33,8 @@
     add_option '-u', '--update', 'Update source cache' do |value, options|
       options[:update] = value
     end
+
+    add_proxy_option
   end
 
   def defaults_str
Index: lib/rubygems/commands/rdoc_command.rb
===================================================================
--- lib/rubygems/commands/rdoc_command.rb	(revision 23658)
+++ lib/rubygems/commands/rdoc_command.rb	(revision 23659)
@@ -2,81 +2,75 @@
 require 'rubygems/version_option'
 require 'rubygems/doc_manager'
 
-module Gem
-  module Commands
-    class RdocCommand < Command
-      include VersionOption
+class Gem::Commands::RdocCommand < Gem::Command
+  include Gem::VersionOption
 
-      def initialize
-        super('rdoc',
-          'Generates RDoc for pre-installed gems',
-          {
-            :version => Gem::Requirement.default,
-            :include_rdoc => true,
-            :include_ri => true,
-          })
-        add_option('--all',
-                   'Generate RDoc/RI documentation for all',
-                   'installed gems') do |value, options|
-          options[:all] = value
-        end
-        add_option('--[no-]rdoc',
-          'Include RDoc generated documents') do
-          |value, options|
-          options[:include_rdoc] = value
-        end
-        add_option('--[no-]ri',
-          'Include RI generated documents'
-          ) do |value, options|
-          options[:include_ri] = value
-        end
-        add_version_option
-      end
+  def initialize
+    super 'rdoc', 'Generates RDoc for pre-installed gems',
+          :version => Gem::Requirement.default,
+          :include_rdoc => true, :include_ri => true
 
-      def arguments # :nodoc:
-        "GEMNAME       gem to generate documentation for (unless --all)"
-      end
+    add_option('--all',
+               'Generate RDoc/RI documentation for all',
+               'installed gems') do |value, options|
+      options[:all] = value
+    end
 
-      def defaults_str # :nodoc:
-        "--version '#{Gem::Requirement.default}' --rdoc --ri"
-      end
+    add_option('--[no-]rdoc',
+               'Include RDoc generated documents') do |value, options|
+      options[:include_rdoc] = value
+    end
 
-      def usage # :nodoc:
-        "#{program_name} [args]"
-      end
+    add_option('--[no-]ri',
+               'Include RI generated documents') do |value, options|
+      options[:include_ri] = value
+    end
 
-      def execute
-        if options[:all]
-          specs = Gem::SourceIndex.from_installed_gems.collect { |name, spec|
-            spec
-          }
-        else
-          gem_name = get_one_gem_name
-          specs = Gem::SourceIndex.from_installed_gems.search(
-            gem_name, options[:version])
-        end
+    add_version_option
+  end
 
-        if specs.empty?
-          fail "Failed to find gem #{gem_name} to generate RDoc for #{options[:version]}"
-        end
+  def arguments # :nodoc:
+    "GEMNAME       gem to generate documentation for (unless --all)"
+  end
 
-        if options[:include_ri]
-          specs.each do |spec|
-            Gem::DocManager.new(spec).generate_ri
-          end
+  def defaults_str # :nodoc:
+    "--version '#{Gem::Requirement.default}' --rdoc --ri"
+  end
 
-          Gem::DocManager.update_ri_cache
-        end
+  def usage # :nodoc:
+    "#{program_name} [args]"
+  end
 
-        if options[:include_rdoc]
-          specs.each do |spec|
-            Gem::DocManager.new(spec).generate_rdoc
-          end
-        end
+  def execute
+    if options[:all] then
+      specs = Gem::SourceIndex.from_installed_gems.collect { |name, spec|
+        spec
+      }
+    else
+      gem_name = get_one_gem_name
+      dep = Gem::Dependency.new gem_name, options[:version]
+      specs = Gem::SourceIndex.from_installed_gems.search dep
+    end
 
-        true
+    if specs.empty?
+      fail "Failed to find gem #{gem_name} to generate RDoc for #{options[:version]}"
+    end
+
+    if options[:include_ri]
+      specs.each do |spec|
+        Gem::DocManager.new(spec).generate_ri
       end
+
+      Gem::DocManager.update_ri_cache
     end
 
+    if options[:include_rdoc]
+      specs.each do |spec|
+        Gem::DocManager.new(spec).generate_rdoc
+      end
+    end
+
+    true
   end
 end
+
Index: lib/rubygems/commands/cleanup_command.rb
===================================================================
--- lib/rubygems/commands/cleanup_command.rb	(revision 23658)
+++ lib/rubygems/commands/cleanup_command.rb	(revision 23659)
@@ -1,6 +1,7 @@
 require 'rubygems/command'
 require 'rubygems/source_index'
 require 'rubygems/dependency_list'
+require 'rubygems/uninstaller'
 
 class Gem::Commands::CleanupCommand < Gem::Command
 
@@ -22,6 +23,13 @@
     "--no-dryrun"
   end
 
+  def description # :nodoc:
+    <<-EOF
+The cleanup command removes old gems from GEM_HOME.  If an older version is
+installed elsewhere in GEM_PATH the cleanup command won't touch it.
+    EOF
+  end
+
   def usage # :nodoc:
     "#{program_name} [GEMNAME ...]"
   end
@@ -41,7 +49,8 @@
 
     unless options[:args].empty? then
       options[:args].each do |gem_name|
-        specs = Gem.cache.search(/^#{gem_name}$/i)
+        dep = Gem::Dependency.new gem_name, Gem::Requirement.default
+        specs = Gem.source_index.search dep
         specs.each do |spec|
           gems_to_cleanup << spec
         end
@@ -56,7 +65,6 @@
       primary_gems[spec.name].version != spec.version
     }
 
-    uninstall_command = Gem::CommandManager.instance['uninstall']
     deplist = Gem::DependencyList.new
     gems_to_cleanup.uniq.each do |spec| deplist.add spec end
 
@@ -69,14 +77,21 @@
         say "Attempting to uninstall #{spec.full_name}"
 
         options[:args] = [spec.name]
-        options[:version] = "= #{spec.version}"
-        options[:executables] = false
 
-        uninstaller = Gem::Uninstaller.new spec.name, options
+        uninstall_options = {
+          :executables => false,
+          :version => "= #{spec.version}",
+        }
 
+        if Gem.user_dir == spec.installation_path then
+          uninstall_options[:install_dir] = spec.installation_path
+        end
+
+        uninstaller = Gem::Uninstaller.new spec.name, uninstall_options
+
         begin
           uninstaller.uninstall
-        rescue Gem::DependencyRemovalException,
+        rescue Gem::DependencyRemovalException, Gem::InstallError,
                Gem::GemNotInHomeException => e
           say "Unable to uninstall #{spec.full_name}:"
           say "\t#{e.class}: #{e.message}"
Index: lib/rubygems/commands/contents_command.rb
===================================================================
--- lib/rubygems/commands/contents_command.rb	(revision 23658)
+++ lib/rubygems/commands/contents_command.rb	(revision 23659)
@@ -11,6 +11,11 @@
 
     add_version_option
 
+    add_option(      '--all',
+               "Contents for all gems") do |all, options|
+      options[:all] = all
+    end
+
     add_option('-s', '--spec-dir a,b,c', Array,
                "Search for gems under specific paths") do |spec_dirs, options|
       options[:specdirs] = spec_dirs
@@ -20,6 +25,11 @@
                "Only return files in the Gem's lib_dirs") do |lib_only, options|
       options[:lib_only] = lib_only
     end
+
+    add_option(      '--[no-]prefix',
+               "Don't include installed path prefix") do |prefix, options|
+      options[:prefix] = prefix
+    end
   end
 
   def arguments # :nodoc:
@@ -27,46 +37,60 @@
   end
 
   def defaults_str # :nodoc:
-    "--no-lib-only"
+    "--no-lib-only --prefix"
   end
 
   def usage # :nodoc:
-    "#{program_name} GEMNAME"
+    "#{program_name} GEMNAME [GEMNAME ...]"
   end
 
   def execute
     version = options[:version] || Gem::Requirement.default
-    gem = get_one_gem_name
 
-    s = options[:specdirs].map do |i|
+    spec_dirs = options[:specdirs].map do |i|
       [i, File.join(i, "specifications")]
     end.flatten
 
-    path_kind = if s.empty? then
-                  s = Gem::SourceIndex.installed_spec_directories
+    path_kind = if spec_dirs.empty? then
+                  spec_dirs = Gem::SourceIndex.installed_spec_directories
                   "default gem paths"
                 else
                   "specified path"
                 end
 
-    si = Gem::SourceIndex.from_gems_in(*s)
+    si = Gem::SourceIndex.from_gems_in(*spec_dirs)
 
-    gem_spec = si.find_name(gem, version).last
+    gem_names = if options[:all] then
+                  si.map { |_, spec| spec.name }
+                else
+                  get_all_gem_names
+                end
 
-    unless gem_spec then
-      say "Unable to find gem '#{gem}' in #{path_kind}"
+    gem_names.each do |name|
+      gem_spec = si.find_name(name, version).last
 
-      if Gem.configuration.verbose then
-        say "\nDirectories searched:"
-        s.each { |dir| say dir }
+      unless gem_spec then
+        say "Unable to find gem '#{name}' in #{path_kind}"
+
+        if Gem.configuration.verbose then
+          say "\nDirectories searched:"
+          spec_dirs.each { |dir| say dir }
+        end
+
+        terminate_interaction 1 if gem_names.length == 1
       end
 
-      terminate_interaction
-    end
+      files = options[:lib_only] ? gem_spec.lib_files : gem_spec.files
 
-    files = options[:lib_only] ? gem_spec.lib_files : gem_spec.files
-    files.each do |f|
-      say File.join(gem_spec.full_gem_path, f)
+      files.each do |f|
+        path = if options[:prefix] then
+                 File.join gem_spec.full_gem_path, f
+               else
+                 f
+               end
+
+        say path
+      end
     end
   end
 
Index: lib/rubygems/commands/setup_command.rb
===================================================================
--- lib/rubygems/commands/setup_command.rb	(revision 0)
+++ lib/rubygems/commands/setup_command.rb	(revision 23659)
@@ -0,0 +1,353 @@
+require 'rubygems/command'
+require 'fileutils'
+require 'rbconfig'
+require 'tmpdir'
+require 'pathname'
+
+##
+# Installs RubyGems itself.  This command is ordinarily only available from a
+# RubyGems checkout or tarball.
+
+class Gem::Commands::SetupCommand < Gem::Command
+
+  def initialize
+    super 'setup', 'Install RubyGems',
+          :format_executable => true, :rdoc => true, :ri => true,
+          :site_or_vendor => :sitelibdir,
+          :destdir => '', :prefix => ''
+
+    add_option '--prefix=PREFIX',
+               'Prefix path for installing RubyGems',
+               'Will not affect gem repository location' do |prefix, options|
+      options[:prefix] = File.expand_path prefix
+    end
+
+    add_option '--destdir=DESTDIR',
+               'Root directory to install RubyGems into',
+               'Mainly used for packaging RubyGems' do |destdir, options|
+      options[:destdir] = File.expand_path destdir
+    end
+
+    add_option '--[no-]vendor',
+               'Install into vendorlibdir not sitelibdir',
+               '(Requires Ruby 1.8.7)' do |vendor, options|
+      if vendor and Gem.ruby_version < Gem::Version.new('1.8.7') then
+        raise OptionParser::InvalidOption,
+              "requires ruby 1.8.7+ (you have #{Gem.ruby_version})"
+      end
+
+      options[:site_or_vendor] = vendor ? :vendorlibdir : :sitelibdir
+    end
+
+    add_option '--[no-]format-executable',
+               'Makes `gem` match ruby',
+               'If ruby is ruby18, gem will be gem18' do |value, options|
+      options[:format_executable] = value
+    end
+
+    add_option '--[no-]rdoc',
+               'Generate RDoc documentation for RubyGems' do |value, options|
+      options[:rdoc] = value
+    end
+
+    add_option '--[no-]ri',
+               'Generate RI documentation for RubyGems' do |value, options|
+      options[:ri] = value
+    end
+  end
+
+  def check_ruby_version
+    required_version = Gem::Requirement.new '>= 1.8.6'
+
+    unless required_version.satisfied_by? Gem.ruby_version then
+      alert_error "Expected Ruby version #{required_version}, is #{Gem.ruby_version}"
+      terminate_interaction 1
+    end
+  end
+
+  def defaults_str # :nodoc:
+    "--format-executable --rdoc --ri"
+  end
+
+  def description # :nodoc:
+    <<-EOF
+Installs RubyGems itself.
+
+RubyGems installs RDoc for itself in GEM_HOME.  By default this is:
+  #{Gem.dir}
+
+If you prefer a different directory, set the GEM_HOME environment variable.
+
+RubyGems will install the gem command with a name matching ruby's
+prefix and suffix.  If ruby was installed as `ruby18`, gem will be
+installed as `gem18`.
+
+By default, this RubyGems will install gem as:
+  #{Gem.default_exec_format % 'gem'}
+    EOF
+  end
+
+  def execute
+    install_destdir = options[:destdir]
+
+    unless install_destdir.empty? then
+      ENV['GEM_HOME'] ||= File.join(install_destdir,
+                                    Gem.default_dir.gsub(/^[a-zA-Z]:/, ''))
+    end
+
+    check_ruby_version
+
+    if Gem.configuration.really_verbose then
+      extend FileUtils::Verbose
+    else
+      extend FileUtils
+    end
+
+    lib_dir, bin_dir = make_destination_dirs install_destdir
+
+    install_lib lib_dir
+
+    install_executables bin_dir
+
+    remove_old_bin_files bin_dir
+
+    remove_source_caches install_destdir
+
+    install_rdoc
+
+    say
+    say "-" * 78
+    say
+
+    release_notes = File.join Dir.pwd, 'doc', 'release_notes',
+                              "rel_#{Gem::RubyGemsVersion.gsub '.', '_'}.rdoc"
+
+    if File.exist? release_notes then
+      say File.read(release_notes)
+    else
+      say "Oh-no! Unable to find release notes!"
+      say "Looked in: #{release_notes}" if Gem.configuration.really_verbose
+    end
+
+    say
+    say "-" * 78
+    say
+
+    say "RubyGems installed the following executables:"
+    say @bin_file_names.map { |name| "\t#{name}\n" }
+    say
+
+    unless @bin_file_names.grep(/#{File::SEPARATOR}gem$/) then
+      say "If `gem` was installed by a previous RubyGems installation, you may need"
+      say "to remove it by hand."
+      say
+    end
+  end
+
+  def install_executables(bin_dir)
+    say "Installing gem executable"
+
+    @bin_file_names = []
+
+    Dir.chdir 'bin' do
+      bin_files = Dir['*']
+
+      bin_files.delete 'update_rubygems'
+
+      bin_files.each do |bin_file|
+        bin_file_formatted = if options[:format_executable] then
+                               Gem.default_exec_format % bin_file
+                             else
+                               bin_file
+                             end
+
+        dest_file = File.join bin_dir, bin_file_formatted
+        bin_tmp_file = File.join Dir.tmpdir, bin_file
+
+        begin
+          bin = File.readlines bin_file
+          bin[0] = "#!#{Gem.ruby}\n"
+
+          File.open bin_tmp_file, 'w' do |fp|
+            fp.puts bin.join
+          end
+
+          install bin_tmp_file, dest_file, :mode => 0755
+          @bin_file_names << dest_file
+        ensure
+          rm bin_tmp_file
+        end
+
+        next unless Gem.win_platform?
+
+        begin
+          bin_cmd_file = File.join Dir.tmpdir, "#{bin_file}.bat"
+
+          File.open bin_cmd_file, 'w' do |file|
+            file.puts <<-TEXT
+@ECHO OFF
+IF NOT "%~f0" == "~f0" GOTO :WinNT
+@"#{File.basename(Gem.ruby).chomp('"')}" "#{dest_file}" %1 %2 %3 %4 %5 %6 %7 %8 %9
+GOTO :EOF
+:WinNT
+@"#{File.basename(Gem.ruby).chomp('"')}" "%~dpn0" %*
+TEXT
+          end
+
+          install bin_cmd_file, "#{dest_file}.bat", :mode => 0755
+        ensure
+          rm bin_cmd_file
+        end
+      end
+    end
+  end
+
+  def install_lib(lib_dir)
+    say "Installing RubyGems"
+
+    Dir.chdir 'lib' do
+      lib_files = Dir[File.join('**', '*rb')]
+
+      lib_files.each do |lib_file|
+        dest_file = File.join lib_dir, lib_file
+        dest_dir = File.dirname dest_file
+        mkdir_p dest_dir unless File.directory? dest_dir
+
+        install lib_file, dest_file, :mode => 0644
+      end
+    end
+  end
+
+  def install_rdoc
+    gem_doc_dir = File.join Gem.dir, 'doc'
+    rubygems_name = "rubygems-#{Gem::RubyGemsVersion}"
+    rubygems_doc_dir = File.join gem_doc_dir, rubygems_name
+
+    if File.writable? gem_doc_dir and
+       (not File.exist? rubygems_doc_dir or
+        File.writable? rubygems_doc_dir) then
+      say "Removing old RubyGems RDoc and ri"
+      Dir[File.join(Gem.dir, 'doc', 'rubygems-[0-9]*')].each do |dir|
+        rm_rf dir
+      end
+
+      if options[:ri] then
+        ri_dir = File.join rubygems_doc_dir, 'ri'
+        say "Installing #{rubygems_name} ri into #{ri_dir}"
+        run_rdoc '--ri', '--op', ri_dir
+      end
+
+      if options[:rdoc] then
+        rdoc_dir = File.join rubygems_doc_dir, 'rdoc'
+        say "Installing #{rubygems_name} rdoc into #{rdoc_dir}"
+        run_rdoc '--op', rdoc_dir
+      end
+    else
+      say "Skipping RDoc generation, #{gem_doc_dir} not writable"
+      say "Set the GEM_HOME environment variable if you want RDoc generated"
+    end
+  end
+
+  def make_destination_dirs(install_destdir)
+    lib_dir = nil
+    bin_dir = nil
+
+    prefix = options[:prefix]
+    site_or_vendor = options[:site_or_vendor]
+
+    if prefix.empty? then
+      lib_dir = Gem::ConfigMap[site_or_vendor]
+      bin_dir = Gem::ConfigMap[:bindir]
+    else
+      # Apple installed RubyGems into libdir, and RubyGems <= 1.1.0 gets
+      # confused about installation location, so switch back to
+      # sitelibdir/vendorlibdir.
+      if defined?(APPLE_GEM_HOME) and
+        # just in case Apple and RubyGems don't get this patched up proper.
+        (prefix == Gem::ConfigMap[:libdir] or
+         # this one is important
+         prefix == File.join(Gem::ConfigMap[:libdir], 'ruby')) then
+         lib_dir = Gem::ConfigMap[site_or_vendor]
+         bin_dir = Gem::ConfigMap[:bindir]
+      else
+        lib_dir = File.join prefix, 'lib'
+        bin_dir = File.join prefix, 'bin'
+      end
+    end
+
+    unless install_destdir.empty? then
+      lib_dir = File.join install_destdir, lib_dir.gsub(/^[a-zA-Z]:/, '')
+      bin_dir = File.join install_destdir, bin_dir.gsub(/^[a-zA-Z]:/, '')
+    end
+
+    mkdir_p lib_dir
+    mkdir_p bin_dir
+
+    return lib_dir, bin_dir
+  end
+
+  def remove_old_bin_files(bin_dir)
+    old_bin_files = {
+      'gem_mirror' => 'gem mirror',
+      'gem_server' => 'gem server',
+      'gemlock' => 'gem lock',
+      'gemri' => 'ri',
+      'gemwhich' => 'gem which',
+      'index_gem_repository.rb' => 'gem generate_index',
+    }
+
+    old_bin_files.each do |old_bin_file, new_name|
+      old_bin_path = File.join bin_dir, old_bin_file
+      next unless File.exist? old_bin_path
+
+      deprecation_message = "`#{old_bin_file}` has been deprecated.  Use `#{new_name}` instead."
+
+      File.open old_bin_path, 'w' do |fp|
+        fp.write <<-EOF
+#!#{Gem.ruby}
+
+abort "#{deprecation_message}"
+    EOF
+      end
+
+      next unless Gem.win_platform?
+
+      File.open "#{old_bin_path}.bat", 'w' do |fp|
+        fp.puts %{@ECHO.#{deprecation_message}}
+      end
+    end
+  end
+
+  def remove_source_caches(install_destdir)
+    if install_destdir.empty?
+      require 'rubygems/source_info_cache'
+
+      user_cache_file = File.join(install_destdir,
+                                  Gem::SourceInfoCache.user_cache_file)
+      system_cache_file = File.join(install_destdir,
+                                    Gem::SourceInfoCache.system_cache_file)
+
+      say "Removing old source_cache files"
+      rm_f user_cache_file if File.writable? File.dirname(user_cache_file)
+      rm_f system_cache_file if File.writable? File.dirname(system_cache_file)
+    end
+  end
+
+  def run_rdoc(*args)
+    begin
+      gem 'rdoc'
+    rescue Gem::LoadError
+    end
+
+    require 'rdoc/rdoc'
+
+    args << '--quiet'
+    args << '--main' << 'README'
+    args << '.' << 'README' << 'LICENSE.txt' << 'GPL.txt'
+
+    r = RDoc::RDoc.new
+    r.document args
+  end
+
+end
+
Index: lib/rubygems/commands/which_command.rb
===================================================================
--- lib/rubygems/commands/which_command.rb	(revision 23658)
+++ lib/rubygems/commands/which_command.rb	(revision 23659)
@@ -46,7 +46,7 @@
         end
 
         say "(checking gem #{spec.full_name} for #{arg})" if
-          Gem.configuration.verbose
+          Gem.configuration.verbose and $stdout.tty?
       end
 
       paths = find_paths arg, dirs
Index: lib/rubygems/commands/query_command.rb
===================================================================
--- lib/rubygems/commands/query_command.rb	(revision 23658)
+++ lib/rubygems/commands/query_command.rb	(revision 23659)
@@ -2,9 +2,11 @@
 require 'rubygems/local_remote_options'
 require 'rubygems/spec_fetcher'
 require 'rubygems/version_option'
+require 'rubygems/text'
 
 class Gem::Commands::QueryCommand < Gem::Command
 
+  include Gem::Text
   include Gem::LocalRemoteOptions
   include Gem::VersionOption
 
@@ -43,6 +45,11 @@
       options[:all] = value
     end
 
+    add_option(      '--prerelease',
+               'Display prerelease versions') do |value, options|
+      options[:prerelease] = value
+    end
+
     add_local_remote_options
   end
 
@@ -54,6 +61,7 @@
     exit_code = 0
 
     name = options[:name]
+    prerelease = options[:prerelease]
 
     if options[:installed] then
       if name.source.empty? then
@@ -72,6 +80,10 @@
     dep = Gem::Dependency.new name, Gem::Requirement.default
 
     if local? then
+      if prerelease and not both? then
+        alert_warning "prereleases are always shown locally"
+      end
+
       if ui.outs.tty? or both? then
         say
         say "*** LOCAL GEMS ***"
@@ -98,8 +110,13 @@
 
       begin
         fetcher = Gem::SpecFetcher.fetcher
-        spec_tuples = fetcher.find_matching dep, all, false
+        spec_tuples = fetcher.find_matching dep, all, false, prerelease
       rescue Gem::RemoteFetcher::FetchError => e
+        if prerelease then
+          raise Gem::OperationNotSupportedError,
+                "Prereleases not supported on legacy repositories"
+        end
+
         raise unless fetcher.warn_legacy e do
           require 'rubygems/source_info_cache'
 
@@ -145,6 +162,12 @@
         version
       end.reverse
 
+      platforms = Hash.new { |h,version| h[version] = [] }
+
+      matching_tuples.map do |(name, version, platform,_),_|
+        platforms[version] << platform if platform
+      end
+
       seen = {}
 
       matching_tuples.delete_if do |(name, version,_),_|
@@ -174,6 +197,28 @@
                end
 
         entry << "\n"
+
+        non_ruby = platforms.any? do |_, pls|
+          pls.any? { |pl| pl != Gem::Platform::RUBY }
+        end
+
+        if non_ruby then
+          if platforms.length == 1 then
+            title = platforms.values.length == 1 ? 'Platform' : 'Platforms'
+            entry << "    #{title}: #{platforms.values.sort.join ', '}\n"
+          else
+            entry << "    Platforms:\n"
+            platforms.sort_by do |version,|
+              version
+            end.each do |version, pls|
+              label = "        #{version}: "
+              data = format_text pls.sort.join(', '), 68, label.length
+              data[0, label.length] = label
+              entry << data << "\n"
+            end
+          end
+        end
+
         authors = "Author#{spec.authors.length > 1 ? 's' : ''}: "
         authors << spec.authors.join(', ')
         entry << format_text(authors, 68, 4)
@@ -187,6 +232,12 @@
           entry << "\n" << format_text("Homepage: #{spec.homepage}", 68, 4)
         end
 
+        if spec.license and not spec.license.empty? then
+          licenses = "License#{spec.licenses.length > 1 ? 's' : ''}: "
+          licenses << spec.licenses.join(', ')
+          entry << "\n" << format_text(licenses, 68, 4)
+        end
+
         if spec.loaded_from then
           if matching_tuples.length == 1 then
             loaded_from = File.dirname File.dirname(spec.loaded_from)
@@ -209,25 +260,5 @@
     say output.join(options[:details] ? "\n\n" : "\n")
   end
 
-  ##
-  # Used for wrapping and indenting text
-
-  def format_text(text, wrap, indent=0)
-    result = []
-    work = text.dup
-
-    while work.length > wrap
-      if work =~ /^(.{0,#{wrap}})[ \n]/o then
-        result << $1
-        work.slice!(0, $&.length)
-      else
-        result << work.slice!(0, wrap)
-      end
-    end
-
-    result << work if work.length.nonzero?
-    result.join("\n").gsub(/^/, " " * indent)
-  end
-
 end
 
Index: lib/rubygems/commands/search_command.rb
===================================================================
--- lib/rubygems/commands/search_command.rb	(revision 23658)
+++ lib/rubygems/commands/search_command.rb	(revision 23659)
@@ -1,37 +1,31 @@
 require 'rubygems/command'
 require 'rubygems/commands/query_command'
 
-module Gem
-  module Commands
+class Gem::Commands::SearchCommand < Gem::Commands::QueryCommand
 
-    class SearchCommand < QueryCommand
+  def initialize
+    super 'search', 'Display all gems whose name contains STRING'
 
-      def initialize
-        super(
-          'search',
-          'Display all gems whose name contains STRING'
-        )
-        remove_option('--name-matches')
-      end
+    remove_option '--name-matches'
+  end
 
-      def arguments # :nodoc:
-        "STRING        fragment of gem name to search for"
-      end
+  def arguments # :nodoc:
+    "STRING        fragment of gem name to search for"
+  end
 
-      def defaults_str # :nodoc:
-        "--local --no-details"
-      end
+  def defaults_str # :nodoc:
+    "--local --no-details"
+  end
 
-      def usage # :nodoc:
-        "#{program_name} [STRING]"
-      end
+  def usage # :nodoc:
+    "#{program_name} [STRING]"
+  end
 
-      def execute
-        string = get_one_optional_argument
-        options[:name] = /#{string}/i
-        super
-      end
-    end
-
+  def execute
+    string = get_one_optional_argument
+    options[:name] = /#{string}/i
+    super
   end
+
 end
+
Index: lib/rubygems/commands/install_command.rb
===================================================================
--- lib/rubygems/commands/install_command.rb	(revision 23658)
+++ lib/rubygems/commands/install_command.rb	(revision 23659)
@@ -6,6 +6,11 @@
 require 'rubygems/validator'
 require 'rubygems/version_option'
 
+##
+# Gem installer command line tool
+#
+# See `gem help install`
+
 class Gem::Commands::InstallCommand < Gem::Command
 
   include Gem::VersionOption
@@ -14,11 +19,11 @@
 
   def initialize
     defaults = Gem::DependencyInstaller::DEFAULT_OPTIONS.merge({
-      :generate_rdoc => true,
-      :generate_ri   => true,
+      :generate_rdoc     => true,
+      :generate_ri       => true,
       :format_executable => false,
-      :test => false,
-      :version => Gem::Requirement.default,
+      :test              => false,
+      :version           => Gem::Requirement.default,
     })
 
     super 'install', 'Install a gem into the local repository', defaults
@@ -43,11 +48,51 @@
 The install command installs local or remote gem into a gem repository.
 
 For gems with executables ruby installs a wrapper file into the executable
-directory by deault.  This can be overridden with the --no-wrappers option.
+directory by default.  This can be overridden with the --no-wrappers option.
 The wrapper allows you to choose among alternate gem versions using _version_.
 
 For example `rake _0.7.3_ --version` will run rake version 0.7.3 if a newer
 version is also installed.
+
+If an extension fails to compile during gem installation the gem
+specification is not written out, but the gem remains unpacked in the
+repository.  You may need to specify the path to the library's headers and
+libraries to continue.  You can do this by adding a -- between RubyGems'
+options and the extension's build options:
+
+  $ gem install some_extension_gem
+  [build fails]
+  Gem files will remain installed in \\
+  /path/to/gems/some_extension_gem-1.0 for inspection.
+  Results logged to /path/to/gems/some_extension_gem-1.0/gem_make.out
+  $ gem install some_extension_gem -- --with-extension-lib=/path/to/lib
+  [build succeeds]
+  $ gem list some_extension_gem
+
+  *** LOCAL GEMS ***
+
+  some_extension_gem (1.0)
+  $
+
+If you correct the compilation errors by editing the gem files you will need
+to write the specification by hand.  For example:
+
+  $ gem install some_extension_gem
+  [build fails]
+  Gem files will remain installed in \\
+  /path/to/gems/some_extension_gem-1.0 for inspection.
+  Results logged to /path/to/gems/some_extension_gem-1.0/gem_make.out
+  $ [cd /path/to/gems/some_extension_gem-1.0]
+  $ [edit files or what-have-you and run make]
+  $ gem spec ../../cache/some_extension_gem-1.0.gem --ruby > \\
+             ../../specifications/some_extension_gem-1.0.gemspec
+  $ gem list some_extension_gem
+
+  *** LOCAL GEMS ***
+
+  some_extension_gem (1.0)
+  $
+
     EOF
   end
 
@@ -65,24 +110,11 @@
 
     ENV.delete 'GEM_PATH' if options[:install_dir].nil? and RUBY_VERSION > '1.9'
 
-    install_options = {
-      :env_shebang => options[:env_shebang],
-      :domain => options[:domain],
-      :force => options[:force],
-      :format_executable => options[:format_executable],
-      :ignore_dependencies => options[:ignore_dependencies],
-      :install_dir => options[:install_dir],
-      :security_policy => options[:security_policy],
-      :wrappers => options[:wrappers],
-      :bin_dir => options[:bin_dir],
-      :development => options[:development],
-    }
-
     exit_code = 0
 
     get_all_gem_names.each do |gem_name|
       begin
-        inst = Gem::DependencyInstaller.new install_options
+        inst = Gem::DependencyInstaller.new options
         inst.install gem_name, options[:version]
 
         inst.installed_gems.each do |spec|
@@ -96,46 +128,40 @@
       rescue Gem::GemNotFoundException => e
         alert_error e.message
         exit_code |= 2
-#      rescue => e
-#        # TODO: Fix this handle to allow the error to propagate to
-#        # the top level handler.  Examine the other errors as
-#        # well.  This implementation here looks suspicious to me --
-#        # JimWeirich (4/Jan/05)
-#        alert_error "Error installing gem #{gem_name}: #{e.message}"
-#        return
       end
     end
 
     unless installed_gems.empty? then
       gems = installed_gems.length == 1 ? 'gem' : 'gems'
       say "#{installed_gems.length} #{gems} installed"
-    end
 
-    # NOTE: *All* of the RI documents must be generated first.
-    # For some reason, RI docs cannot be generated after any RDoc
-    # documents are generated.
+      # NOTE: *All* of the RI documents must be generated first.  For some
+      # reason, RI docs cannot be generated after any RDoc documents are
+      # generated.
 
-    if options[:generate_ri] then
-      installed_gems.each do |gem|
-        Gem::DocManager.new(gem, options[:rdoc_args]).generate_ri
+      if options[:generate_ri] then
+        installed_gems.each do |gem|
+          Gem::DocManager.new(gem, options[:rdoc_args]).generate_ri
+        end
+
+        Gem::DocManager.update_ri_cache
       end
 
-      Gem::DocManager.update_ri_cache
-    end
-
-    if options[:generate_rdoc] then
-      installed_gems.each do |gem|
-        Gem::DocManager.new(gem, options[:rdoc_args]).generate_rdoc
+      if options[:generate_rdoc] then
+        installed_gems.each do |gem|
+          Gem::DocManager.new(gem, options[:rdoc_args]).generate_rdoc
+        end
       end
-    end
 
-    if options[:test] then
-      installed_gems.each do |spec|
-        gem_spec = Gem::SourceIndex.from_installed_gems.search(spec.name, spec.version.version).first
-        result = Gem::Validator.new.unit_test(gem_spec)
-        if result and not result.passed?
-          unless ask_yes_no("...keep Gem?", true) then
-            Gem::Uninstaller.new(spec.name, :version => spec.version.version).uninstall
+      if options[:test] then
+        installed_gems.each do |spec|
+          gem_spec = Gem::SourceIndex.from_installed_gems.find_name(spec.name, spec.version.version).first
+          result = Gem::Validator.new.unit_test(gem_spec)
+          if result and not result.passed?
+            unless ask_yes_no("...keep Gem?", true)
+              require 'rubygems/uninstaller'
+              Gem::Uninstaller.new(spec.name, :version => spec.version.version).uninstall
+            end
           end
         end
       end
Index: lib/rubygems/commands/server_command.rb
===================================================================
--- lib/rubygems/commands/server_command.rb	(revision 23658)
+++ lib/rubygems/commands/server_command.rb	(revision 23659)
@@ -7,7 +7,23 @@
     super 'server', 'Documentation and gem repository HTTP server',
           :port => 8808, :gemdir => Gem.dir, :daemon => false
 
-    add_option '-p', '--port=PORT', Integer,
+    OptionParser.accept :Port do |port|
+      if port =~ /\A\d+\z/ then
+        port = Integer port
+        raise OptionParser::InvalidArgument, "#{port}: not a port number" if
+          port > 65535
+
+        port
+      else
+        begin
+          Socket.getservbyname port
+        rescue SocketError => e
+          raise OptionParser::InvalidArgument, "#{port}: no such named service"
+        end
+      end
+    end
+
+    add_option '-p', '--port=PORT', :Port,
                'port to listen on' do |port, options|
       options[:port] = port
     end
@@ -37,6 +53,12 @@
 
 To install gems from a running server, use `gem install GEMNAME --source
 http://gem_server_host:8808`
+
+You can set up a shortcut to gem server documentation using the URL:
+
+  http://localhost:8808/rdoc?q=%s - Firefox
+  http://localhost:8808/rdoc?q=* - LaunchBar
+
     EOF
   end
 
Index: lib/rubygems/commands/uninstall_command.rb
===================================================================
--- lib/rubygems/commands/uninstall_command.rb	(revision 23658)
+++ lib/rubygems/commands/uninstall_command.rb	(revision 23659)
@@ -2,72 +2,82 @@
 require 'rubygems/version_option'
 require 'rubygems/uninstaller'
 
-module Gem
-  module Commands
-    class UninstallCommand < Command
+##
+# Gem uninstaller command line tool
+#
+# See `gem help uninstall`
 
-      include VersionOption
+class Gem::Commands::UninstallCommand < Gem::Command
 
-      def initialize
-        super 'uninstall', 'Uninstall gems from the local repository',
-              :version => Gem::Requirement.default
+  include Gem::VersionOption
 
-        add_option('-a', '--[no-]all',
-          'Uninstall all matching versions'
-          ) do |value, options|
-          options[:all] = value
-        end
+  def initialize
+    super 'uninstall', 'Uninstall gems from the local repository',
+          :version => Gem::Requirement.default, :user_install => true
 
-        add_option('-I', '--[no-]ignore-dependencies',
-                   'Ignore dependency requirements while',
-                   'uninstalling') do |value, options|
-          options[:ignore] = value
-        end
+    add_option('-a', '--[no-]all',
+      'Uninstall all matching versions'
+      ) do |value, options|
+      options[:all] = value
+    end
 
-        add_option('-x', '--[no-]executables',
-                     'Uninstall applicable executables without',
-                     'confirmation') do |value, options|
-          options[:executables] = value
-        end
+    add_option('-I', '--[no-]ignore-dependencies',
+               'Ignore dependency requirements while',
+               'uninstalling') do |value, options|
+      options[:ignore] = value
+    end
 
-        add_option('-i', '--install-dir DIR',
-                   'Directory to uninstall gem from') do |value, options|
-          options[:install_dir] = File.expand_path(value)
-        end
+    add_option('-x', '--[no-]executables',
+                 'Uninstall applicable executables without',
+                 'confirmation') do |value, options|
+      options[:executables] = value
+    end
 
-        add_option('-n', '--bindir DIR',
-                   'Directory to remove binaries from') do |value, options|
-          options[:bin_dir] = File.expand_path(value)
-        end
+    add_option('-i', '--install-dir DIR',
+               'Directory to uninstall gem from') do |value, options|
+      options[:install_dir] = File.expand_path(value)
+    end
 
-        add_version_option
-        add_platform_option
-      end
+    add_option('-n', '--bindir DIR',
+               'Directory to remove binaries from') do |value, options|
+      options[:bin_dir] = File.expand_path(value)
+    end
 
-      def arguments # :nodoc:
-        "GEMNAME       name of gem to uninstall"
-      end
+    add_option('--[no-]user-install',
+               'Uninstall from user\'s home directory',
+               'in addition to GEM_HOME.') do |value, options|
+      options[:user_install] = value
+    end
 
-      def defaults_str # :nodoc:
-        "--version '#{Gem::Requirement.default}' --no-force " \
-        "--install-dir #{Gem.dir}"
-      end
+    add_version_option
+    add_platform_option
+  end
 
-      def usage # :nodoc:
-        "#{program_name} GEMNAME [GEMNAME ...]"
-      end
+  def arguments # :nodoc:
+    "GEMNAME       name of gem to uninstall"
+  end
 
-      def execute
-        get_all_gem_names.each do |gem_name|
-          begin
-            Gem::Uninstaller.new(gem_name, options).uninstall
-          rescue Gem::GemNotInHomeException => e
-            spec = e.spec
-            alert("In order to remove #{spec.name}, please execute:\n" \
-                  "\tgem uninstall #{spec.name} --install-dir=#{spec.installation_path}")
-          end
-        end
+  def defaults_str # :nodoc:
+    "--version '#{Gem::Requirement.default}' --no-force " \
+    "--install-dir #{Gem.dir}\n" \
+    "--user-install"
+  end
+
+  def usage # :nodoc:
+    "#{program_name} GEMNAME [GEMNAME ...]"
+  end
+
+  def execute
+    get_all_gem_names.each do |gem_name|
+      begin
+        Gem::Uninstaller.new(gem_name, options).uninstall
+      rescue Gem::GemNotInHomeException => e
+        spec = e.spec
+        alert("In order to remove #{spec.name}, please execute:\n" \
+              "\tgem uninstall #{spec.name} --install-dir=#{spec.installation_path}")
       end
     end
   end
+
 end
+
Index: lib/rubygems/commands/check_command.rb
===================================================================
--- lib/rubygems/commands/check_command.rb	(revision 23658)
+++ lib/rubygems/commands/check_command.rb	(revision 23659)
@@ -21,6 +21,10 @@
       options[:alien] = true
     end
 
+    add_option('-v', '--verbose', "Spew more words") do |value, options|
+      options[:verbose] = true
+    end
+
     add_option('-t', '--test', "Run unit tests for gem") do |value, options|
       options[:test] = true
     end
@@ -38,16 +42,17 @@
 
     if options[:alien]
       say "Performing the 'alien' operation"
-      Gem::Validator.new.alien.each do |key, val|
-        if(val.size > 0)
+      say
+      gems = get_all_gem_names rescue []
+      Gem::Validator.new.alien(gems).sort.each do |key, val|
+        unless val.empty? then
           say "#{key} has #{val.size} problems"
           val.each do |error_entry|
-            say "\t#{error_entry.path}:"
-            say "\t#{error_entry.problem}"
-            say
+            say "  #{error_entry.path}:"
+            say "    #{error_entry.problem}"
           end
         else
-          say "#{key} is error-free"
+          say "#{key} is error-free" if options[:verbose]
         end
         say
       end
Index: lib/rubygems/requirement.rb
===================================================================
--- lib/rubygems/requirement.rb	(revision 23658)
+++ lib/rubygems/requirement.rb	(revision 23659)
@@ -4,8 +4,6 @@
 # See LICENSE.txt for permissions.
 #++
 
-require 'rubygems/version'
-
 ##
 # Requirement version includes a prefaced comparator in addition
 # to a version number.
@@ -26,10 +24,10 @@
     "<"  =>  lambda { |v, r| v < r },
     ">=" =>  lambda { |v, r| v >= r },
     "<=" =>  lambda { |v, r| v <= r },
-    "~>" =>  lambda { |v, r| v >= r && v < r.bump }
+    "~>" =>  lambda { |v, r| v = v.release; v >= r && v < r.bump }
   }
 
-  OP_RE = /#{OPS.keys.map{ |k| Regexp.quote k }.join '|'}/o
+  OP_RE = OPS.keys.map{ |k| Regexp.quote k }.join '|'
 
   ##
   # Factory method to create a Gem::Requirement object.  Input may be a
@@ -65,7 +63,7 @@
 
   ##
   # Constructs a Requirement from +requirements+ which can be a String, a
-  # Gem::Version, or an Array of those.  See parse for details on the
+  # Gem::Version, or an Array of those.  See #parse for details on the
   # formatting of requirement strings.
 
   def initialize(requirements)
@@ -99,11 +97,15 @@
     as_list.join(", ")
   end
 
+  def pretty_print(q) # :nodoc:
+    q.group 1, 'Gem::Requirement.new(', ')' do
+      q.pp as_list
+    end
+  end
+
   def as_list
     normalize
-    @requirements.collect { |req|
-      "#{req[0]} #{req[1]}"
-    }
+    @requirements.map do |op, version| "#{op} #{version}" end
   end
 
   def normalize
@@ -129,18 +131,23 @@
     OPS[op].call(version, required_version)
   end
 
+  def prerelease?
+    # TODO: why is @requirements a nested array?
+    @requirements.any?{ |r| r[1].prerelease? }
+  end
+
   ##
   # Parse the version requirement obj returning the operator and version.
   #
   # The requirement can be a String or a Gem::Version.  A String can be an
-  # operator (<, <=, =, =>, >, !=, ~>), a version number, or both, operator
+  # operator (<, <=, =, >=, >, !=, ~>), a version number, or both, operator
   # first.
 
   def parse(obj)
     case obj
-    when /^\s*(#{OP_RE})\s*([0-9.]+)\s*$/o then
+    when /^\s*(#{OP_RE})\s*(#{Gem::Version::VERSION_PATTERN})\s*$/o then
       [$1, Gem::Version.new($2)]
-    when /^\s*([0-9.]+)\s*$/ then
+    when /^\s*(#{Gem::Version::VERSION_PATTERN})\s*$/o then
       ['=', Gem::Version.new($1)]
     when /^\s*(#{OP_RE})\s*$/o then
       [$1, Gem::Version.new('0')]
Index: lib/rubygems/gem_path_searcher.rb
===================================================================
--- lib/rubygems/gem_path_searcher.rb	(revision 23658)
+++ lib/rubygems/gem_path_searcher.rb	(revision 23659)
@@ -4,8 +4,6 @@
 # See LICENSE.txt for permissions.
 #++
 
-require 'rubygems'
-
 ##
 # GemPathSearcher has the capability to find loadable files inside
 # gems.  It generates data up front to speed up searches later.
@@ -80,11 +78,15 @@
 
   ##
   # Return a list of all installed gemspecs, sorted by alphabetical order and
-  # in reverse version order.
+  # in reverse version order.  (bar-2, bar-1, foo-2)
 
   def init_gemspecs
-    Gem.source_index.map { |_, spec| spec }.sort { |a,b|
-      (a.name <=> b.name).nonzero? || (b.version <=> a.version)
+    specs = Gem.source_index.map { |_, spec| spec }
+
+    specs.sort { |a, b|
+      names = a.name <=> b.name
+      next names if names.nonzero?
+      b.version <=> a.version
     }
   end
 
Index: lib/rubygems/uninstaller.rb
===================================================================
--- lib/rubygems/uninstaller.rb	(revision 23658)
+++ lib/rubygems/uninstaller.rb	(revision 23659)
@@ -12,6 +12,11 @@
 
 ##
 # An Uninstaller.
+#
+# The uninstaller fires pre and post uninstall hooks.  Hooks can be added
+# either through a rubygems_plugin.rb file in an installed gem or via a
+# rubygems/defaults/#{RUBY_ENGINE}.rb or rubygems/defaults/operating_system.rb
+# file.  See Gem.pre_uninstall and Gem.post_uninstall for details.
 
 class Gem::Uninstaller
 
@@ -46,8 +51,17 @@
     @force_ignore = options[:ignore]
     @bin_dir = options[:bin_dir]
 
+    # only add user directory if install_dir is not set
+    @user_install = false
+    @user_install = options[:user_install] unless options[:install_dir]
+
     spec_dir = File.join @gem_home, 'specifications'
     @source_index = Gem::SourceIndex.from_gems_in spec_dir
+
+    if @user_install then
+      user_dir = File.join Gem.user_dir, 'specifications'
+      @user_index = Gem::SourceIndex.from_gems_in user_dir
+    end
   end
 
   ##
@@ -56,9 +70,10 @@
 
   def uninstall
     list = @source_index.find_name @gem, @version
+    list += @user_index.find_name @gem, @version if @user_install
 
     if list.empty? then
-      raise Gem::InstallError, "Unknown gem #{@gem} #{@version}"
+      raise Gem::InstallError, "cannot uninstall, check `gem list -d #{@gem}`"
 
     elsif list.size > 1 and @force_all then
       remove_all list.dup
@@ -91,8 +106,8 @@
       hook.call self
     end
 
-    specs.each { |s| remove_executables s }
-    remove spec, specs
+    remove_executables @spec
+    remove @spec, specs
 
     Gem.post_uninstall_hooks.each do |hook|
       hook.call self
@@ -105,29 +120,29 @@
   # Removes installed executables and batch files (windows only) for
   # +gemspec+.
 
-  def remove_executables(gemspec)
-    return if gemspec.nil?
+  def remove_executables(spec)
+    return if spec.nil?
 
-    if gemspec.executables.size > 0 then
-      bindir = @bin_dir ? @bin_dir : (Gem.bindir @gem_home)
+    unless spec.executables.empty? then
+      bindir = @bin_dir ? @bin_dir : Gem.bindir(spec.installation_path)
 
-      list = @source_index.find_name(gemspec.name).delete_if { |spec|
-        spec.version == gemspec.version
+      list = @source_index.find_name(spec.name).delete_if { |s|
+        s.version == spec.version
       }
 
-      executables = gemspec.executables.clone
+      executables = spec.executables.clone
 
-      list.each do |spec|
-        spec.executables.each do |exe_name|
-          executables.delete(exe_name)
+      list.each do |s|
+        s.executables.each do |exe_name|
+          executables.delete exe_name
         end
       end
 
-      return if executables.size == 0
+      return if executables.empty?
 
       answer = if @force_executables.nil? then
                  ask_yes_no("Remove executables:\n" \
-                            "\t#{gemspec.executables.join(", ")}\n\nin addition to the gem?",
+                            "\t#{spec.executables.join(", ")}\n\nin addition to the gem?",
                             true) # " # appease ruby-mode - don't ask
                else
                  @force_executables
@@ -138,7 +153,7 @@
       else
         raise Gem::FilePermissionError, bindir unless File.writable? bindir
 
-        gemspec.executables.each do |exe_name|
+        spec.executables.each do |exe_name|
           say "Removing #{exe_name}"
           FileUtils.rm_f File.join(bindir, exe_name)
           FileUtils.rm_f File.join(bindir, "#{exe_name}.bat")
@@ -169,7 +184,8 @@
             "Uninstallation aborted due to dependent gem(s)"
     end
 
-    unless path_ok? spec then
+    unless path_ok?(@gem_home, spec) or
+           (@user_install and path_ok?(Gem.user_dir, spec)) then
       e = Gem::GemNotInHomeException.new \
             "Gem is not installed in directory #{@gem_home}"
       e.spec = spec
@@ -210,10 +226,13 @@
     list.delete spec
   end
 
-  def path_ok?(spec)
-    full_path = File.join @gem_home, 'gems', spec.full_name
-    original_path = File.join @gem_home, 'gems', spec.original_name
+  ##
+  # Is +spec+ in +gem_dir+?
 
+  def path_ok?(gem_dir, spec)
+    full_path = File.join gem_dir, 'gems', spec.full_name
+    original_path = File.join gem_dir, 'gems', spec.original_name
+
     full_path == spec.full_gem_path || original_path == spec.full_gem_path
   end
 
@@ -221,6 +240,7 @@
     return true if @force_ignore
 
     deplist = Gem::DependencyList.from_source_index @source_index
+    deplist.add(*@user_index.gems.values) if @user_install
     deplist.ok_to_remove?(spec.full_name) || ask_if_ok(spec)
   end
 
Index: lib/rubygems/rubygems_version.rb
===================================================================
--- lib/rubygems/rubygems_version.rb	(revision 23658)
+++ lib/rubygems/rubygems_version.rb	(revision 23659)
@@ -1,6 +1,19 @@
+#--
 # DO NOT EDIT
 # This file is auto-generated by build scripts.
 # See:  rake update_version
+#++
+
 module Gem
-  RubyGemsVersion = '1.3.1'
+
+  ##
+  # The version of RubyGems you are using
+
+  RubyGemsVersion = '1.3.4'
+
+  ##
+  # The version of RubyGems you are using (duplicated for familiarity)
+
+  VERSION = RubyGemsVersion
+
 end
Index: lib/rubygems/server.rb
===================================================================
--- lib/rubygems/server.rb	(revision 23658)
+++ lib/rubygems/server.rb	(revision 23659)
@@ -17,6 +17,7 @@
 #   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 @@
 
 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 @@
   </head>
   <body>
     <div id="fileHeader">
+<%= SEARCH %>
       <h1>RubyGems Documentation Index</h1>
     </div>
     <!-- banner header -->
@@ -114,10 +127,10 @@
   </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,8 +338,93 @@
 .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
   end
@@ -533,6 +631,90 @@
     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 @@
 
     @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,
Index: lib/rubygems/defaults.rb
===================================================================
--- lib/rubygems/defaults.rb	(revision 23658)
+++ lib/rubygems/defaults.rb	(revision 23659)
@@ -20,8 +20,13 @@
     if defined? RUBY_FRAMEWORK_VERSION then
       File.join File.dirname(ConfigMap[:sitedir]), 'Gems',
                 ConfigMap[:ruby_version]
+    # 1.9.2dev reverted to 1.8 style path
+    elsif RUBY_VERSION > '1.9' and RUBY_VERSION < '1.9.2' then
+      File.join(ConfigMap[:libdir], ConfigMap[:ruby_install_name], 'gems',
+                ConfigMap[:ruby_version])
     else
-      ConfigMap[:sitelibdir].sub(%r'/site_ruby/(?=[^/]+)', '/gems/')
+      File.join(ConfigMap[:libdir], ruby_engine, 'gems',
+                ConfigMap[:ruby_version])
     end
   end
 
@@ -37,15 +42,25 @@
   # Default gem load path
 
   def self.default_path
-    [user_dir, default_dir]
+    if File.exist?(Gem.user_home)
+      [user_dir, default_dir]
+    else
+      [default_dir]
+    end
   end
 
   ##
   # Deduce Ruby's --program-prefix and --program-suffix from its install name
 
   def self.default_exec_format
-    baseruby = ConfigMap[:BASERUBY] || 'ruby'
-    ConfigMap[:RUBY_INSTALL_NAME].sub(baseruby, '%s') rescue '%s'
+    exec_format = ConfigMap[:ruby_install_name].sub('ruby', '%s') rescue '%s'
+
+    unless exec_format =~ /%s/ then
+      raise Gem::Exception,
+        "[BUG] invalid exec_format #{exec_format.inspect}, no %s"
+    end
+
+    exec_format
   end
 
   ##
Index: lib/rubygems/security.rb
===================================================================
--- lib/rubygems/security.rb	(revision 23658)
+++ lib/rubygems/security.rb	(revision 23659)
@@ -218,7 +218,7 @@
 #
 #   # signing key (still kept in an undisclosed location!)
 #   s.signing_key = '/mnt/floppy/alf-private_key.pem'
-#
+#   
 #   # certificate chain (includes the issuer certificate now too)
 #   s.cert_chain  = ['/home/alf/doc/seattlerb-public_cert.pem',
 #                    '/home/alf/doc/alf_at_seattle-public_cert.pem']
@@ -274,7 +274,7 @@
 #   # convert a PEM format X509 certificate into DER format:
 #   # (note: Windows .cer files are X509 certificates in DER format)
 #   $ openssl x509 -in input.pem -outform der -out output.der
-#
+#   
 #   # print out the certificate in a human-readable format:
 #   $ openssl x509 -in input.pem -noout -text
 #
@@ -282,7 +282,7 @@
 #
 #   # convert a PEM format RSA key into DER format:
 #   $ openssl rsa -in input_key.pem -outform der -out output_key.der
-#
+#   
 #   # print out the key in a human readable format:
 #   $ openssl rsa -in input_key.pem -noout -text
 #
Index: lib/rubygems/command_manager.rb
===================================================================
--- lib/rubygems/command_manager.rb	(revision 23658)
+++ lib/rubygems/command_manager.rb	(revision 23659)
@@ -8,139 +8,167 @@
 require 'rubygems/command'
 require 'rubygems/user_interaction'
 
-module Gem
+##
+# The command manager registers and installs all the individual sub-commands
+# supported by the gem command.
+#
+# Extra commands can be provided by writing a rubygems_plugin.rb
+# file in an installed gem.  You should register your command against the
+# Gem::CommandManager instance, like this:
+#
+#   # file rubygems_plugin.rb
+#   require 'rubygems/command_manager'
+#
+#   class Gem::Commands::EditCommand < Gem::Command
+#     # ...
+#   end
+#
+#   Gem::CommandManager.instance.register_command :edit
+#
+# See Gem::Command for instructions on writing gem commands.
 
-  ####################################################################
-  # The command manager registers and installs all the individual
-  # sub-commands supported by the gem command.
-  class CommandManager
-    include UserInteraction
+class Gem::CommandManager
 
-    # Return the authoritative instance of the command manager.
-    def self.instance
-      @command_manager ||= CommandManager.new
-    end
+  include Gem::UserInteraction
 
-    # Register all the subcommands supported by the gem command.
-    def initialize
-      @commands = {}
-      register_command :build
-      register_command :cert
-      register_command :check
-      register_command :cleanup
-      register_command :contents
-      register_command :dependency
-      register_command :environment
-      register_command :fetch
-      register_command :generate_index
-      register_command :help
-      register_command :install
-      register_command :list
-      register_command :lock
-      register_command :mirror
-      register_command :outdated
-      register_command :pristine
-      register_command :query
-      register_command :rdoc
-      register_command :search
-      register_command :server
-      register_command :sources
-      register_command :specification
-      register_command :stale
-      register_command :uninstall
-      register_command :unpack
-      register_command :update
-      register_command :which
-    end
+  ##
+  # Return the authoritative instance of the command manager.
 
-    # Register the command object.
-    def register_command(command_obj)
-      @commands[command_obj] = false
-    end
+  def self.instance
+    @command_manager ||= new
+  end
 
-    # Return the registered command from the command name.
-    def [](command_name)
-      command_name = command_name.intern
-      return nil if @commands[command_name].nil?
-      @commands[command_name] ||= load_and_instantiate(command_name)
-    end
+  ##
+  # Register all the subcommands supported by the gem command.
 
-    # Return a list of all command names (as strings).
-    def command_names
-      @commands.keys.collect {|key| key.to_s}.sort
-    end
+  def initialize
+    @commands = {}
+    register_command :build
+    register_command :cert
+    register_command :check
+    register_command :cleanup
+    register_command :contents
+    register_command :dependency
+    register_command :environment
+    register_command :fetch
+    register_command :generate_index
+    register_command :help
+    register_command :install
+    register_command :list
+    register_command :lock
+    register_command :mirror
+    register_command :outdated
+    register_command :pristine
+    register_command :query
+    register_command :rdoc
+    register_command :search
+    register_command :server
+    register_command :sources
+    register_command :specification
+    register_command :stale
+    register_command :uninstall
+    register_command :unpack
+    register_command :update
+    register_command :which
+  end
 
-    # Run the config specified by +args+.
-    def run(args)
-      process_args(args)
-    rescue StandardError, Timeout::Error => ex
-      alert_error "While executing gem ... (#{ex.class})\n    #{ex.to_s}"
-      ui.errs.puts "\t#{ex.backtrace.join "\n\t"}" if
-        Gem.configuration.backtrace
+  ##
+  # Register the command object.
+
+  def register_command(command_obj)
+    @commands[command_obj] = false
+  end
+
+  ##
+  # Return the registered command from the command name.
+
+  def [](command_name)
+    command_name = command_name.intern
+    return nil if @commands[command_name].nil?
+    @commands[command_name] ||= load_and_instantiate(command_name)
+  end
+
+  ##
+  # Return a sorted list of all command names (as strings).
+
+  def command_names
+    @commands.keys.collect {|key| key.to_s}.sort
+  end
+
+  ##
+  # Run the config specified by +args+.
+
+  def run(args)
+    process_args(args)
+  rescue StandardError, Timeout::Error => ex
+    alert_error "While executing gem ... (#{ex.class})\n    #{ex.to_s}"
+    ui.errs.puts "\t#{ex.backtrace.join "\n\t"}" if
+      Gem.configuration.backtrace
+    terminate_interaction(1)
+  rescue Interrupt
+    alert_error "Interrupted"
+    terminate_interaction(1)
+  end
+
+  def process_args(args)
+    args = args.to_str.split(/\s+/) if args.respond_to?(:to_str)
+    if args.size == 0
+      say Gem::Command::HELP
       terminate_interaction(1)
-    rescue Interrupt
-      alert_error "Interrupted"
+    end
+    case args[0]
+    when '-h', '--help'
+      say Gem::Command::HELP
+      terminate_interaction(0)
+    when '-v', '--version'
+      say Gem::RubyGemsVersion
+      terminate_interaction(0)
+    when /^-/
+      alert_error "Invalid option: #{args[0]}.  See 'gem --help'."
       terminate_interaction(1)
+    else
+      cmd_name = args.shift.downcase
+      cmd = find_command(cmd_name)
+      cmd.invoke(*args)
     end
+  end
 
-    def process_args(args)
-      args = args.to_str.split(/\s+/) if args.respond_to?(:to_str)
-      if args.size == 0
-        say Gem::Command::HELP
-        terminate_interaction(1)
-      end
-      case args[0]
-      when '-h', '--help'
-        say Gem::Command::HELP
-        terminate_interaction(0)
-      when '-v', '--version'
-        say Gem::RubyGemsVersion
-        terminate_interaction(0)
-      when /^-/
-        alert_error "Invalid option: #{args[0]}.  See 'gem --help'."
-        terminate_interaction(1)
-      else
-        cmd_name = args.shift.downcase
-        cmd = find_command(cmd_name)
-        cmd.invoke(*args)
-      end
+  def find_command(cmd_name)
+    possibilities = find_command_possibilities cmd_name
+    if possibilities.size > 1 then
+      raise "Ambiguous command #{cmd_name} matches [#{possibilities.join(', ')}]"
+    elsif possibilities.size < 1 then
+      raise "Unknown command #{cmd_name}"
     end
 
-    def find_command(cmd_name)
-      possibilities = find_command_possibilities(cmd_name)
-      if possibilities.size > 1
-        raise "Ambiguous command #{cmd_name} matches [#{possibilities.join(', ')}]"
-      end
-      if possibilities.size < 1
-        raise "Unknown command #{cmd_name}"
-      end
+    self[possibilities.first]
+  end
 
-      self[possibilities.first]
-    end
+  def find_command_possibilities(cmd_name)
+    len = cmd_name.length
 
-    def find_command_possibilities(cmd_name)
-      len = cmd_name.length
-      self.command_names.select { |n| cmd_name == n[0,len] }
-    end
+    command_names.select { |n| cmd_name == n[0, len] }
+  end
 
-    private
+  private
 
-    def load_and_instantiate(command_name)
-      command_name = command_name.to_s
-      retried = false
+  def load_and_instantiate(command_name)
+    command_name = command_name.to_s
+    retried = false
 
-      begin
-        const_name = command_name.capitalize.gsub(/_(.)/) { $1.upcase }
-        Gem::Commands.const_get("#{const_name}Command").new
-      rescue NameError
-        if retried then
-          raise
-        else
-          retried = true
-          require "rubygems/commands/#{command_name}_command"
-          retry
-        end
+    begin
+      const_name = command_name.capitalize.gsub(/_(.)/) { $1.upcase }
+      Gem::Commands.const_get("#{const_name}Command").new
+    rescue NameError
+      if retried then
+        raise
+      else
+        retried = true
+        require "rubygems/commands/#{command_name}_command"
+        retry
       end
     end
   end
+
 end
+
Index: lib/rubygems/dependency_list.rb
===================================================================
--- lib/rubygems/dependency_list.rb	(revision 23658)
+++ lib/rubygems/dependency_list.rb	(revision 23659)
@@ -8,6 +8,7 @@
 
 class Gem::DependencyList
 
+  include Enumerable
   include TSort
 
   def self.from_source_index(src_index)
@@ -24,24 +25,27 @@
     @specs = []
   end
 
+  ##
   # Adds +gemspecs+ to the dependency list.
+
   def add(*gemspecs)
     @specs.push(*gemspecs)
   end
 
-  # Return a list of the specifications in the dependency list,
-  # sorted in order so that no spec in the list depends on a gem
-  # earlier in the list.
+  ##
+  # Return a list of the specifications in the dependency list, sorted in
+  # order so that no spec in the list depends on a gem earlier in the list.
   #
-  # This is useful when removing gems from a set of installed gems.
-  # By removing them in the returned order, you don't get into as
-  # many dependency issues.
+  # This is useful when removing gems from a set of installed gems.  By
+  # removing them in the returned order, you don't get into as many dependency
+  # issues.
   #
-  # If there are circular dependencies (yuck!), then gems will be
-  # returned in order until only the circular dependents and anything
-  # they reference are left.  Then arbitrary gemspecs will be returned
-  # until the circular dependency is broken, after which gems will be
-  # returned in dependency order again.
+  # If there are circular dependencies (yuck!), then gems will be returned in
+  # order until only the circular dependents and anything they reference are
+  # left.  Then arbitrary gemspecs will be returned until the circular
+  # dependency is broken, after which gems will be returned in dependency
+  # order again.
+
   def dependency_order
     sorted = strongly_connected_components.flatten
 
@@ -62,11 +66,20 @@
     result.reverse
   end
 
+  ##
+  # Iterator over dependency_order
+
+  def each(&block)
+    dependency_order.each(&block)
+  end
+
   def find_name(full_name)
     @specs.find { |spec| spec.full_name == full_name }
   end
 
+  ##
   # Are all the dependencies in the list satisfied?
+
   def ok?
     @specs.all? do |spec|
       spec.runtime_dependencies.all? do |dep|
@@ -75,10 +88,12 @@
     end
   end
 
+  ##
   # Is is ok to remove a gem from the dependency list?
   #
-  # If removing the gemspec creates breaks a currently ok dependency,
-  # then it is NOT ok to remove the gem.
+  # If removing the gemspec creates breaks a currently ok dependency, then it
+  # is NOT ok to remove the gem.
+
   def ok_to_remove?(full_name)
     gem_to_remove = find_name full_name
 
@@ -106,9 +121,10 @@
     @specs.delete_if { |spec| spec.full_name == full_name }
   end
 
-  # Return a hash of predecessors.  <tt>result[spec]</tt> is an
-  # Array of gemspecs that have a dependency satisfied by the named
-  # spec.
+  ##
+  # Return a hash of predecessors.  <tt>result[spec]</tt> is an Array of
+  # gemspecs that have a dependency satisfied by the named spec.
+
   def spec_predecessors
     result = Hash.new { |h,k| h[k] = [] }
 
@@ -151,13 +167,17 @@
 
   private
 
+  ##
   # Count the number of gemspecs in the list +specs+ that are not in
   # +ignored+.
+
   def active_count(specs, ignored)
     result = 0
+
     specs.each do |spec|
       result += 1 unless ignored[spec.full_name]
     end
+
     result
   end
 
Index: lib/rubygems/test_utilities.rb
===================================================================
--- lib/rubygems/test_utilities.rb	(revision 23658)
+++ lib/rubygems/test_utilities.rb	(revision 23659)
@@ -11,9 +11,9 @@
 #   @fetcher = Gem::FakeFetcher.new
 #   @fetcher.data['http://gems.example.com/yaml'] = source_index.to_yaml
 #   Gem::RemoteFetcher.fetcher = @fetcher
-#
+#   
 #   # invoke RubyGems code
-#
+#   
 #   paths = @fetcher.paths
 #   assert_equal 'http://gems.example.com/yaml', paths.shift
 #   assert paths.empty?, paths.join(', ')
Index: lib/rubygems/gem_openssl.rb
===================================================================
--- lib/rubygems/gem_openssl.rb	(revision 23658)
+++ lib/rubygems/gem_openssl.rb	(revision 23659)
@@ -4,23 +4,30 @@
 # See LICENSE.txt for permissions.
 #++
 
+#--
 # Some system might not have OpenSSL installed, therefore the core
 # library file openssl might not be available.  We localize testing
 # for the presence of OpenSSL in this file.
+#++
 
 module Gem
   class << self
+    ##
     # Is SSL (used by the signing commands) available on this
     # platform?
+
     def ssl_available?
-      require 'rubygems/gem_openssl'
       @ssl_available
     end
 
-    # Set the value of the ssl_available flag.
+    ##
+    # Is SSL available?
+
     attr_writer :ssl_available
 
+    ##
     # Ensure that SSL is available.  Throw an exception if it is not.
+
     def ensure_ssl_available
       unless ssl_available?
         fail Gem::Exception, "SSL is not installed on this system"
@@ -61,6 +68,8 @@
   Gem.ssl_available = false
 end
 
+# :stopdoc:
+
 module Gem::SSL
 
   # We make our own versions of the constants here.  This allows us
@@ -70,7 +79,7 @@
   # These constants are only used during load time.  At runtime, any
   # method that makes a direct reference to SSL software must be
   # protected with a Gem.ensure_ssl_available call.
-  #
+
   if Gem.ssl_available? then
     PKEY_RSA = OpenSSL::PKey::RSA
     DIGEST_SHA1 = OpenSSL::Digest::SHA1
@@ -81,3 +90,5 @@
 
 end
 
+# :startdoc:
+
Index: lib/rubygems.rb
===================================================================
--- lib/rubygems.rb	(revision 23658)
+++ lib/rubygems.rb	(revision 23659)
@@ -8,11 +8,29 @@
 require 'rubygems/rubygems_version'
 require 'rubygems/defaults'
 require 'thread'
+require 'etc'
 
 module Gem
+
+  ##
+  # Raised when RubyGems is unable to load or activate a gem.  Contains the
+  # name and version requirements of the gem that either conflicts with
+  # already activated gems or that RubyGems is otherwise unable to activate.
+
   class LoadError < ::LoadError
-    attr_accessor :name, :version_requirement
+
+    ##
+    # Name of gem
+
+    attr_accessor :name
+
+    ##
+    # Version requirement of gem
+
+    attr_accessor :version_requirement
+
   end
+
 end
 
 module Kernel
@@ -54,18 +72,102 @@
 end
 
 ##
-# Main module to hold all RubyGem classes/modules.
+# RubyGems is the Ruby standard for publishing and managing third party
+# libraries.
+#
+# For user documentation, see:
+#
+# * <tt>gem help</tt> and <tt>gem help [command]</tt>
+# * {RubyGems User Guide}[http://docs.rubygems.org/read/book/1]
+# * {Frequently Asked Questions}[http://docs.rubygems.org/read/book/3]
+#
+# For gem developer documentation see:
+#
+# * {Creating Gems}[http://docs.rubygems.org/read/chapter/5]
+# * Gem::Specification
+#
+# Further RubyGems documentation can be found at:
+#
+# * {RubyGems API}[http://rubygems.rubyforge.org/rdoc] (also available from
+#   <tt>gem server</tt>)
+# * {RubyGems Bookshelf}[http://rubygem.org]
+#
+# == RubyGems Plugins
+#
+# As of RubyGems 1.3.2, RubyGems will load plugins installed in gems or
+# $LOAD_PATH.  Plugins must be named 'rubygems_plugin' are discovered via
+# Gem::find_files then loaded.  Take care when implementing a plugin as your
+# plugin file may be loaded multiple times if multiple versions of your gem
+# are installed.
+#
+# For an example plugin, see the graph gem which adds a `gem graph` command.
+#
+# == RubyGems Defaults, Packaging
+#
+# RubyGems defaults are stored in rubygems/defaults.rb.  If you're packaging
+# RubyGems or implementing Ruby you can change RubyGems' defaults.
+#
+# For RubyGems packagers, provide lib/rubygems/operating_system.rb and
+# override any defaults from lib/rubygems/defaults.rb.
+#
+# For Ruby implementers, provide lib/rubygems/#{RUBY_ENGINE}.rb and override
+# any defaults from lib/rubygems/defaults.rb.
+#
+# If you need RubyGems to perform extra work on install or uninstall, your
+# defaults override file can set pre and post install and uninstall hooks.
+# See Gem::pre_install, Gem::pre_uninstall, Gem::post_install,
+# Gem::post_uninstall.
+#
+# == Bugs
+#
+# You can submit bugs to the
+# {RubyGems bug tracker}[http://rubyforge.org/tracker/?atid=575&group_id=126&func=browse]
+# on RubyForge
+#
+# == Credits
+#
+# RubyGems is currently maintained by Eric Hodel.
+#
+# RubyGems was originally developed at RubyConf 2003 by:
+#
+# * Rich Kilmer -- rich(at)infoether.com
+# * Chad Fowler -- chad(at)chadfowler.com
+# * David Black -- dblack(at)wobblini.net
+# * Paul Brannan -- paul(at)atdesk.com
+# * Jim Weirch -- {jim(at)weirichhouse.org}[mailto:jim@w...]
+#
+# Contributors:
+#
+# * Gavin Sinclair -- gsinclair(at)soyabean.com.au
+# * George Marrows -- george.marrows(at)ntlworld.com
+# * Dick Davies -- rasputnik(at)hellooperator.net
+# * Mauricio Fernandez -- batsman.geo(at)yahoo.com
+# * Simon Strandgaard -- neoneye(at)adslhome.dk
+# * Dave Glasser -- glasser(at)mit.edu
+# * Paul Duncan -- pabs(at)pablotron.org
+# * Ville Aine -- vaine(at)cs.helsinki.fi
+# * Eric Hodel -- drbrain(at)segment7.net
+# * Daniel Berger -- djberg96(at)gmail.com
+# * Phil Hagelberg -- technomancy(at)gmail.com
+# * Ryan Davis
+#
+# (If your name is missing, PLEASE let us know!)
+#
+# Thanks!
+#
+# -The RubyGems Team
 
 module Gem
 
+  ##
+  # Configuration settings from ::RbConfig
+
   ConfigMap = {} unless defined?(ConfigMap)
+
   require 'rbconfig'
-  RbConfig = Config unless defined? ::RbConfig
 
   ConfigMap.merge!(
-    :BASERUBY => RbConfig::CONFIG["BASERUBY"],
     :EXEEXT => RbConfig::CONFIG["EXEEXT"],
-    :RUBY_INSTALL_NAME => RbConfig::CONFIG["RUBY_INSTALL_NAME"],
     :RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"],
     :arch => RbConfig::CONFIG["arch"],
     :bindir => RbConfig::CONFIG["bindir"],
@@ -79,11 +181,16 @@
     :vendorlibdir => RbConfig::CONFIG["vendorlibdir"]
   )
 
+  ##
+  # Default directories in a gem repository
+
   DIRECTORIES = %w[cache doc gems specifications] unless defined?(DIRECTORIES)
 
+  # :stopdoc:
   MUTEX = Mutex.new
 
   RubyGemsPackageVersion = RubyGemsVersion
+  # :startdoc:
 
   ##
   # An Array of Regexps that match windows ruby platforms.
@@ -102,6 +209,7 @@
 
   @configuration = nil
   @loaded_specs = {}
+  @loaded_stacks = {}
   @platforms = []
   @ruby = nil
   @sources = []
@@ -128,6 +236,14 @@
   # Gem::Requirement and Gem::Version documentation.
 
   def self.activate(gem, *version_requirements)
+    if version_requirements.last.is_a?(Hash)
+      options = version_requirements.pop
+    else
+      options = {}
+    end
+
+    sources = options[:sources] || []
+
     if version_requirements.empty? then
       version_requirements = Gem::Requirement.default
     end
@@ -146,8 +262,18 @@
       existing_spec = @loaded_specs[gem.name]
 
       unless matches.any? { |spec| spec.version == existing_spec.version } then
-        raise Gem::Exception,
-              "can't activate #{gem}, already activated #{existing_spec.full_name}"
+         sources_message = sources.map { |spec| spec.full_name }
+         stack_message = @loaded_stacks[gem.name].map { |spec| spec.full_name }
+
+         msg = "can't activate #{gem} for #{sources_message.inspect}, "
+         msg << "already activated #{existing_spec.full_name} for "
+         msg << "#{stack_message.inspect}"
+
+         e = Gem::LoadError.new msg
+         e.name = gem.name
+         e.version_requirement = gem.version_requirements
+
+         raise e
       end
 
       return false
@@ -159,10 +285,11 @@
 
     spec.loaded = true
     @loaded_specs[spec.name] = spec
+    @loaded_stacks[spec.name] = sources.dup
 
     # Load dependent gems first
     spec.runtime_dependencies.each do |dep_gem|
-      activate dep_gem
+      activate dep_gem, :sources => [spec, *sources]
     end
 
     # bin directory must come before library directories
@@ -228,6 +355,35 @@
   end
 
   ##
+  # Find the full path to the executable for gem +name+.  If the +exec_name+
+  # is not given, the gem's default_executable is chosen, otherwise the
+  # specifed executable's path is returned.  +version_requirements+ allows you
+  # to specify specific gem versions.
+
+  def self.bin_path(name, exec_name = nil, *version_requirements)
+    version_requirements = Gem::Requirement.default if
+      version_requirements.empty?
+    spec = Gem.source_index.find_name(name, version_requirements).last
+
+    raise Gem::GemNotFoundException,
+          "can't find gem #{name} (#{version_requirements})" unless spec
+
+    exec_name ||= spec.default_executable
+
+    unless exec_name
+      msg = "no default executable for #{spec.full_name}"
+      raise Gem::Exception, msg
+    end
+
+    unless spec.executables.include? exec_name
+      msg = "can't find executable #{exec_name} for #{spec.full_name}"
+      raise Gem::Exception, msg
+    end
+
+    File.join(spec.full_gem_path, spec.bindir, exec_name).sub(/.*\s.*/m, '"\&"')
+  end
+
+  ##
   # The mode needed to read a file as straight binary.
 
   def self.binary_mode
@@ -351,14 +507,27 @@
   #
   #   Gem.find_files('rdoc/discover').each do |path| load path end
   #
-  # find_files does not search $LOAD_PATH for files, only gems.
+  # find_files search $LOAD_PATH for files as well as gems.
+  #
+  # Note that find_files will return all files even if they are from different
+  # versions of the same gem.
 
   def self.find_files(path)
+    load_path_files = $LOAD_PATH.map do |load_path|
+      files = Dir["#{File.expand_path path, load_path}#{Gem.suffix_pattern}"]
+
+      files.select do |load_path_file|
+        File.file? load_path_file.untaint
+      end
+    end.flatten
+
     specs = searcher.find_all path
 
-    specs.map do |spec|
+    specs_files = specs.map do |spec|
       searcher.matching_files spec, path
     end.flatten
+
+    (load_path_files + specs_files).flatten.uniq
   end
 
   ##
@@ -373,7 +542,17 @@
   #   least on Win32).
 
   def self.find_home
-    File.expand_path("~")
+    unless RUBY_VERSION > '1.9' then
+      ['HOME', 'USERPROFILE'].each do |homekey|
+        return ENV[homekey] if ENV[homekey]
+      end
+
+      if ENV['HOMEDRIVE'] && ENV['HOMEPATH'] then
+        return "#{ENV['HOMEDRIVE']}#{ENV['HOMEPATH']}"
+      end
+    end
+
+    File.expand_path "~"
   rescue
     if File::ALT_SEPARATOR then
       "C:/"
@@ -477,7 +656,7 @@
   # The file name and line number of the caller of the caller of this method.
 
   def self.location_of_caller
-    caller[1] =~ /(.*?):(\d+)$/i
+    caller[1] =~ /(.*?):(\d+).*?$/i
     file = $1
     lineno = $2.to_i
 
@@ -485,15 +664,6 @@
   end
 
   ##
-  # manage_gems is useless and deprecated.  Don't call it anymore.
-
-  def self.manage_gems # :nodoc:
-    file, lineno = location_of_caller
-
-    warn "#{file}:#{lineno}:Warning: Gem::manage_gems is deprecated and will be removed on or after March 2009."
-  end
-
-  ##
   # The version of the Marshal format for your Ruby.
 
   def self.marshal_version
@@ -587,6 +757,33 @@
   end
 
   ##
+  # Promotes the load paths of the +gem_name+ over the load paths of
+  # +over_name+.  Useful for allowing one gem to override features in another
+  # using #find_files.
+
+  def self.promote_load_path(gem_name, over_name)
+    gem = Gem.loaded_specs[gem_name]
+    over = Gem.loaded_specs[over_name]
+
+    raise ArgumentError, "gem #{gem_name} is not activated" if gem.nil?
+    raise ArgumentError, "gem #{over_name} is not activated" if over.nil?
+
+    last_gem_path = File.join gem.full_gem_path, gem.require_paths.last
+
+    over_paths = over.require_paths.map do |path|
+      File.join over.full_gem_path, path
+    end
+
+    over_paths.each do |path|
+      $LOAD_PATH.delete path
+    end
+
+    gem = $LOAD_PATH.index(last_gem_path) + 1
+
+    $LOAD_PATH.insert(gem, *over_paths)
+  end
+
+  ##
   # Refresh source_index from disk and clear searcher.
 
   def self.refresh
@@ -628,15 +825,23 @@
 
   private_class_method :report_activate_error
 
-  def self.required_location(gemname, libfile, *version_constraints)
-    version_constraints = Gem::Requirement.default if version_constraints.empty?
-    matches = Gem.source_index.find_name(gemname, version_constraints)
+  ##
+  # Full path to +libfile+ in +gemname+.  Searches for the latest gem unless
+  # +requirements+ is given.
+
+  def self.required_location(gemname, libfile, *requirements)
+    requirements = Gem::Requirement.default if requirements.empty?
+
+    matches = Gem.source_index.find_name gemname, requirements
+
     return nil if matches.empty?
+
     spec = matches.last
     spec.require_paths.each do |path|
-      result = File.join(spec.full_gem_path, path, libfile)
-      return result if File.exist?(result)
+      result = File.join spec.full_gem_path, path, libfile
+      return result if File.exist? result
     end
+
     nil
   end
 
@@ -662,7 +867,13 @@
   def self.ruby_version
     return @ruby_version if defined? @ruby_version
     version = RUBY_VERSION.dup
-    version << ".#{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
+
+    if defined?(RUBY_PATCHLEVEL) && RUBY_PATCHLEVEL != -1 then
+      version << ".#{RUBY_PATCHLEVEL}"
+    elsif defined?(RUBY_REVISION) then
+      version << ".dev.#{RUBY_REVISION}"
+    end
+
     @ruby_version = Gem::Version.new version
   end
 
@@ -679,7 +890,7 @@
   # Set the Gem home directory (as reported by Gem.dir).
 
   def self.set_home(home)
-    home = home.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
+    home = home.gsub File::ALT_SEPARATOR, File::SEPARATOR if File::ALT_SEPARATOR
     @gem_home = home
   end
 
@@ -757,6 +968,31 @@
   end
 
   ##
+  # Prints the amount of time the supplied block takes to run using the debug
+  # UI output.
+
+  def self.time(msg, width = 0, display = Gem.configuration.verbose)
+    now = Time.now
+
+    value = yield
+
+    elapsed = Time.now - now
+
+    ui.say "%2$*1$s: %3$3.3fs" % [-width, msg, elapsed] if display
+
+    value
+  end
+
+  ##
+  # Lazily loads DefaultUserInteraction and returns the default UI.
+
+  def self.ui
+    require 'rubygems/user_interaction'
+
+    Gem::DefaultUserInteraction.ui
+  end
+
+  ##
   # Use the +home+ and +paths+ values for Gem.dir and Gem.path.  Used mainly
   # by the unit tests to provide environment isolation.
 
@@ -786,6 +1022,9 @@
 
   class << self
 
+    ##
+    # Hash of loaded Gem::Specification keyed by name
+
     attr_reader :loaded_specs
 
     ##
@@ -817,25 +1056,27 @@
 
   end
 
+  ##
+  # Location of Marshal quick gemspecs on remote repositories
+
   MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/"
 
+  ##
+  # Location of legacy YAML quick gemspecs on remote repositories
+
   YAML_SPEC_DIR = 'quick/'
 
 end
 
-module RbConfig
-  # :stopdoc:
-  class << self
-    # Return the path to the data directory associated with the named
-    # package.  If the package is loaded as a gem, return the gem
-    # specific data directory.  Otherwise return a path to the share
-    # area as define by "#{ConfigMap[:datadir]}/#{package_name}".
-    def datadir(package_name)
-      Gem.datadir(package_name) ||
-        File.join(Gem::ConfigMap[:datadir], package_name)
-    end
-  end
-  # :startdoc:
+##
+# Return the path to the data directory associated with the named package.  If
+# the package is loaded as a gem, return the gem specific data directory.
+# Otherwise return a path to the share area as define by
+# "#{ConfigMap[:datadir]}/#{package_name}".
+
+def RbConfig.datadir(package_name)
+  Gem.datadir(package_name) ||
+    File.join(Gem::ConfigMap[:datadir], package_name)
 end
 
 require 'rubygems/exceptions'
@@ -866,3 +1107,14 @@
 end
 
 Gem.clear_paths
+
+plugins = Gem.find_files 'rubygems_plugin'
+
+plugins.each do |plugin|
+  begin
+    load plugin
+  rescue => e
+    warn "error loading #{plugin.inspect}: #{e.message} (#{e.class})"
+  end
+end
+
Index: lib/gauntlet_rubygems.rb
===================================================================
--- lib/gauntlet_rubygems.rb	(revision 0)
+++ lib/gauntlet_rubygems.rb	(revision 23659)
@@ -0,0 +1,50 @@
+require 'rubygems'
+require 'gauntlet'
+
+##
+# GemGauntlet validates all current gems. Currently these packages are
+# borked:
+#
+# Asami-0.04           : No such file or directory - bin/Asami.rb
+# ObjectGraph-1.0.1    : No such file or directory - bin/objectgraph
+# evil-ruby-0.1.0      : authors must be Array of Strings
+# fresh_cookies-1.0.0  : authors must be Array of Strings
+# plugems_deploy-0.2.0 : authors must be Array of Strings
+# pmsrb-0.2.0          : authors must be Array of Strings
+# pqa-1.6              : authors must be Array of Strings
+# rant-0.5.7           : authors must be Array of Strings
+# rvsh-0.4.5           : No such file or directory - bin/rvsh
+# xen-0.1.2.1          : authors must be Array of Strings
+
+class GemGauntlet < Gauntlet
+  def run(name)
+    warn name
+
+    spec = begin
+             Gem::Specification.load 'gemspec'
+           rescue SyntaxError
+             Gem::Specification.from_yaml File.read('gemspec')
+           end
+    spec.validate
+
+    self.data[name] = false
+    self.dirty = true
+  rescue SystemCallError, Gem::InvalidSpecificationException => e
+    self.data[name] = e.message
+    self.dirty = true
+  end
+
+  def should_skip?(name)
+    self.data[name] == false
+  end
+
+  def report
+    self.data.sort.reject { |k,v| !v }.each do |k,v|
+      puts "%-21s: %s" % [k, v]
+    end
+  end
+end
+
+gauntlet = GemGauntlet.new
+gauntlet.run_the_gauntlet ARGV.shift
+gauntlet.report
Index: lib/rbconfig/datadir.rb
===================================================================
--- lib/rbconfig/datadir.rb	(revision 23658)
+++ lib/rbconfig/datadir.rb	(revision 23659)
@@ -4,20 +4,17 @@
 # See LICENSE.txt for permissions.
 #++
 
-
 module RbConfig
 
-  # Only define datadir if it doesn't already exist.
-  unless RbConfig.respond_to?(:datadir)
+  ##
+  # Return the path to the data directory associated with the given package
+  # name.  Normally this is just
+  # "#{RbConfig::CONFIG['datadir']}/#{package_name}", but may be modified by
+  # packages like RubyGems to handle versioned data directories.
 
-    # Return the path to the data directory associated with the given
-    # package name.  Normally this is just
-    # "#{RbConfig::CONFIG['datadir']}/#{package_name}", but may be
-    # modified by packages like RubyGems to handle versioned data
-    # directories.
-    def RbConfig.datadir(package_name)
-      File.join(CONFIG['datadir'], package_name)
-    end
+  def self.datadir(package_name)
+    File.join(CONFIG['datadir'], package_name)
+  end unless RbConfig.respond_to?(:datadir)
 
-  end
 end
+
Index: bin/gem
===================================================================
--- bin/gem	(revision 23658)
+++ bin/gem	(revision 23659)
@@ -9,16 +9,13 @@
 require 'rubygems/gem_runner'
 require 'rubygems/exceptions'
 
-required_version = Gem::Requirement.new "> 1.8.3"
+required_version = Gem::Requirement.new ">= 1.8.6"
 
 unless required_version.satisfied_by? Gem.ruby_version then
-  abort "Expected Ruby Version #{required_version}, was #{Gem.ruby_version}"
+  abort "Expected Ruby Version #{required_version}, is #{Gem.ruby_version}"
 end
 
-# We need to preserve the original ARGV to use for passing gem options
-# to source gems.  If there is a -- in the line, strip all options after
-# it...its for the source building process.
-args = !ARGV.include?("--") ? ARGV.clone : ARGV[0...ARGV.index("--")]
+args = ARGV.clone
 
 begin
   Gem::GemRunner.new.run args
Index: test/rubygems/test_kernel.rb
===================================================================
--- test/rubygems/test_kernel.rb	(revision 23658)
+++ test/rubygems/test_kernel.rb	(revision 23659)
@@ -31,14 +31,14 @@
 
   def test_gem_redundent
     assert gem('a', '= 1'), "Should load"
-    assert ! gem('a', '= 1'), "Should not load"
+    refute gem('a', '= 1'), "Should not load"
     assert_equal 1, $:.select { |p| %r{a-1/lib} =~ p }.size
     assert_equal 1, $:.select { |p| %r{a-1/bin} =~ p }.size
   end
 
   def test_gem_overlapping
     assert gem('a', '= 1'), "Should load"
-    assert ! gem('a', '>= 1'), "Should not load"
+    refute gem('a', '>= 1'), "Should not load"
     assert_equal 1, $:.select { |p| %r{a-1/lib} =~ p }.size
     assert_equal 1, $:.select { |p| %r{a-1/bin} =~ p }.size
   end
@@ -46,17 +46,19 @@
   def test_gem_conflicting
     assert gem('a', '= 1'), "Should load"
 
-    ex = assert_raises Gem::Exception do
+    ex = assert_raises Gem::LoadError do
       gem 'a', '= 2'
     end
 
     assert_match(/activate a \(= 2, runtime\)/, ex.message)
     assert_match(/activated a-1/, ex.message)
+    assert_equal 'a', ex.name
+    assert_equal Gem::Requirement.new('= 2'), ex.version_requirement
 
     assert $:.any? { |p| %r{a-1/lib} =~ p }
     assert $:.any? { |p| %r{a-1/bin} =~ p }
-    assert ! $:.any? { |p| %r{a-2/lib} =~ p }
-    assert ! $:.any? { |p| %r{a-2/bin} =~ p }
+    refute $:.any? { |p| %r{a-2/lib} =~ p }
+    refute $:.any? { |p| %r{a-2/bin} =~ p }
   end
 
 end
Index: test/rubygems/test_gem_commands_uninstall_command.rb
===================================================================
--- test/rubygems/test_gem_commands_uninstall_command.rb	(revision 23658)
+++ test/rubygems/test_gem_commands_uninstall_command.rb	(revision 23659)
@@ -53,9 +53,10 @@
       end
     end
 
-    assert_match(/\AUnknown gem foo >= 0$/, e.message)
+    assert_match(/\Acannot uninstall, check `gem list -d foo`$/, e.message)
     output = @ui.output.split "\n"
-    assert output.empty?, "UI output should be empty after an uninstall error"
+    assert_empty output, "UI output should be empty after an uninstall error"
   end
+
 end
 
Index: test/rubygems/test_gem_spec_fetcher.rb
===================================================================
--- test/rubygems/test_gem_spec_fetcher.rb	(revision 23658)
+++ test/rubygems/test_gem_spec_fetcher.rb	(revision 23659)
@@ -10,22 +10,31 @@
 
     util_setup_fake_fetcher
 
+    @a_pre = quick_gem 'a', '1.a'
     @source_index.add_spec @pl1
+    @source_index.add_spec @a_pre
 
     @specs = @source_index.gems.sort.map do |name, spec|
       [spec.name, spec.version, spec.original_platform]
     end.sort
 
-    @fetcher.data["#{@gem_repo}specs.#{Gem.marshal_version}.gz"] =
-      util_gzip(Marshal.dump(@specs))
-
     @latest_specs = @source_index.latest_specs.sort.map do |spec|
       [spec.name, spec.version, spec.original_platform]
     end
 
+    @prerelease_specs = @source_index.prerelease_gems.sort.map do |name, spec|
+      [spec.name, spec.version, spec.original_platform]
+    end.sort
+
+    @fetcher.data["#{@gem_repo}specs.#{Gem.marshal_version}.gz"] =
+      util_gzip(Marshal.dump(@specs))
+
     @fetcher.data["#{@gem_repo}latest_specs.#{Gem.marshal_version}.gz"] =
       util_gzip(Marshal.dump(@latest_specs))
 
+    @fetcher.data["#{@gem_repo}prerelease_specs.#{Gem.marshal_version}.gz"] =
+      util_gzip(Marshal.dump(@prerelease_specs))
+
     @sf = Gem::SpecFetcher.new
   end
 
@@ -34,6 +43,8 @@
       util_zip(Marshal.dump(@a1))
     @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a2.full_name}.gemspec.rz"] =
       util_zip(Marshal.dump(@a2))
+    @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a_pre.full_name}.gemspec.rz"] =
+      util_zip(Marshal.dump(@a_pre))
 
     dep = Gem::Dependency.new 'a', 1
     specs_and_sources = @sf.fetch dep, true
@@ -54,6 +65,8 @@
       util_zip(Marshal.dump(@a1))
     @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a2.full_name}.gemspec.rz"] =
       util_zip(Marshal.dump(@a2))
+    @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a_pre.full_name}.gemspec.rz"] =
+      util_zip(Marshal.dump(@a_pre))
 
     dep = Gem::Dependency.new 'a', 1
     specs_and_sources = @sf.fetch dep
@@ -65,6 +78,24 @@
     assert_equal [[@a2.full_name, @gem_repo]], spec_names
   end
 
+  def test_fetch_prerelease
+    @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a1.full_name}.gemspec.rz"] =
+      util_zip(Marshal.dump(@a1))
+    @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a2.full_name}.gemspec.rz"] =
+      util_zip(Marshal.dump(@a2))
+    @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@a_pre.full_name}.gemspec.rz"] =
+      util_zip(Marshal.dump(@a_pre))
+
+    dep = Gem::Dependency.new 'a', '1.a'
+    specs_and_sources = @sf.fetch dep, false, true, true
+
+    spec_names = specs_and_sources.map do |spec, source_uri|
+      [spec.full_name, source_uri]
+    end
+
+    assert_equal [[@a_pre.full_name, @gem_repo]], spec_names
+  end
+
   def test_fetch_legacy_repo
     @fetcher.data.delete "#{@gem_repo}specs.#{Gem.marshal_version}.gz"
     @fetcher.data["#{@gem_repo}yaml"] = ''
@@ -186,6 +217,17 @@
     assert_equal expected, specs
   end
 
+  def test_find_matching_prerelease
+    dep = Gem::Dependency.new 'a', '1.a'
+    specs = @sf.find_matching dep, false, true, true
+
+    expected = [
+      [['a', Gem::Version.new('1.a'), Gem::Platform::RUBY], @gem_repo],
+    ]
+
+    assert_equal expected, specs
+  end
+
   def test_find_matching_platform
     util_set_arch 'i386-linux'
 
@@ -237,7 +279,7 @@
   def test_list_cache
     specs = @sf.list
 
-    assert !specs[@uri].empty?
+    refute specs[@uri].empty?
 
     @fetcher.data["#{@gem_repo}/latest_specs.#{Gem.marshal_version}.gz"] = nil
 
@@ -249,7 +291,7 @@
   def test_list_cache_all
     specs = @sf.list true
 
-    assert !specs[@uri].empty?
+    refute specs[@uri].empty?
 
     @fetcher.data["#{@gem_repo}/specs.#{Gem.marshal_version}.gz"] = nil
 
@@ -268,6 +310,12 @@
     assert_equal [@specs], specs.values, 'specs file not loaded'
   end
 
+  def test_list_prerelease
+    specs = @sf.list false, true
+
+    assert_equal @prerelease_specs, specs[@uri].sort
+  end
+
   def test_load_specs
     specs = @sf.load_specs @uri, 'specs'
 
@@ -308,5 +356,29 @@
     assert_equal @latest_specs, latest_specs
   end
 
+  def test_load_specs_cached_empty
+    @fetcher.data["#{@gem_repo}latest_specs.#{Gem.marshal_version}.gz"] =
+      proc do
+        @fetcher.data["#{@gem_repo}latest_specs.#{Gem.marshal_version}.gz"] =
+          util_gzip(Marshal.dump(@latest_specs))
+
+        nil
+      end
+
+    cache_dir = File.join Gem.user_home, '.gem', 'specs', 'gems.example.com%80'
+
+    FileUtils.mkdir_p cache_dir
+
+    cache_file = File.join cache_dir, "latest_specs.#{Gem.marshal_version}"
+
+    open cache_file, 'wb' do |io|
+      io.write Marshal.dump(@latest_specs)[0, 10]
+    end
+
+    latest_specs = @sf.load_specs @uri, 'latest_specs'
+
+    assert_equal @latest_specs, latest_specs
+  end
+
 end
 
Index: test/rubygems/test_gem_dependency_installer.rb
===================================================================
--- test/rubygems/test_gem_dependency_installer.rb	(revision 23658)
+++ test/rubygems/test_gem_dependency_installer.rb	(revision 23659)
@@ -13,8 +13,10 @@
     write_file File.join('gems', 'a-1', 'bin', 'a_bin') do |fp|
       fp.puts "#!/usr/bin/ruby"
     end
+
     @a1, @a1_gem = util_gem 'a', '1' do |s| s.executables << 'a_bin' end
     @aa1, @aa1_gem = util_gem 'aa', '1'
+    @a1_pre, @a1_pre_gem = util_gem 'a', '1.a'
 
     @b1, @b1_gem = util_gem 'b', '1' do |s|
       s.add_dependency 'a'
@@ -44,8 +46,8 @@
     @fetcher = Gem::FakeFetcher.new
     Gem::RemoteFetcher.fetcher = @fetcher
 
-    si = util_setup_spec_fetcher @a1, @b1, @d1, @d2, @x1_m, @x1_o, @w1, @y1,
-                                 @y1_1_p, @z1
+    si = util_setup_spec_fetcher(@a1, @a1_pre, @b1, @d1, @d2, @x1_m, @x1_o, @w1, @y1,
+                                 @y1_1_p, @z1)
 
     util_clear_gems
   end
@@ -257,7 +259,7 @@
       inst.install 'a'
     end
 
-    assert_match %r|\A#!/\S+/env #{Gem::ConfigMap[:RUBY_INSTALL_NAME]}\n|,
+    assert_match %r|\A#!/\S+/env #{Gem::ConfigMap[:ruby_install_name]}\n|,
                  File.read(File.join(@gemhome, 'bin', 'a_bin'))
   end
 
@@ -356,13 +358,15 @@
     FileUtils.mv @b1_gem, @tempdir
     inst = nil
 
-    Gem.source_index.gems.delete @a1.full_name
+    Gem.source_index.remove_spec @a1.full_name
+    Gem.source_index.remove_spec @a1_pre.full_name
 
     Dir.chdir @tempdir do
       e = assert_raises Gem::InstallError do
         inst = Gem::DependencyInstaller.new :domain => :local
         inst.install 'b'
       end
+
       assert_equal 'b requires a (>= 0, runtime)', e.message
     end
 
@@ -632,5 +636,16 @@
     assert_equal %w[d-1 e-1], inst.gems_to_install.map { |s| s.full_name }
   end
 
+  def test_prerelease_uses_pre_index
+    installer = Gem::DependencyInstaller.new
+    pre_installer = Gem::DependencyInstaller.new(:prerelease => true)
+    dependency = Gem::Dependency.new('a', Gem::Requirement.default)
+
+    releases = installer.find_gems_with_sources(dependency).map{ |gems, *| gems }
+    prereleases = pre_installer.find_gems_with_sources(dependency).map{ |gems, *| gems }
+
+    assert releases.select{ |s| s.name == 'a' and s.version.to_s == '1' }.first
+    assert releases.select{ |s| s.name == 'a' and s.version.to_s == '1.a' }.empty?
+    assert_equal [@a1_pre], prereleases
+  end
 end
-
Index: test/rubygems/test_gem_source_info_cache.rb
===================================================================
--- test/rubygems/test_gem_source_info_cache.rb	(revision 23658)
+++ test/rubygems/test_gem_source_info_cache.rb	(revision 23659)
@@ -294,7 +294,7 @@
 
     gem_names = @sic.search(//, false, true).map { |spec| spec.full_name }
 
-    assert_equal %w[a-1 a-2 a_evil-9 c-1.2], gem_names
+    assert_equal %w[a-1 a-2 a-3.a a_evil-9 c-1.2], gem_names
   end
 
   def test_search_dependency
Index: test/rubygems/test_gem_uninstaller.rb
===================================================================
--- test/rubygems/test_gem_uninstaller.rb	(revision 23658)
+++ test/rubygems/test_gem_uninstaller.rb	(revision 23659)
@@ -10,9 +10,28 @@
     ui = MockGemUi.new
     util_setup_gem ui
 
+    @user_spec.executables = ["my_exec"]
+
+    # HACK util_make_exec
+    user_bin_dir = File.join Gem.user_dir, 'gems', @user_spec.full_name, 'bin'
+    FileUtils.mkdir_p user_bin_dir
+    exec_path = File.join user_bin_dir, "my_exec"
+    File.open exec_path, 'w' do |f|
+      f.puts "#!/usr/bin/ruby"
+    end
+
+    user_bin_dir = File.join Gem.user_dir, 'bin'
+    FileUtils.mkdir_p user_bin_dir
+    exec_path = File.join user_bin_dir, "my_exec"
+    File.open exec_path, 'w' do |f|
+      f.puts "#!/usr/bin/ruby"
+    end
+
     build_rake_in do
       use_ui ui do
         @installer.install
+        @user_installer.install
+        Gem::Uninstaller.new(@user_spec.name, :executables => false).uninstall
       end
     end
   end
@@ -47,10 +66,23 @@
     assert_equal false, File.exist?(File.join(@gemhome, 'bin', 'executable'))
   end
 
+  def test_remove_executables_user
+    uninstaller = Gem::Uninstaller.new nil, :executables => true
+
+    use_ui @ui do
+      uninstaller.remove_executables @user_spec
+    end
+
+    exec_path = File.join Gem.user_dir, 'bin', 'my_exec'
+    assert_equal false, File.exist?(exec_path), 'removed exec from bin dir'
+
+    assert_equal "Removing my_exec\n", @ui.output
+  end
+
   def test_path_ok_eh
     uninstaller = Gem::Uninstaller.new nil
 
-    assert_equal true, uninstaller.path_ok?(@spec)
+    assert_equal true, uninstaller.path_ok?(@gemhome, @spec)
   end
 
   def test_path_ok_eh_legacy
@@ -59,9 +91,15 @@
     @spec.loaded_from.gsub! @spec.full_name, '\&-legacy'
     @spec.platform = 'legacy'
 
-    assert_equal true, uninstaller.path_ok?(@spec)
+    assert_equal true, uninstaller.path_ok?(@gemhome, @spec)
   end
 
+  def test_path_ok_eh_user
+    uninstaller = Gem::Uninstaller.new nil
+
+    assert_equal true, uninstaller.path_ok?(Gem.user_dir, @user_spec)
+  end
+
   def test_uninstall
     uninstaller = Gem::Uninstaller.new @spec.name, :executables => true
 
@@ -72,16 +110,38 @@
     end
 
     Gem.post_uninstall do
-      assert !File.exist?(gem_dir), 'gem_dir should not exist'
+      refute File.exist?(gem_dir), 'gem_dir should not exist'
     end
 
     uninstaller.uninstall
 
-    assert !File.exist?(gem_dir)
+    refute File.exist?(gem_dir)
 
     assert_same uninstaller, @pre_uninstall_hook_arg
     assert_same uninstaller, @post_uninstall_hook_arg
   end
 
+  def test_uninstall_user
+    uninstaller = Gem::Uninstaller.new @user_spec.name, :executables => true,
+                  :user_install => true
+
+    gem_dir = File.join Gem.user_dir, 'gems', @user_spec.full_name
+
+    Gem.pre_uninstall do
+      assert File.exist?(gem_dir), 'gem_dir should exist'
+    end
+
+    Gem.post_uninstall do
+      refute File.exist?(gem_dir), 'gem_dir should not exist'
+    end
+
+    uninstaller.uninstall
+
+    refute File.exist?(gem_dir)
+
+    assert_same uninstaller, @pre_uninstall_hook_arg
+    assert_same uninstaller, @post_uninstall_hook_arg
+  end
+
 end
 
Index: test/rubygems/test_gem_commands_generate_index_command.rb
===================================================================
--- test/rubygems/test_gem_commands_generate_index_command.rb	(revision 23658)
+++ test/rubygems/test_gem_commands_generate_index_command.rb	(revision 23659)
@@ -1,4 +1,3 @@
-require 'minitest/unit'
 require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
 require 'rubygems/indexer'
 require 'rubygems/commands/generate_index_command'
@@ -28,5 +27,109 @@
     assert File.exist?(quick_index_rz), quick_index_rz
   end
 
+  def test_execute_rss_update
+    @cmd.options[:update] = true
+    @cmd.options[:rss_host] = 'example.com'
+    @cmd.options[:rss_gems_host] = 'gems.example.com'
+
+    use_ui @ui do
+      assert_raises MockGemUi::TermError do
+        @cmd.execute
+      end
+    end
+
+    assert_equal "ERROR:  --update not compatible with RSS generation\n",
+                 @ui.error
+    assert_empty @ui.output
+  end
+
+  def test_handle_options_directory
+    return if win_platform?
+    refute_equal '/nonexistent', @cmd.options[:directory]
+
+    @cmd.handle_options %w[--directory /nonexistent]
+
+    assert_equal '/nonexistent', @cmd.options[:directory]
+  end
+
+  def test_handle_options_directory_windows
+    return unless win_platform?
+
+    refute_equal '/nonexistent', @cmd.options[:directory]
+
+    @cmd.handle_options %w[--directory C:/nonexistent]
+
+    assert_equal 'C:/nonexistent', @cmd.options[:directory]
+  end
+
+  def test_handle_options_invalid
+    e = assert_raises OptionParser::InvalidOption do
+      @cmd.handle_options %w[--no-modern --no-legacy]
+    end
+
+    assert_equal 'invalid option: --no-legacy no indicies will be built',
+                 e.message
+
+    @cmd = Gem::Commands::GenerateIndexCommand.new
+    e = assert_raises OptionParser::InvalidOption do
+      @cmd.handle_options %w[--no-legacy --no-modern]
+    end
+
+    assert_equal 'invalid option: --no-modern no indicies will be built',
+                 e.message
+  end
+
+  def test_handle_options_legacy
+    @cmd.handle_options %w[--legacy]
+
+    assert @cmd.options[:build_legacy]
+    assert @cmd.options[:build_modern], ':build_modern not set'
+  end
+
+  def test_handle_options_modern
+    @cmd.handle_options %w[--modern]
+
+    assert @cmd.options[:build_legacy]
+    assert @cmd.options[:build_modern], ':build_modern not set'
+  end
+
+  def test_handle_options_no_legacy
+    @cmd.handle_options %w[--no-legacy]
+
+    refute @cmd.options[:build_legacy]
+    assert @cmd.options[:build_modern]
+  end
+
+  def test_handle_options_no_modern
+    @cmd.handle_options %w[--no-modern]
+
+    assert @cmd.options[:build_legacy]
+    refute @cmd.options[:build_modern]
+  end
+
+  def test_handle_options_rss_gems_host
+    @cmd.handle_options %w[--rss-gems-host gems.example.com]
+
+    assert_equal 'gems.example.com', @cmd.options[:rss_gems_host]
+  end
+
+  def test_handle_options_rss_host
+    @cmd.handle_options %w[--rss-host example.com]
+
+    assert_equal 'example.com', @cmd.options[:rss_host]
+  end
+
+  def test_handle_options_rss_title
+    @cmd.handle_options %w[--rss-title Example\ Gems]
+
+    assert_equal 'Example Gems', @cmd.options[:rss_title]
+  end
+
+  def test_handle_options_update
+    @cmd.handle_options %w[--update]
+
+    assert @cmd.options[:update]
+  end
+
 end if ''.respond_to? :to_xs
 
Index: test/rubygems/test_gem_gem_path_searcher.rb
===================================================================
--- test/rubygems/test_gem_gem_path_searcher.rb	(revision 23658)
+++ test/rubygems/test_gem_gem_path_searcher.rb	(revision 23659)
@@ -51,7 +51,7 @@
   end
 
   def test_matching_file_eh
-    assert !@gps.matching_file?(@foo1, 'bar')
+    refute @gps.matching_file?(@foo1, 'bar')
     assert @gps.matching_file?(@foo1, 'foo')
   end
 
Index: test/rubygems/test_gem_gem_runner.rb
===================================================================
--- test/rubygems/test_gem_gem_runner.rb	(revision 23658)
+++ test/rubygems/test_gem_gem_runner.rb	(revision 23659)
@@ -30,5 +30,16 @@
     assert_equal %w[--all], Gem::DocManager.configured_args
   end
 
+  def test_build_args__are_handled
+    Gem.clear_paths
+
+    gr = Gem::GemRunner.new
+    assert_raises(Gem::SystemExitException) do
+      gr.run(%W[--help -- --build_arg1 --build_arg2])
+    end
+
+    assert_equal %w[--build_arg1 --build_arg2], Gem::Command.build_args
+  end
+
 end
 
Index: test/rubygems/test_gem_ext_configure_builder.rb
===================================================================
--- test/rubygems/test_gem_ext_configure_builder.rb	(revision 23658)
+++ test/rubygems/test_gem_ext_configure_builder.rb	(revision 23659)
@@ -16,7 +16,7 @@
   end
 
   def test_self_build
-    return if RUBY_PLATFORM =~ /mswin/ # HACK
+    skip("test_self_build skipped on MS Windows (VC++)") if vc_windows?
 
     File.open File.join(@ext, './configure'), 'w' do |configure|
       configure.puts "#!/bin/sh\necho \"#{@makefile_body}\" > Makefile"
@@ -37,7 +37,7 @@
   end
 
   def test_self_build_fail
-    return if RUBY_PLATFORM =~ /mswin/ # HACK
+    skip("test_self_build_fail skipped on MS Windows (VC++)") if vc_windows?
     output = []
 
     error = assert_raises Gem::InstallError do
@@ -63,6 +63,10 @@
   end
 
   def test_self_build_has_makefile
+    if vc_windows? && !nmake_found?
+      skip("test_self_build_has_makefile skipped - nmake not found")
+    end
+
     File.open File.join(@ext, 'Makefile'), 'w' do |makefile|
       makefile.puts @makefile_body
     end
@@ -72,14 +76,8 @@
       Gem::Ext::ConfigureBuilder.build nil, nil, @dest_path, output
     end
 
-    case RUBY_PLATFORM
-    when /mswin/ then
-      assert_equal 'nmake', output[0]
-      assert_equal 'nmake install', output[2]
-    else
-      assert_equal 'make', output[0]
-      assert_equal 'make install', output[2]
-    end
+    assert_equal make_command, output[0]
+    assert_equal "#{make_command} install", output[2]
   end
 
 end
Index: test/rubygems/test_gem_command_manager.rb
===================================================================
--- test/rubygems/test_gem_command_manager.rb	(revision 23658)
+++ test/rubygems/test_gem_command_manager.rb	(revision 23659)
@@ -7,29 +7,16 @@
 require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
 require 'rubygems/command_manager'
 
-class InterruptCommand < Gem::Command
-
-  def initialize
-    super('interrupt', 'Raises an Interrupt Exception', {})
-  end
-
-  def execute
-    raise Interrupt, "Interrupt exception"
-  end
-
-end
-
 class TestGemCommandManager < RubyGemTestCase
 
   def setup
     super
 
-    @command_manager = Gem::CommandManager.new
+    @command_manager = Gem::CommandManager.instance
   end
 
   def test_run_interrupt
     use_ui @ui do
-      @command_manager.register_command :interrupt
       assert_raises MockGemUi::TermError do
         @command_manager.run 'interrupt'
       end
Index: test/rubygems/test_gem_dependency_list.rb
===================================================================
--- test/rubygems/test_gem_dependency_list.rb	(revision 23658)
+++ test/rubygems/test_gem_dependency_list.rb	(revision 23659)
@@ -105,7 +105,7 @@
 
     @deplist.add @b2
 
-    assert ! @deplist.ok?, 'unsatisfied dependency'
+    refute @deplist.ok?, 'unsatisfied dependency'
 
     @deplist.add @a1
 
@@ -144,7 +144,7 @@
 
     @deplist.add @b2
 
-    assert ! @deplist.ok_to_remove?("a-1")
+    refute @deplist.ok_to_remove?("a-1")
 
     @deplist.add @a2
 
@@ -161,7 +161,7 @@
 
     @deplist.remove_by_name("a-1")
 
-    assert ! @deplist.ok_to_remove?("a-2")
+    refute @deplist.ok_to_remove?("a-2")
   end
 
   def test_remove_by_name
@@ -169,7 +169,7 @@
 
     @deplist.remove_by_name "a-1"
 
-    assert ! @deplist.ok?
+    refute @deplist.ok?
   end
 
   def test_tsort_each_node
@@ -181,7 +181,7 @@
       assert_equal order.shift, node.full_name
     end
 
-    assert order.empty?
+    assert_empty order
   end
 
   def test_tsort_each_child
@@ -193,7 +193,7 @@
       assert_equal order.shift, node.full_name
     end
 
-    assert order.empty?
+    assert_empty order
   end
 
   # d1 -> b1 -> a1
Index: test/rubygems/test_gem_package_tar_header.rb
===================================================================
--- test/rubygems/test_gem_package_tar_header.rb	(revision 23658)
+++ test/rubygems/test_gem_package_tar_header.rb	(revision 23659)
@@ -58,7 +58,7 @@
     assert_equal 'user',  @tar_header.uname,    'uname'
     assert_equal '00',    @tar_header.version,  'version'
 
-    assert !@tar_header.empty?, 'empty'
+    refute_empty @tar_header, 'empty'
   end
 
   def test_initialize_bad
@@ -80,13 +80,13 @@
   end
 
   def test_empty_eh
-    assert !@tar_header.empty?
+    refute_empty @tar_header
 
     @tar_header = Gem::Package::TarHeader.new :name => 'x', :prefix => '',
                                               :mode => 0, :size => 0,
                                               :empty => true
 
-    assert @tar_header.empty?
+    assert_empty @tar_header
   end
 
   def test_equals2
Index: test/rubygems/test_gem_commands_contents_command.rb
===================================================================
--- test/rubygems/test_gem_commands_contents_command.rb	(revision 23658)
+++ test/rubygems/test_gem_commands_contents_command.rb	(revision 23659)
@@ -24,6 +24,27 @@
     assert_equal "", @ui.error
   end
 
+  def test_execute_all
+    @cmd.options[:all] = true
+
+    quick_gem 'foo' do |gem|
+      gem.files = %w[lib/foo.rb Rakefile]
+    end
+
+    quick_gem 'bar' do |gem|
+      gem.files = %w[lib/bar.rb Rakefile]
+    end
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    assert_match %r|lib/foo\.rb|, @ui.output
+    assert_match %r|lib/bar\.rb|, @ui.output
+    assert_match %r|Rakefile|, @ui.output
+    assert_equal "", @ui.error
+  end
+
   def test_execute_bad_gem
     @cmd.options[:args] = %w[foo]
 
@@ -75,6 +96,48 @@
     assert_equal "", @ui.error
   end
 
+  def test_execute_multiple
+    @cmd.options[:args] = %w[foo bar]
+    quick_gem 'foo' do |gem|
+      gem.files = %w[lib/foo.rb Rakefile]
+    end
+
+    quick_gem 'bar' do |gem|
+      gem.files = %w[lib/bar.rb Rakefile]
+    end
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    assert_match %r|lib/foo\.rb|, @ui.output
+    assert_match %r|lib/bar\.rb|, @ui.output
+    assert_match %r|Rakefile|, @ui.output
+    assert_equal "", @ui.error
+  end
+
+  def test_execute_no_prefix
+    @cmd.options[:args] = %w[foo]
+    @cmd.options[:prefix] = false
+
+    quick_gem 'foo' do |gem|
+      gem.files = %w[lib/foo.rb Rakefile]
+    end
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    expected = <<-EOF
+lib/foo.rb
+Rakefile
+    EOF
+
+    assert_equal expected, @ui.output
+
+    assert_equal "", @ui.error
+  end
+
   def test_handle_options
     assert_equal false, @cmd.options[:lib_only]
     assert_equal [], @cmd.options[:specdirs]
Index: test/rubygems/test_gem_version_option.rb
===================================================================
--- test/rubygems/test_gem_version_option.rb	(revision 23658)
+++ test/rubygems/test_gem_version_option.rb	(revision 23659)
@@ -23,6 +23,19 @@
     assert @cmd.handles?(%w[--version >1])
   end
 
+  def test_enables_prerelease
+    @cmd.add_version_option
+
+    @cmd.handle_options %w[mygem -v 0.2.0.a]
+    assert @cmd.options[:prerelease]
+
+    @cmd.handle_options %w[mygem -v 0.2.0]
+    refute @cmd.options[:prerelease]
+
+    @cmd.handle_options %w[mygem]
+    refute @cmd.options[:prerelease]
+  end
+
   def test_platform_option
     @cmd.add_platform_option
 
Index: test/rubygems/insure_session.rb
===================================================================
--- test/rubygems/insure_session.rb	(revision 23658)
+++ test/rubygems/insure_session.rb	(revision 23659)
@@ -23,7 +23,7 @@
     puts
     puts "with the appropriate admin privileges."
     puts "*****************************************************************"
-    puts
+    puts 
     exit
   end
   gem 'session'
Index: test/rubygems/test_gem_commands_environment_command.rb
===================================================================
--- test/rubygems/test_gem_commands_environment_command.rb	(revision 23658)
+++ test/rubygems/test_gem_commands_environment_command.rb	(revision 23659)
@@ -24,7 +24,7 @@
     assert_match %r|INSTALLATION DIRECTORY: #{Regexp.escape @gemhome}|,
                  @ui.output
     assert_match %r|RUBYGEMS PREFIX: |, @ui.output
-    assert_match %r|RUBY EXECUTABLE:.*#{Gem::ConfigMap[:RUBY_INSTALL_NAME]}|,
+    assert_match %r|RUBY EXECUTABLE:.*#{Gem::ConfigMap[:ruby_install_name]}|,
                  @ui.output
     assert_match %r|EXECUTABLE DIRECTORY:|, @ui.output
     assert_match %r|RUBYGEMS PLATFORMS:|, @ui.output
Index: test/rubygems/rubygems_plugin.rb
===================================================================
--- test/rubygems/rubygems_plugin.rb	(revision 0)
+++ test/rubygems/rubygems_plugin.rb	(revision 23659)
@@ -0,0 +1,16 @@
+require 'rubygems/command_manager'
+
+class Gem::Commands::InterruptCommand < Gem::Command
+
+  def initialize
+    super('interrupt', 'Raises an Interrupt Exception', {})
+  end
+
+  def execute
+    raise Interrupt, "Interrupt exception"
+  end
+
+end
+
+Gem::CommandManager.instance.register_command :interrupt
+
Index: test/rubygems/gem_installer_test_case.rb
===================================================================
--- test/rubygems/gem_installer_test_case.rb	(revision 23658)
+++ test/rubygems/gem_installer_test_case.rb	(revision 23659)
@@ -1,4 +1,3 @@
-require 'minitest/unit'
 require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
 require 'rubygems/installer'
 
@@ -20,17 +19,17 @@
   def setup
     super
 
-    @spec = quick_gem "a"
+    @spec = quick_gem 'a'
     @gem = File.join @tempdir, "#{@spec.full_name}.gem"
 
-    util_build_gem @spec
-    FileUtils.mv File.join(@gemhome, 'cache', "#{@spec.full_name}.gem"),
-                 @tempdir
+    @installer = util_installer @spec, @gem, @gemhome
 
-    @installer = Gem::Installer.new @gem
-    @installer.gem_dir = util_gem_dir
-    @installer.gem_home = @gemhome
-    @installer.spec = @spec
+    @user_spec = quick_gem 'b'
+    @user_gem = File.join @tempdir, "#{@user_spec.full_name}.gem"
+
+    @user_installer = util_installer @user_spec, @user_gem, Gem.user_dir
+    @user_installer.gem_dir = File.join(Gem.user_dir, 'gems',
+                                        @user_spec.full_name)
   end
 
   def util_gem_bindir(version = '2')
@@ -49,8 +48,7 @@
     @spec.executables = ["my_exec"]
 
     FileUtils.mkdir_p util_gem_bindir(version)
-    exec_file = @installer.formatted_program_filename "my_exec"
-    exec_path = File.join util_gem_bindir(version), exec_file
+    exec_path = File.join util_gem_bindir(version), "my_exec"
     File.open exec_path, 'w' do |f|
       f.puts shebang
     end
@@ -82,5 +80,18 @@
     @installer = Gem::Installer.new @gem
   end
 
+  def util_installer(spec, gem_path, gem_home)
+    util_build_gem spec
+    FileUtils.mv File.join(@gemhome, 'cache', "#{spec.full_name}.gem"),
+                 @tempdir
+
+    installer = Gem::Installer.new gem_path
+    installer.gem_dir = util_gem_dir
+    installer.gem_home = gem_home
+    installer.spec = spec
+
+    installer
+  end
+
 end
 
Index: test/rubygems/foo/discover.rb
===================================================================
Index: test/rubygems/test_gem_remote_fetcher.rb
===================================================================
--- test/rubygems/test_gem_remote_fetcher.rb	(revision 23658)
+++ test/rubygems/test_gem_remote_fetcher.rb	(revision 23659)
@@ -151,7 +151,7 @@
       fetcher.fetch_size 'gems.example.com/yaml'
     end
 
-    assert_equal 'uri is not an HTTP URI', e.message
+    assert_equal 'uri scheme is invalid', e.message
   end
 
   def test_fetch_size_socket_error
@@ -237,6 +237,21 @@
                  inst.download(@a1, local_path)
   end
 
+  def test_download_local_space
+    space_path = File.join @tempdir, 'space path'
+    FileUtils.mkdir space_path
+    FileUtils.mv @a1_gem, space_path
+    local_path = File.join space_path, "#{@a1.full_name}.gem"
+    inst = nil
+
+    Dir.chdir @tempdir do
+      inst = Gem::RemoteFetcher.fetcher
+    end
+
+    assert_equal File.join(@gemhome, 'cache', "#{@a1.full_name}.gem"),
+                 inst.download(@a1, local_path)
+  end
+
   def test_download_install_dir
     a1_data = nil
     File.open @a1_gem, 'rb' do |fp|
@@ -463,6 +478,13 @@
     assert_equal nil, fetcher.fetch_path(URI.parse(@gem_repo), Time.at(0))
   end
 
+  def test_get_proxy_from_env_auto_normalizes
+    fetcher = Gem::RemoteFetcher.new(nil)
+    ENV['HTTP_PROXY'] = 'fakeurl:12345'
+
+    assert_equal('http://fakeurl:12345', fetcher.get_proxy_from_env.to_s)
+  end
+
   def test_get_proxy_from_env_empty
     orig_env_HTTP_PROXY = ENV['HTTP_PROXY']
     orig_env_http_proxy = ENV['http_proxy']
Index: test/rubygems/test_gem_package_tar_writer.rb
===================================================================
--- test/rubygems/test_gem_package_tar_writer.rb	(revision 23658)
+++ test/rubygems/test_gem_package_tar_writer.rb	(revision 23659)
@@ -46,7 +46,7 @@
   def test_add_file_simple_padding
     @tar_writer.add_file_simple 'x', 0, 100
 
-    assert_headers_equal tar_file_header('x', '', 0, 100),
+    assert_headers_equal tar_file_header('x', '', 0, 100), 
                          @io.string[0, 512]
 
     assert_equal "\0" * 512, @io.string[512, 512]
@@ -61,7 +61,7 @@
   end
 
   def test_add_file_simple_size
-    assert_raises Gem::Package::TarWriter::FileOverflow do
+    assert_raises Gem::Package::TarWriter::FileOverflow do 
       @tar_writer.add_file_simple("lib/foo/bar", 0, 10) do |io|
         io.write "1" * 11
       end
@@ -69,7 +69,7 @@
   end
 
   def test_add_file_unseekable
-    assert_raises Gem::Package::NonSeekableIO do
+    assert_raises Gem::Package::NonSeekableIO do 
       Gem::Package::TarWriter.new(Object.new).add_file 'x', 0
     end
   end
Index: test/rubygems/test_gem_commands_sources_command.rb
===================================================================
--- test/rubygems/test_gem_commands_sources_command.rb	(revision 23658)
+++ test/rubygems/test_gem_commands_sources_command.rb	(revision 23659)
@@ -11,6 +11,10 @@
     @new_repo = "http://beta-gems.example.com"
   end
 
+  def test_initialize_proxy
+    assert @cmd.handles?(['--http-proxy', 'http://proxy.example.com'])
+  end
+
   def test_execute
     util_setup_spec_fetcher
     @cmd.handle_options []
@@ -175,12 +179,12 @@
     assert_equal expected, @ui.output
     assert_equal '', @ui.error
 
-    assert !File.exist?(cache.system_cache_file),
+    refute File.exist?(cache.system_cache_file),
            'system cache file'
-    assert !File.exist?(cache.latest_system_cache_file),
+    refute File.exist?(cache.latest_system_cache_file),
            'latest system cache file'
 
-    assert !File.exist?(fetcher.dir), 'cache dir removed'
+    refute File.exist?(fetcher.dir), 'cache dir removed'
   end
 
   def test_execute_remove
Index: test/rubygems/test_gem_commands_pristine_command.rb
===================================================================
--- test/rubygems/test_gem_commands_pristine_command.rb	(revision 23658)
+++ test/rubygems/test_gem_commands_pristine_command.rb	(revision 23659)
@@ -35,7 +35,7 @@
 
     assert_equal "Restoring gem(s) to pristine condition...", out.shift
     assert_equal "Restored #{a.full_name}", out.shift
-    assert out.empty?, out.inspect
+    assert_empty out, out.inspect
   end
 
   def test_execute_all
@@ -63,7 +63,7 @@
 
     assert_equal "Restoring gem(s) to pristine condition...", out.shift
     assert_equal "Restored #{a.full_name}", out.shift
-    assert out.empty?, out.inspect
+    assert_empty out, out.inspect
   end
 
   def test_execute_missing_cache_gem
@@ -86,7 +86,7 @@
     out = @ui.output.split "\n"
 
     assert_equal "Restoring gem\(s\) to pristine condition...", out.shift
-    assert out.empty?, out.inspect
+    assert_empty out, out.inspect
 
     assert_equal "ERROR:  Cached gem for #{a.full_name} not found, use `gem install` to restore\n",
                  @ui.error
Index: test/rubygems/test_gem.rb
===================================================================
--- test/rubygems/test_gem.rb	(revision 23658)
+++ test/rubygems/test_gem.rb	(revision 23659)
@@ -24,6 +24,7 @@
     expected = [
       File.join(@gemhome, *%W[gems #{@a1.full_name} lib]),
       File.join(@gemhome, *%W[gems #{@a2.full_name} lib]),
+      File.join(@gemhome, *%W[gems #{@a3a.full_name} lib]),
       File.join(@gemhome, *%W[gems #{@a_evil9.full_name} lib]),
       File.join(@gemhome, *%W[gems #{@b2.full_name} lib]),
       File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]),
@@ -41,6 +42,56 @@
     assert(!Gem.available?("monkeys"))
   end
 
+  def test_self_bin_path_bin_name
+    util_exec_gem
+    assert_equal @abin_path, Gem.bin_path('a', 'abin')
+  end
+
+  def test_self_bin_path_bin_name_version
+    util_exec_gem
+    assert_equal @abin_path, Gem.bin_path('a', 'abin', '4')
+  end
+
+  def test_self_bin_path_name
+    util_exec_gem
+    assert_equal @exec_path, Gem.bin_path('a')
+  end
+
+  def test_self_bin_path_name_version
+    util_exec_gem
+    assert_equal @exec_path, Gem.bin_path('a', nil, '4')
+  end
+
+  def test_self_bin_path_no_default_bin
+    quick_gem 'a', '2' do |s|
+      s.executables = ['exec']
+    end
+    assert_raises(Gem::Exception) do
+      Gem.bin_path('a', '2')
+    end
+  end
+
+  def test_self_bin_path_no_bin_file
+    quick_gem 'a', '1'
+    assert_raises(Gem::Exception) do
+      Gem.bin_path('a', '1')
+    end
+  end
+
+  def test_self_bin_path_with_spaces
+    quick_gem 'sp ace', '3' do |s|
+      s.executables = ['exec']
+    end
+    path = Gem.bin_path('sp ace', 'exec')
+    assert_equal %w(" "), [path[0,1], path[-1,1]], "Path should be escaped"
+  end
+
+  def test_self_bin_path_not_found
+    assert_raises(Gem::GemNotFoundException) do
+      Gem.bin_path('non-existent')
+    end
+  end
+
   def test_self_bindir
     assert_equal File.join(@gemhome, 'bin'), Gem.bindir
     assert_equal File.join(@gemhome, 'bin'), Gem.bindir(Gem.dir)
@@ -111,39 +162,30 @@
   end
 
   def test_self_default_exec_format
-    orig_BASERUBY = Gem::ConfigMap[:BASERUBY]
-    orig_RUBY_INSTALL_NAME = Gem::ConfigMap[:RUBY_INSTALL_NAME]
-    Gem::ConfigMap[:BASERUBY] = 'ruby'
-    Gem::ConfigMap[:RUBY_INSTALL_NAME] = 'ruby'
+    orig_RUBY_INSTALL_NAME = Gem::ConfigMap[:ruby_install_name]
+    Gem::ConfigMap[:ruby_install_name] = 'ruby'
 
     assert_equal '%s', Gem.default_exec_format
   ensure
-    Gem::ConfigMap[:BASERUBY] = orig_BASERUBY
-    Gem::ConfigMap[:RUBY_INSTALL_NAME] = orig_RUBY_INSTALL_NAME
+    Gem::ConfigMap[:ruby_install_name] = orig_RUBY_INSTALL_NAME
   end
 
   def test_self_default_exec_format_18
-    orig_BASERUBY = Gem::ConfigMap[:BASERUBY]
-    orig_RUBY_INSTALL_NAME = Gem::ConfigMap[:RUBY_INSTALL_NAME]
-    Gem::ConfigMap[:BASERUBY] = 'ruby'
-    Gem::ConfigMap[:RUBY_INSTALL_NAME] = 'ruby18'
+    orig_RUBY_INSTALL_NAME = Gem::ConfigMap[:ruby_install_name]
+    Gem::ConfigMap[:ruby_install_name] = 'ruby18'
 
     assert_equal '%s18', Gem.default_exec_format
   ensure
-    Gem::ConfigMap[:BASERUBY] = orig_BASERUBY
-    Gem::ConfigMap[:RUBY_INSTALL_NAME] = orig_RUBY_INSTALL_NAME
+    Gem::ConfigMap[:ruby_install_name] = orig_RUBY_INSTALL_NAME
   end
 
   def test_self_default_exec_format_jruby
-    orig_BASERUBY = Gem::ConfigMap[:BASERUBY]
-    orig_RUBY_INSTALL_NAME = Gem::ConfigMap[:RUBY_INSTALL_NAME]
-    Gem::ConfigMap[:BASERUBY] = 'ruby'
-    Gem::ConfigMap[:RUBY_INSTALL_NAME] = 'jruby'
+    orig_RUBY_INSTALL_NAME = Gem::ConfigMap[:ruby_install_name]
+    Gem::ConfigMap[:ruby_install_name] = 'jruby'
 
     assert_equal 'j%s', Gem.default_exec_format
   ensure
-    Gem::ConfigMap[:BASERUBY] = orig_BASERUBY
-    Gem::ConfigMap[:RUBY_INSTALL_NAME] = orig_RUBY_INSTALL_NAME
+    Gem::ConfigMap[:ruby_install_name] = orig_RUBY_INSTALL_NAME
   end
 
   def test_self_default_sources
@@ -166,7 +208,7 @@
   def test_self_ensure_gem_directories_missing_parents
     gemdir = File.join @tempdir, 'a/b/c/gemdir'
     FileUtils.rm_rf File.join(@tempdir, 'a') rescue nil
-    assert !File.exist?(File.join(@tempdir, 'a')),
+    refute File.exist?(File.join(@tempdir, 'a')),
            "manually remove #{File.join @tempdir, 'a'}, tests are broken"
     Gem.use_paths gemdir
 
@@ -179,14 +221,14 @@
     def test_self_ensure_gem_directories_write_protected
       gemdir = File.join @tempdir, "egd"
       FileUtils.rm_r gemdir rescue nil
-      assert !File.exist?(gemdir), "manually remove #{gemdir}, tests are broken"
+      refute File.exist?(gemdir), "manually remove #{gemdir}, tests are broken"
       FileUtils.mkdir_p gemdir
       FileUtils.chmod 0400, gemdir
       Gem.use_paths gemdir
 
       Gem.ensure_gem_subdirectories gemdir
 
-      assert !File.exist?("#{gemdir}/cache")
+      refute File.exist?("#{gemdir}/cache")
     ensure
       FileUtils.chmod 0600, gemdir
     end
@@ -196,14 +238,14 @@
       gemdir = "#{parent}/a/b/c"
 
       FileUtils.rm_r parent rescue nil
-      assert !File.exist?(parent), "manually remove #{parent}, tests are broken"
+      refute File.exist?(parent), "manually remove #{parent}, tests are broken"
       FileUtils.mkdir_p parent
       FileUtils.chmod 0400, parent
       Gem.use_paths(gemdir)
 
       Gem.ensure_gem_subdirectories gemdir
 
-      assert !File.exist?("#{gemdir}/cache")
+      refute File.exist?("#{gemdir}/cache")
     ensure
       FileUtils.chmod 0600, parent
     end
@@ -223,18 +265,20 @@
   end
 
   def test_self_find_files
+    discover_path = File.join 'lib', 'foo', 'discover.rb'
+
     foo1 = quick_gem 'foo', '1' do |s|
-      s.files << 'lib/foo/discover.rb'
+      s.files << discover_path
     end
 
     foo2 = quick_gem 'foo', '2' do |s|
-      s.files << 'lib/foo/discover.rb'
+      s.files << discover_path
     end
 
-    path = File.join 'gems', foo1.full_name, 'lib', 'foo', 'discover.rb'
+    path = File.join 'gems', foo1.full_name, discover_path
     write_file(path) { |fp| fp.puts "# #{path}" }
 
-    path = File.join 'gems', foo2.full_name, 'lib', 'foo', 'discover.rb'
+    path = File.join 'gems', foo2.full_name, discover_path
     write_file(path) { |fp| fp.puts "# #{path}" }
 
     @fetcher = Gem::FakeFetcher.new
@@ -245,18 +289,19 @@
     Gem.searcher = nil
 
     expected = [
-      File.join(foo1.full_gem_path, 'lib', 'foo', 'discover.rb'),
-      File.join(foo2.full_gem_path, 'lib', 'foo', 'discover.rb'),
+      File.expand_path('foo/discover.rb', File.dirname(__FILE__)),
+      File.join(foo2.full_gem_path, discover_path),
+      File.join(foo1.full_gem_path, discover_path),
     ]
 
-    assert_equal expected, Gem.find_files('foo/discover').sort
+    assert_equal expected, Gem.find_files('foo/discover')
   end
 
   def test_self_latest_load_paths
     util_make_gems
 
     expected = [
-      File.join(@gemhome, *%W[gems #{@a2.full_name} lib]),
+      File.join(@gemhome, *%W[gems #{@a3a.full_name} lib]),
       File.join(@gemhome, *%W[gems #{@a_evil9.full_name} lib]),
       File.join(@gemhome, *%W[gems #{@b2.full_name} lib]),
       File.join(@gemhome, *%W[gems #{@c1_2.full_name} lib]),
@@ -298,7 +343,7 @@
       apple_gem_home = File.join @tempdir, 'apple_gem_home'
       Gem.const_set :APPLE_GEM_HOME, apple_gem_home
 
-      assert Gem.path.include?(apple_gem_home)
+      assert_includes Gem.path, apple_gem_home
     ensure
       Gem.send :remove_const, :APPLE_GEM_HOME
     end
@@ -309,7 +354,7 @@
       apple_gem_home = File.join @tempdir, 'apple_gem_home'
       Gem.const_set :APPLE_GEM_HOME, apple_gem_home
 
-      assert !Gem.path.include?(apple_gem_home)
+      refute Gem.path.include?(apple_gem_home)
     ensure
       Gem.send :remove_const, :APPLE_GEM_HOME
     end
@@ -400,17 +445,17 @@
   def test_self_refresh
     util_make_gems
 
-    a1_spec = File.join @gemhome, "specifications", "#{@a1.full_name}.gemspec"
+    a1_spec = File.join @gemhome, "specifications", "#{@a1.full_name}.gemspec" 
 
     FileUtils.mv a1_spec, @tempdir
 
-    assert !Gem.source_index.gems.include?(@a1.full_name)
+    refute Gem.source_index.gems.include?(@a1.full_name)
 
     FileUtils.mv File.join(@tempdir, "#{@a1.full_name}.gemspec"), a1_spec
 
     Gem.refresh
 
-    assert Gem.source_index.gems.include?(@a1.full_name)
+    assert_includes Gem.source_index.gems, @a1.full_name
     assert_equal nil, Gem.instance_variable_get(:@searcher)
   end
 
@@ -463,13 +508,30 @@
     Gem::ConfigMap[:EXEEXT] = orig_exe_ext
   end
 
-  def test_self_ruby_version
-    version = RUBY_VERSION.dup
-    version << ".#{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
+  def test_self_ruby_version_1_8_5
+    util_set_RUBY_VERSION '1.8.5'
 
-    assert_equal Gem::Version.new(version), Gem.ruby_version
+    assert_equal Gem::Version.new('1.8.5'), Gem.ruby_version
+  ensure
+    util_restore_RUBY_VERSION
   end
 
+  def test_self_ruby_version_1_8_6p287
+    util_set_RUBY_VERSION '1.8.6', 287
+
+    assert_equal Gem::Version.new('1.8.6.287'), Gem.ruby_version
+  ensure
+    util_restore_RUBY_VERSION
+  end
+
+  def test_self_ruby_version_1_9_2dev_r23493
+    util_set_RUBY_VERSION '1.9.2', -1, 23493
+
+    assert_equal Gem::Version.new('1.9.2.dev.23493'), Gem.ruby_version
+  ensure
+    util_restore_RUBY_VERSION
+  end
+
   def test_self_searcher
     assert_kind_of Gem::GemPathSearcher, Gem.searcher
   end
@@ -478,13 +540,12 @@
     other = File.join @tempdir, 'other'
     path = [@userhome, other].join File::PATH_SEPARATOR
     Gem.send :set_paths, path
-    path = Gem.path
 
-    assert_equal path[0], @userhome
-    assert_equal path[1], other
+    assert_equal [@userhome, other, @gemhome], Gem.path
   end
 
   def test_self_set_paths_nonexistent_home
+    ENV['GEM_HOME'] = @gemhome
     Gem.clear_paths
 
     other = File.join @tempdir, 'other'
@@ -493,7 +554,7 @@
 
     Gem.send :set_paths, other
 
-    refute File.exist?(File.join(other, 'gems'))
+    assert_equal [other, @gemhome], Gem.path
   end
 
   def test_self_source_index
@@ -538,6 +599,28 @@
     end
   end
 
+  def test_self_user_home_user_drive_and_path
+    Gem.clear_paths
+
+    # safe-keep env variables
+    orig_home, orig_user_profile = ENV['HOME'], ENV['USERPROFILE']
+    orig_user_drive, orig_user_path = ENV['HOMEDRIVE'], ENV['HOMEPATH']
+
+    # prepare the environment
+    ENV.delete('HOME')
+    ENV.delete('USERPROFILE')
+    ENV['HOMEDRIVE'] = 'Z:'
+    ENV['HOMEPATH'] = '\\Users\\RubyUser'
+
+    assert_equal "Z:\\Users\\RubyUser", Gem.user_home
+
+  ensure
+    ENV['HOME'] = orig_home
+    ENV['USERPROFILE'] = orig_user_profile
+    ENV['USERDRIVE'] = orig_user_drive
+    ENV['USERPATH'] = orig_user_path
+  end if '1.9' > RUBY_VERSION
+
   def util_ensure_gem_dirs
     Gem.ensure_gem_subdirectories @gemhome
     @additional.each do |dir|
@@ -545,5 +628,46 @@
     end
   end
 
+  def util_exec_gem
+    spec, _ = quick_gem 'a', '4' do |s|
+      s.default_executable = 'exec'
+      s.executables = ['exec', 'abin']
+    end
+
+    @exec_path = File.join spec.full_gem_path, spec.bindir, 'exec'
+    @abin_path = File.join spec.full_gem_path, spec.bindir, 'abin'
+  end
+
+  def util_set_RUBY_VERSION(version, patchlevel = nil, revision = nil)
+    if Gem.instance_variables.include? :@ruby_version or
+       Gem.instance_variables.include? '@ruby_version' then
+      Gem.send :remove_instance_variable, :@ruby_version
+    end
+
+    @RUBY_VERSION    = RUBY_VERSION
+    @RUBY_PATCHLEVEL = RUBY_PATCHLEVEL if defined?(RUBY_PATCHLEVEL)
+    @RUBY_REVISION   = RUBY_REVISION   if defined?(RUBY_REVISION)
+
+    Object.send :remove_const, :RUBY_VERSION
+    Object.send :remove_const, :RUBY_PATCHLEVEL if defined?(RUBY_PATCHLEVEL)
+    Object.send :remove_const, :RUBY_REVISION   if defined?(RUBY_REVISION)
+
+    Object.const_set :RUBY_VERSION,    version
+    Object.const_set :RUBY_PATCHLEVEL, patchlevel if patchlevel
+    Object.const_set :RUBY_REVISION,   revision   if revision
+  end
+
+  def util_restore_RUBY_VERSION
+    Object.send :remove_const, :RUBY_VERSION
+    Object.send :remove_const, :RUBY_PATCHLEVEL if defined?(RUBY_PATCHLEVEL)
+    Object.send :remove_const, :RUBY_REVISION   if defined?(RUBY_REVISION)
+
+    Object.const_set :RUBY_VERSION,    @RUBY_VERSION
+    Object.const_set :RUBY_PATCHLEVEL, @RUBY_PATCHLEVEL if
+      defined?(@RUBY_PATCHLEVEL)
+    Object.const_set :RUBY_REVISION,   @RUBY_REVISION   if
+      defined?(@RUBY_REVISION)
+  end
+
 end
 
Index: test/rubygems/test_gem_commands_query_command.rb
===================================================================
--- test/rubygems/test_gem_commands_query_command.rb	(revision 23658)
+++ test/rubygems/test_gem_commands_query_command.rb	(revision 23659)
@@ -10,7 +10,7 @@
 
     util_setup_fake_fetcher
 
-    @si = util_setup_spec_fetcher @a1, @a2, @pl1
+    @si = util_setup_spec_fetcher @a1, @a2, @pl1, @a3a
 
     @fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] = proc do
       raise Gem::RemoteFetcher::FetchError
@@ -85,6 +85,7 @@
     This is a lot of text.
 
 pl (1)
+    Platform: i386-linux
     Author: A User
     Homepage: http://example.com
 
@@ -95,6 +96,50 @@
     assert_equal '', @ui.error
   end
 
+  def test_execute_details_platform
+    @a1.platform = 'x86-linux'
+
+    @a2.summary = 'This is a lot of text. ' * 4
+    @a2.authors = ['Abraham Lincoln', 'Hirohito']
+    @a2.homepage = 'http://a.example.com/'
+    @a2.rubyforge_project = 'rubygems'
+    @a2.platform = 'universal-darwin'
+
+    @si = util_setup_spec_fetcher @a1, @a2, @pl1
+
+    @cmd.handle_options %w[-r -d]
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    expected = <<-EOF
+
+*** REMOTE GEMS ***
+
+a (2, 1)
+    Platforms:
+        1: x86-linux
+        2: universal-darwin
+    Authors: Abraham Lincoln, Hirohito
+    Rubyforge: http://rubyforge.org/projects/rubygems
+    Homepage: http://a.example.com/
+
+    This is a lot of text. This is a lot of text. This is a lot of text.
+    This is a lot of text.
+
+pl (1)
+    Platform: i386-linux
+    Author: A User
+    Homepage: http://example.com
+
+    this is a summary
+    EOF
+
+    assert_equal expected, @ui.output
+    assert_equal '', @ui.error
+  end
+
   def test_execute_installed
     @cmd.handle_options %w[-n c --installed]
 
@@ -207,11 +252,30 @@
     assert_equal expected, @ui.error
   end
 
+  def test_execute_legacy_prerelease
+    Gem::SpecFetcher.fetcher = nil
+    si = util_setup_source_info_cache @a1, @a2, @pl1
+
+    @fetcher.data["#{@gem_repo}yaml"] = YAML.dump si
+    @fetcher.data["#{@gem_repo}Marshal.#{Gem.marshal_version}"] =
+      si.dump
+
+    @fetcher.data.delete "#{@gem_repo}latest_specs.#{Gem.marshal_version}.gz"
+
+    @cmd.handle_options %w[-r --prerelease]
+
+    e = assert_raises Gem::OperationNotSupportedError do
+      @cmd.execute
+    end
+
+    assert_equal 'Prereleases not supported on legacy repositories', e.message
+  end
+
   def test_execute_local_details
-    @a2.summary = 'This is a lot of text. ' * 4
-    @a2.authors = ['Abraham Lincoln', 'Hirohito']
-    @a2.homepage = 'http://a.example.com/'
-    @a2.rubyforge_project = 'rubygems'
+    @a3a.summary = 'This is a lot of text. ' * 4
+    @a3a.authors = ['Abraham Lincoln', 'Hirohito']
+    @a3a.homepage = 'http://a.example.com/'
+    @a3a.rubyforge_project = 'rubygems'
 
     @cmd.handle_options %w[--local --details]
 
@@ -223,10 +287,11 @@
 
 *** LOCAL GEMS ***
 
-a (2, 1)
+a (3.a, 2, 1)
     Author: A User
     Homepage: http://example.com
-    Installed at (2): #{@gemhome}
+    Installed at (3.a): #{@gemhome}
+                 (2): #{@gemhome}
                  (1): #{@gemhome}
 
     this is a summary
@@ -253,6 +318,7 @@
     this is a summary
 
 pl (1)
+    Platform: i386-linux
     Author: A User
     Homepage: http://example.com
     Installed at: #{@gemhome}
@@ -274,7 +340,7 @@
     end
 
     expected = <<-EOF
-a (2, 1)
+a (3.a, 2, 1)
 a_evil (9)
 b (2)
 c (1.2)
@@ -322,5 +388,45 @@
     assert_equal '', @ui.error
   end
 
+  def test_execute_prerelease
+    @cmd.handle_options %w[-r --prerelease]
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    expected = <<-EOF
+
+*** REMOTE GEMS ***
+
+a (3.a)
+    EOF
+
+    assert_equal expected, @ui.output
+    assert_equal '', @ui.error
+  end
+
+  def test_execute_prerelease_local
+    @cmd.handle_options %w[-l --prerelease]
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    expected = <<-EOF
+
+*** LOCAL GEMS ***
+
+a (3.a, 2, 1)
+a_evil (9)
+b (2)
+c (1.2)
+pl (1)
+    EOF
+
+    assert_equal expected, @ui.output
+    assert_equal "WARNING:  prereleases are always shown locally\n", @ui.error
+  end
+
 end
 
Index: test/rubygems/test_gem_commands_install_command.rb
===================================================================
--- test/rubygems/test_gem_commands_install_command.rb	(revision 23658)
+++ test/rubygems/test_gem_commands_install_command.rb	(revision 23659)
@@ -11,6 +11,52 @@
     @cmd.options[:generate_ri] = false
   end
 
+  def test_execute_exclude_prerelease
+    util_setup_fake_fetcher(:prerelease)
+    util_setup_spec_fetcher @a2, @a2_pre
+
+    @fetcher.data["#{@gem_repo}gems/#{@a2.full_name}.gem"] =
+      read_binary(File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"))
+    @fetcher.data["#{@gem_repo}gems/#{@a2_pre.full_name}.gem"] =
+      read_binary(File.join(@gemhome, 'cache', "#{@a2_pre.full_name}.gem"))
+
+    @cmd.options[:args] = [@a2.name]
+
+    use_ui @ui do
+      e = assert_raises Gem::SystemExitException do
+        @cmd.execute
+      end
+      assert_equal 0, e.exit_code, @ui.error
+    end
+
+    assert_match(/Successfully installed #{@a2.full_name}$/, @ui.output)
+    refute_match(/Successfully installed #{@a2_pre.full_name}$/, @ui.output)
+  end
+
+  def test_execute_explicit_version_includes_prerelease
+    util_setup_fake_fetcher(:prerelease)
+    util_setup_spec_fetcher @a2, @a2_pre
+
+    @fetcher.data["#{@gem_repo}gems/#{@a2.full_name}.gem"] =
+      read_binary(File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"))
+    @fetcher.data["#{@gem_repo}gems/#{@a2_pre.full_name}.gem"] =
+      read_binary(File.join(@gemhome, 'cache', "#{@a2_pre.full_name}.gem"))
+
+    @cmd.handle_options [@a2_pre.name, '--version', @a2_pre.version.to_s]
+    assert @cmd.options[:prerelease]
+    assert @cmd.options[:version].satisfied_by?(@a2_pre.version)
+
+    use_ui @ui do
+      e = assert_raises Gem::SystemExitException do
+        @cmd.execute
+      end
+      assert_equal 0, e.exit_code, @ui.error
+    end
+
+    refute_match(/Successfully installed #{@a2.full_name}$/, @ui.output)
+    assert_match(/Successfully installed #{@a2_pre.full_name}$/, @ui.output)
+  end
+
   def test_execute_include_dependencies
     @cmd.options[:include_dependencies] = true
     @cmd.options[:args] = []
@@ -57,6 +103,34 @@
     assert out.empty?, out.inspect
   end
 
+  def test_no_user_install
+    skip 'skipped on MS Windows (chmod has no effect)' if win_platform?
+
+    util_setup_fake_fetcher
+    @cmd.options[:user_install] = false
+
+    FileUtils.mv File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"),
+                 File.join(@tempdir)
+
+    @cmd.options[:args] = [@a2.name]
+
+    use_ui @ui do
+      orig_dir = Dir.pwd
+      begin
+        File.chmod 0755, @userhome
+        File.chmod 0555, @gemhome
+
+        Dir.chdir @tempdir
+        assert_raises Gem::FilePermissionError do
+          @cmd.execute
+        end
+      ensure
+        Dir.chdir orig_dir
+        File.chmod 0755, @gemhome
+      end
+    end
+  end
+
   def test_execute_local_missing
     util_setup_fake_fetcher
     @cmd.options[:domain] = :local
@@ -100,6 +174,29 @@
                  @ui.error
   end
 
+  def test_execute_prerelease
+    util_setup_fake_fetcher(:prerelease)
+    util_setup_spec_fetcher @a2, @a2_pre
+
+    @fetcher.data["#{@gem_repo}gems/#{@a2.full_name}.gem"] =
+      read_binary(File.join(@gemhome, 'cache', "#{@a2.full_name}.gem"))
+    @fetcher.data["#{@gem_repo}gems/#{@a2_pre.full_name}.gem"] =
+      read_binary(File.join(@gemhome, 'cache', "#{@a2_pre.full_name}.gem"))
+
+    @cmd.options[:prerelease] = true
+    @cmd.options[:args] = [@a2_pre.name]
+
+    use_ui @ui do
+      e = assert_raises Gem::SystemExitException do
+        @cmd.execute
+      end
+      assert_equal 0, e.exit_code, @ui.error
+    end
+
+    refute_match(/Successfully installed #{@a2.full_name}$/, @ui.output)
+    assert_match(/Successfully installed #{@a2_pre.full_name}$/, @ui.output)
+  end
+
   def test_execute_remote
     @cmd.options[:generate_rdoc] = true
     @cmd.options[:generate_ri] = true
@@ -112,17 +209,10 @@
 
     @cmd.options[:args] = [@a2.name]
 
-    err = ""
-    class << err
-      alias write <<
-    end
     use_ui @ui do
       e = assert_raises Gem::SystemExitException do
-        stderr, $stderr = $stderr, err
-        begin
+        capture_io do
           @cmd.execute
-        ensure
-          $stderr = stderr
         end
       end
       assert_equal 0, e.exit_code
@@ -136,7 +226,6 @@
     assert_equal "Installing RDoc documentation for #{@a2.full_name}...",
                  out.shift
     assert out.empty?, out.inspect
-    assert_match /^Updating class cache with \d+ classes/, err
   end
 
   def test_execute_two
Index: test/rubygems/test_gem_format.rb
===================================================================
--- test/rubygems/test_gem_format.rb	(revision 23658)
+++ test/rubygems/test_gem_format.rb	(revision 23659)
@@ -21,7 +21,7 @@
 
     gems = Dir[File.join(@gemhome, 'cache', '*.gem')]
 
-    names = [@a1, @a2, @a_evil9, @b2, @c1_2, @pl1].map do |spec|
+    names = [@a1, @a2, @a3a, @a_evil9, @b2, @c1_2, @pl1].map do |spec|
       spec.original_name
     end
 
Index: test/rubygems/test_gem_ext_ext_conf_builder.rb
===================================================================
--- test/rubygems/test_gem_ext_ext_conf_builder.rb	(revision 23658)
+++ test/rubygems/test_gem_ext_ext_conf_builder.rb	(revision 23659)
@@ -14,6 +14,10 @@
   end
 
   def test_class_build
+    if vc_windows? && !nmake_found?
+      skip("test_class_build skipped - nmake not found")
+    end
+
     File.open File.join(@ext, 'extconf.rb'), 'w' do |extconf|
       extconf.puts "require 'mkmf'\ncreate_makefile 'foo'"
     end
@@ -46,6 +50,10 @@
   end
 
   def test_class_build_extconf_fail
+    if vc_windows? && !nmake_found?
+      skip("test_class_build_extconf_fail skipped - nmake not found")
+    end
+
     File.open File.join(@ext, 'extconf.rb'), 'w' do |extconf|
       extconf.puts "require 'mkmf'"
       extconf.puts "have_library 'nonexistent' or abort 'need libnonexistent'"
@@ -69,6 +77,10 @@
   end
 
   def test_class_make
+    if vc_windows? && !nmake_found?
+      skip("test_class_make skipped - nmake not found")
+    end
+
     output = []
     makefile_path = File.join(@ext, 'Makefile')
     File.open makefile_path, 'w' do |makefile|
@@ -82,14 +94,8 @@
       Gem::Ext::ExtConfBuilder.make @ext, output
     end
 
-    case RUBY_PLATFORM
-    when /mswin/ then
-      assert_equal 'nmake', output[0]
-      assert_equal 'nmake install', output[2]
-    else
-      assert_equal 'make', output[0]
-      assert_equal 'make install', output[2]
-    end
+    assert_equal make_command, output[0]
+    assert_equal "#{make_command} install", output[2]
 
     edited_makefile = <<-EOF
 RUBYARCHDIR = #{@ext}$(target_prefix)
Index: test/rubygems/gem_package_tar_test_case.rb
===================================================================
--- test/rubygems/gem_package_tar_test_case.rb	(revision 23658)
+++ test/rubygems/gem_package_tar_test_case.rb	(revision 23659)
@@ -1,20 +1,6 @@
 require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
 require 'rubygems/package'
 
-class File
-
-  # straight from setup.rb
-  def self.dir?(path)
-    # for corrupted windows stat()
-    File.directory?((path[-1,1] == '/') ? path : path + '/')
-  end
-
-  def self.read_b(name)
-    File.open(name, "rb") { |f| f.read }
-  end
-
-end
-
 class TarTestCase < RubyGemTestCase
 
   def ASCIIZ(str, length)
@@ -49,7 +35,7 @@
       linkname 100
       magic 6
       version 2
-      uname 32
+      uname 32 
       gname 32
       devmajor 8
       devminor 8
@@ -68,7 +54,7 @@
         next
       end
 
-      assert_equal expected[offset, length], actual[offset, length],
+      assert_equal expected[offset, length], actual[offset, length], 
                    "Field #{name} of the tar header differs."
 
       offset += length
Index: test/rubygems/test_gem_installer.rb
===================================================================
--- test/rubygems/test_gem_installer.rb	(revision 23658)
+++ test/rubygems/test_gem_installer.rb	(revision 23659)
@@ -31,7 +31,7 @@
 end
 
 gem 'a', version
-load 'my_exec'
+load Gem.bin_path('a', 'my_exec', version)
     EOF
 
     wrapper = @installer.app_script_text 'my_exec'
@@ -46,7 +46,7 @@
     assert_equal '', @ui.output
     assert_equal '', @ui.error
 
-    assert !File.exist?('gem_make.out')
+    refute File.exist?('gem_make.out')
   end
 
   def test_build_extensions_extconf_bad
@@ -288,12 +288,16 @@
     util_make_exec
 
     Dir.mkdir util_inst_bindir
-    File.chmod 0000, util_inst_bindir
 
-    assert_raises Gem::FilePermissionError do
-      @installer.generate_bin
+    if win_platform?
+      skip('test_generate_bin_script_no_perms skipped on MS Windows')
+    else
+      File.chmod 0000, util_inst_bindir
+
+      assert_raises Gem::FilePermissionError do
+        @installer.generate_bin
+      end
     end
-
   ensure
     File.chmod 0700, util_inst_bindir unless $DEBUG
   end
@@ -373,12 +377,16 @@
     @installer.gem_dir = util_gem_dir
 
     Dir.mkdir util_inst_bindir
-    File.chmod 0000, util_inst_bindir
 
-    assert_raises Gem::FilePermissionError do
-      @installer.generate_bin
+    if win_platform?
+      skip('test_generate_bin_symlink_no_perms skipped on MS Windows')
+    else
+      File.chmod 0000, util_inst_bindir
+
+      assert_raises Gem::FilePermissionError do
+        @installer.generate_bin
+      end
     end
-
   ensure
     File.chmod 0700, util_inst_bindir unless $DEBUG
   end
@@ -535,7 +543,7 @@
     cache_file = File.join @gemhome, 'cache', "#{@spec.full_name}.gem"
 
     Gem.pre_install do |installer|
-      assert !File.exist?(cache_file), 'cache file should not exist yet'
+      refute File.exist?(cache_file), 'cache file should not exist yet'
     end
 
     Gem.post_install do |installer|
@@ -771,7 +779,7 @@
     assert @installer.installation_satisfies_dependency?(dep)
 
     dep = Gem::Dependency.new 'a', '> 2'
-    assert ! @installer.installation_satisfies_dependency?(dep)
+    refute @installer.installation_satisfies_dependency?(dep)
   end
 
   def test_shebang
@@ -818,7 +826,7 @@
     @installer.env_shebang = true
 
     shebang = @installer.shebang 'my_exec'
-    assert_equal "#!/usr/bin/env #{Gem::ConfigMap[:RUBY_INSTALL_NAME]}", shebang
+    assert_equal "#!/usr/bin/env #{Gem::ConfigMap[:ruby_install_name]}", shebang
   end
 
   def test_shebang_nested
@@ -884,7 +892,7 @@
     spec_dir = File.join @gemhome, 'specifications'
     spec_file = File.join spec_dir, "#{@spec.full_name}.gemspec"
     FileUtils.rm spec_file
-    assert !File.exist?(spec_file)
+    refute File.exist?(spec_file)
 
     @installer.spec = @spec
     @installer.gem_home = @gemhome
Index: test/rubygems/test_gem_commands_specification_command.rb
===================================================================
--- test/rubygems/test_gem_commands_specification_command.rb	(revision 23658)
+++ test/rubygems/test_gem_commands_specification_command.rb	(revision 23659)
@@ -70,6 +70,34 @@
     assert_equal '', @ui.error
   end
 
+  def test_execute_field
+    foo = quick_gem 'foo'
+    Gem.source_index.add_spec foo
+
+    @cmd.options[:args] = %w[foo name]
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    assert_equal "--- foo\n\n", @ui.output
+  end
+
+  def test_execute_marshal
+    foo = quick_gem 'foo'
+    Gem.source_index.add_spec foo
+
+    @cmd.options[:args] = %w[foo]
+    @cmd.options[:format] = :marshal
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    assert_equal foo, Marshal.load(@ui.output)
+    assert_equal '', @ui.error
+  end
+
   def test_execute_remote
     foo = quick_gem 'foo'
 
@@ -92,5 +120,21 @@
     assert_match %r|name: foo|, @ui.output
   end
 
+  def test_execute_ruby
+    foo = quick_gem 'foo'
+    Gem.source_index.add_spec foo
+
+    @cmd.options[:args] = %w[foo]
+    @cmd.options[:format] = :ruby
+
+    use_ui @ui do
+      @cmd.execute
+    end
+
+    assert_match %r|Gem::Specification.new|, @ui.output
+    assert_match %r|s.name = %q\{foo\}|, @ui.output
+    assert_equal '', @ui.error
+  end
+
 end
 
Index: test/rubygems/gemutilities.rb
===================================================================
--- test/rubygems/gemutilities.rb	(revision 23658)
+++ test/rubygems/gemutilities.rb	(revision 23659)
@@ -8,24 +8,35 @@
 
 $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
 
-require 'rubygems'
+if RUBY_VERSION > '1.9' then
+  Gem::QuickLoader.load_full_rubygems_library
+else
+  require 'rubygems'
+end
 require 'fileutils'
 begin
+  gem 'minitest', '>= 1.3.1'
   require 'minitest/unit'
-rescue LoadError
-  warn "Install minitest gem"
+rescue Gem::LoadError
+  warn "Install minitest gem >= 1.3.1"
   raise
 end
 require 'tmpdir'
 require 'uri'
 require 'rubygems/package'
 require 'rubygems/test_utilities'
+require 'pp'
 
+begin
+  gem 'rdoc'
+rescue Gem::LoadError
+end
+
+require 'rdoc/rdoc'
+
 require File.join(File.expand_path(File.dirname(__FILE__)), 'mockgemui')
 
 module Gem
-  @ruby = ENV['RUBY']
-
   def self.searcher=(searcher)
     MUTEX.synchronize do @searcher = searcher end
   end
@@ -64,6 +75,8 @@
     @latest_usrcache = File.join(@gemhome, ".gem", "latest_user_cache")
     @userhome = File.join @tempdir, 'userhome'
 
+    Gem.ensure_gem_subdirectories @gemhome
+
     @orig_ENV_HOME = ENV['HOME']
     ENV['HOME'] = @userhome
     Gem.instance_variable_set :@user_home, nil
@@ -85,7 +98,7 @@
     Gem::SpecFetcher.fetcher = nil
 
     @orig_BASERUBY = Gem::ConfigMap[:BASERUBY]
-    Gem::ConfigMap[:BASERUBY] = Gem::ConfigMap[:RUBY_INSTALL_NAME]
+    Gem::ConfigMap[:BASERUBY] = Gem::ConfigMap[:ruby_install_name]
 
     @orig_arch = Gem::ConfigMap[:arch]
 
@@ -160,6 +173,13 @@
     Gem::Installer.new(gem, :wrappers => true).install
   end
 
+  def mu_pp(obj)
+    s = ''
+    s = PP.pp obj, s
+    s = s.force_encoding(Encoding.default_external) if defined? Encoding
+    s.chomp
+  end
+
   def prep_cache_files(lc)
     @usr_si ||= Gem::SourceIndex.new
     @usr_sice ||= Gem::SourceInfoCacheEntry.new @usr_si, 0
@@ -254,10 +274,8 @@
         Gem::Builder.new(spec).build
       end
 
-      cache_dir = File.join(@gemhome, 'cache')
-      FileUtils.mkdir_p cache_dir
       FileUtils.mv "#{spec.full_name}.gem",
-                   File.join(cache_dir, "#{spec.original_name}.gem")
+                   File.join(@gemhome, 'cache', "#{spec.original_name}.gem")
     end
   end
 
@@ -294,14 +312,30 @@
     out.string
   end
 
-  def util_make_gems
+  def util_make_gems(prerelease = false)
+    @a1 = quick_gem 'a', '1' do |s|
+      s.files = %w[lib/code.rb]
+      s.require_paths = %w[lib]
+      s.date = Gem::Specification::TODAY - 86400
+      s.homepage = 'http://a.example.com'
+      s.email = %w[example@e... example2@e...]
+      s.authors = %w[Example Example2]
+      s.description = <<-DESC
+This line is really, really long.  So long, in fact, that it is more than eighty characters long!  The purpose of this line is for testing wrapping behavior because sometimes people don't wrap their text to eighty characters.  Without the wrapping, the text might not look good in the RSS feed.
+
+Also, a list:
+  * An entry that's actually kind of sort
+  * an entry that's really long, which will probably get wrapped funny.  That's ok, somebody wasn't thinking straight when they made it more than eighty characters.
+      DESC
+    end
+
     init = proc do |s|
       s.files = %w[lib/code.rb]
       s.require_paths = %w[lib]
     end
 
-    @a1 = quick_gem('a', '1', &init)
     @a2 = quick_gem('a', '2', &init)
+    @a3a = quick_gem('a', '3.a', &init)
     @a_evil9 = quick_gem('a_evil', '9', &init)
     @b2 = quick_gem('b', '2', &init)
     @c1_2   = quick_gem('c', '1.2',   &init)
@@ -312,13 +346,23 @@
       s.instance_variable_set :@original_platform, 'i386-linux'
     end
 
+    if prerelease
+      @a2_pre = quick_gem('a', '2.a', &init)
+      write_file File.join(*%W[gems #{@a2_pre.original_name} lib code.rb]) do
+      end
+      util_build_gem @a2_pre
+    end
+
     write_file File.join(*%W[gems #{@a1.original_name} lib code.rb]) do end
     write_file File.join(*%W[gems #{@a2.original_name} lib code.rb]) do end
+    write_file File.join(*%W[gems #{@a3a.original_name} lib code.rb]) do end
     write_file File.join(*%W[gems #{@b2.original_name} lib code.rb]) do end
     write_file File.join(*%W[gems #{@c1_2.original_name} lib code.rb]) do end
     write_file File.join(*%W[gems #{@pl1.original_name} lib code.rb]) do end
 
-    [@a1, @a2, @a_evil9, @b2, @c1_2, @pl1].each { |spec| util_build_gem spec }
+    [@a1, @a2, @a3a, @a_evil9, @b2, @c1_2, @pl1].each do |spec|
+      util_build_gem spec
+    end
 
     FileUtils.rm_r File.join(@gemhome, 'gems', @pl1.original_name)
 
@@ -338,26 +382,28 @@
     platform
   end
 
-  def util_setup_fake_fetcher
+  def util_setup_fake_fetcher(prerelease = false)
     require 'zlib'
     require 'socket'
     require 'rubygems/remote_fetcher'
 
     @fetcher = Gem::FakeFetcher.new
 
-    util_make_gems
+    util_make_gems(prerelease)
 
-    @all_gems = [@a1, @a2, @a_evil9, @b2, @c1_2].sort
+    @all_gems = [@a1, @a2, @a3a, @a_evil9, @b2, @c1_2].sort
     @all_gem_names = @all_gems.map { |gem| gem.full_name }
 
-    gem_names = [@a1.full_name, @a2.full_name, @b2.full_name]
+    gem_names = [@a1.full_name, @a2.full_name, @a3a.full_name, @b2.full_name]
     @gem_names = gem_names.sort.join("\n")
 
     @source_index = Gem::SourceIndex.new
     @source_index.add_spec @a1
     @source_index.add_spec @a2
+    @source_index.add_spec @a3a
     @source_index.add_spec @a_evil9
     @source_index.add_spec @c1_2
+    @source_index.add_spec @a2_pre if prerelease
 
     Gem::RemoteFetcher.fetcher = @fetcher
   end
@@ -400,7 +446,13 @@
       spec_fetcher.latest_specs[@uri] << spec_tuple
     end
 
-    si.gems.sort_by { |_,spec| spec }.each do |_, spec|
+    spec_fetcher.prerelease_specs[@uri] = []
+    si.prerelease_specs.sort.each do |spec|
+      spec_tuple = [spec.name, spec.version, spec.original_platform]
+      spec_fetcher.prerelease_specs[@uri] << spec_tuple
+    end
+
+    (si.gems.merge si.prerelease_gems).sort_by { |_,spec| spec }.each do |_, spec|
       path = "#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{spec.original_name}.gemspec.rz"
       data = Marshal.dump spec
       data_deflate = Zlib::Deflate.deflate data
@@ -422,6 +474,42 @@
     Gem.win_platform?
   end
 
+  # Returns whether or not we're on a version of Ruby built with VC++ (or
+  # Borland) versus Cygwin, Mingw, etc.
+  #
+  def self.vc_windows?
+    RUBY_PLATFORM.match('mswin')
+  end
+
+  # Returns whether or not we're on a version of Ruby built with VC++ (or
+  # Borland) versus Cygwin, Mingw, etc.
+  #
+  def vc_windows?
+    RUBY_PLATFORM.match('mswin')
+  end
+
+  # Returns the make command for the current platform. For versions of Ruby
+  # built on MS Windows with VC++ or Borland it will return 'nmake'. On all
+  # other platforms, including Cygwin, it will return 'make'.
+  #
+  def self.make_command
+    vc_windows? ? 'nmake' : 'make'
+  end
+
+  # Returns the make command for the current platform. For versions of Ruby
+  # built on MS Windows with VC++ or Borland it will return 'nmake'. On all
+  # other platforms, including Cygwin, it will return 'make'.
+  #
+  def make_command
+    vc_windows? ? 'nmake' : 'make'
+  end
+
+  # Returns whether or not the nmake command could be found.
+  #
+  def nmake_found?
+    system('nmake /? 1>NUL 2>&1')
+  end
+
   # NOTE Allow tests to use a random (but controlled) port number instead of
   # a hardcoded one. This helps CI tools when running parallels builds on
   # the same builder slave.
Index: test/rubygems/test_gem_package_task.rb
===================================================================
--- test/rubygems/test_gem_package_task.rb	(revision 0)
+++ test/rubygems/test_gem_package_task.rb	(revision 23659)
@@ -0,0 +1,70 @@
+# Copyright (c) 2003, 2004 Jim Weirich, 2009 Eric Hodel
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
+require 'rubygems'
+require 'rubygems/package_task'
+
+class TestGemPackageTask < MiniTest::Unit::TestCase
+
+  def test_gem_package
+    gem = Gem::Specification.new do |g|
+      g.name = "pkgr"
+      g.version = "1.2.3"
+      g.files = Rake::FileList["x"].resolve
+    end
+    pkg = Gem::PackageTask.new(gem)  do |p|
+      p.package_files << "y"
+    end
+    assert_equal ["x", "y"], pkg.package_files
+    assert_equal "pkgr-1.2.3.gem", pkg.gem_file
+  end
+
+  def test_gem_package_with_current_platform
+    gem = Gem::Specification.new do |g|
+      g.name = "pkgr"
+      g.version = "1.2.3"
+      g.files = Rake::FileList["x"].resolve
+      g.platform = Gem::Platform::CURRENT
+    end
+    pkg = Gem::PackageTask.new(gem)  do |p|
+      p.package_files << "y"
+    end
+    assert_equal ["x", "y"], pkg.package_files
+    assert_match(/^pkgr-1\.2\.3-(\S+)\.gem$/, pkg.gem_file)
+  end
+
+  def test_gem_package_with_ruby_platform
+    gem = Gem::Specification.new do |g|
+      g.name = "pkgr"
+      g.version = "1.2.3"
+      g.files = Rake::FileList["x"].resolve
+      g.platform = Gem::Platform::RUBY
+    end
+    pkg = Gem::PackageTask.new(gem)  do |p|
+      p.package_files << "y"
+    end
+    assert_equal ["x", "y"], pkg.package_files
+    assert_equal "pkgr-1.2.3.gem", pkg.gem_file
+  end
+
+end
+
Index: test/rubygems/test_gem_command.rb
===================================================================
--- test/rubygems/test_gem_command.rb	(revision 23658)
+++ test/rubygems/test_gem_command.rb	(revision 23659)
@@ -55,16 +55,6 @@
     assert_equal [], h
   end
 
-  def test_add_option_overlapping_common_and_local_options
-    @cmd.add_option('-x', '--zip', 'BAD!') do end
-    @cmd.add_option('-z', '--exe', 'BAD!') do end
-    @cmd.add_option('-x', '--exe', 'BAD!') do end
-
-    assert_match %r|-x, --exe|, @cmd.parser.to_s
-    refute_match %r|-z, --exe|, @cmd.parser.to_s
-    refute_match %r|-x, --zip|, @cmd.parser.to_s
-  end
-
   def test_basic_accessors
     assert_equal "doit", @cmd.command
     assert_equal "gem doit", @cmd.program_name
@@ -182,9 +172,9 @@
     assert @cmd.handles?(['--help', 'command'])
     assert @cmd.handles?(['-f', 'filename'])
     assert @cmd.handles?(['--file=filename'])
-    assert ! @cmd.handles?(['-z'])
-    assert ! @cmd.handles?(['-f'])
-    assert ! @cmd.handles?(['--toothpaste'])
+    refute @cmd.handles?(['-z'])
+    refute @cmd.handles?(['-f'])
+    refute @cmd.handles?(['--toothpaste'])
 
     args = ['-h', 'command']
     @cmd.handles?(args)
Index: test/rubygems/test_gem_package_tar_input.rb
===================================================================
--- test/rubygems/test_gem_package_tar_input.rb	(revision 23658)
+++ test/rubygems/test_gem_package_tar_input.rb	(revision 23659)
@@ -48,7 +48,7 @@
       meta = @spec.to_yaml
 
       f.write tar_file_header("metadata", "", 0644, meta.size)
-      f.write meta + "\0" * (1024 - meta.size)
+      f.write meta + "\0" * (1024 - meta.size) 
       f.write "\0" * 1024
     end
 
@@ -92,8 +92,8 @@
           tar_input.extract_entry @tempdir, entry
           name = File.join @tempdir, entry.header.name
 
-          if entry.directory?
-            assert File.dir?(name)
+          if entry.directory? then
+            assert File.directory?(name)
           else
             assert File.file?(name)
             assert_equal @entry_sizes[i], File.stat(name).size
@@ -111,7 +111,7 @@
 
     @entry_files.each_with_index do |x, i|
       assert File.file?(x)
-      assert_equal @entry_contents[i], File.read_b(x)
+      assert_equal @entry_contents[i], Gem.read_binary(x)
     end
   end
 
Index: test/rubygems/test_gem_package_tar_output.rb
===================================================================
--- test/rubygems/test_gem_package_tar_output.rb	(revision 23658)
+++ test/rubygems/test_gem_package_tar_output.rb	(revision 23659)
@@ -49,7 +49,7 @@
     gz = Zlib::GzipReader.new StringIO.new(data)
     assert_equal "This is some metadata\n", gz.read
 
-    assert files.empty?
+    assert_empty files
   ensure
     gz.close if gz
   end
@@ -82,7 +82,7 @@
       name, data = files.shift
       assert_equal 'metadata.gz.sig', name
 
-      assert files.empty?
+      assert_empty files
     end
   end
 
Index: test/rubygems/test_gem_platform.rb
===================================================================
--- test/rubygems/test_gem_platform.rb	(revision 23658)
+++ test/rubygems/test_gem_platform.rb	(revision 23659)
@@ -133,6 +133,12 @@
     assert_equal '1', platform.version
   end
 
+  def test_empty
+    platform = Gem::Platform.new 'cpu-other_platform1'
+    assert_respond_to platform, :empty?
+    assert_equal false, platform.empty?
+  end
+
   def test_to_s
     if win_platform? then
       assert_equal 'x86-mswin32-60', Gem::Platform.local.to_s
@@ -155,8 +161,8 @@
     other = Gem::Platform.new %w[cpu other_platform 1]
 
     assert(my === my)
-    assert !(other === my)
-    assert !(my === other)
+    refute(other === my)
+    refute(my === other)
   end
 
   def test_equals3_cpu
@@ -167,10 +173,10 @@
     util_set_arch 'powerpc-darwin8'
     assert((ppc_darwin8 === Gem::Platform.local), 'powerpc =~ universal')
     assert((uni_darwin8 === Gem::Platform.local), 'powerpc =~ universal')
-    assert !(x86_darwin8 === Gem::Platform.local), 'powerpc =~ universal'
+    refute((x86_darwin8 === Gem::Platform.local), 'powerpc =~ universal')
 
     util_set_arch 'i686-darwin8'
-    assert !(ppc_darwin8 === Gem::Platform.local), 'powerpc =~ universal'
+    refute((ppc_darwin8 === Gem::Platform.local), 'powerpc =~ universal')
     assert((uni_darwin8 === Gem::Platform.local), 'x86 =~ universal')
     assert((x86_darwin8 === Gem::Platform.local), 'powerpc =~ universal')
 
@@ -191,8 +197,8 @@
     assert((x86_darwin  === Gem::Platform.local), 'x86_darwin === x86_darwin8')
     assert((x86_darwin8 === Gem::Platform.local), 'x86_darwin8 === x86_darwin8')
 
-    assert !(x86_darwin7 === Gem::Platform.local), 'x86_darwin7 === x86_darwin8'
-    assert !(x86_darwin9 === Gem::Platform.local), 'x86_darwin9 === x86_darwin8'
+    refute((x86_darwin7 === Gem::Platform.local), 'x86_darwin7 === x86_darwin8')
+    refute((x86_darwin9 === Gem::Platform.local), 'x86_darwin9 === x86_darwin8')
   end
 
   def test_equals_tilde
Index: test/rubygems/test_gem_commands_server_command.rb
===================================================================
--- test/rubygems/test_gem_commands_server_command.rb	(revision 23658)
+++ test/rubygems/test_gem_commands_server_command.rb	(revision 23659)
@@ -22,5 +22,31 @@
     assert_equal File.expand_path('/nonexistent'), @cmd.options[:gemdir]
     assert_equal 9999, @cmd.options[:port]
   end
+
+  def test_handle_options_port
+    @cmd.send :handle_options, %w[-p 0]
+    assert_equal 0, @cmd.options[:port]
+
+    @cmd.send :handle_options, %w[-p 65535]
+    assert_equal 65535, @cmd.options[:port]
+
+    @cmd.send :handle_options, %w[-p http]
+    assert_equal 80, @cmd.options[:port]
+
+    e = assert_raises OptionParser::InvalidArgument do
+      @cmd.send :handle_options, %w[-p nonexistent]
+    end
+
+    assert_equal 'invalid argument: -p nonexistent: no such named service',
+                 e.message
+
+    e = assert_raises OptionParser::InvalidArgument do
+      @cmd.send :handle_options, %w[-p 65536]
+    end
+
+    assert_equal 'invalid argument: -p 65536: not a port number',
+                 e.message
+  end
+
 end
 
Index: test/rubygems/test_gem_source_index.rb
===================================================================
--- test/rubygems/test_gem_source_index.rb	(revision 23658)
+++ test/rubygems/test_gem_source_index.rb	(revision 23659)
@@ -208,269 +208,6 @@
     assert_equal @fetcher, @source_index.fetcher
   end
 
-  def test_fetch_bulk_index_compressed
-    util_setup_bulk_fetch true
-
-    use_ui @ui do
-      fetched_index = @source_index.fetch_bulk_index @uri
-      assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
-                    @c1_2.full_name].sort,
-                   fetched_index.gems.map { |n,s| n }.sort
-    end
-
-    paths = @fetcher.paths
-
-    assert_equal "#{@gem_repo}Marshal.#{@marshal_version}.Z", paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  end
-
-  def test_fetch_bulk_index_error
-    @fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}.Z"] = proc { raise SocketError }
-    @fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}"] = proc { raise SocketError }
-    @fetcher.data["#{@gem_repo}yaml.Z"] = proc { raise SocketError }
-    @fetcher.data["#{@gem_repo}yaml"] = proc { raise SocketError }
-
-    e = assert_raises Gem::RemoteSourceException do
-      use_ui @ui do
-        @source_index.fetch_bulk_index @uri
-      end
-    end
-
-    paths = @fetcher.paths
-
-    assert_equal "#{@gem_repo}Marshal.#{@marshal_version}.Z", paths.shift
-    assert_equal "#{@gem_repo}Marshal.#{@marshal_version}", paths.shift
-    assert_equal "#{@gem_repo}yaml.Z", paths.shift
-    assert_equal "#{@gem_repo}yaml", paths.shift
-
-    assert paths.empty?, paths.join(', ')
-
-    assert_equal 'Error fetching remote gem cache: SocketError',
-                 e.message
-  end
-
-  def test_fetch_bulk_index_fallback
-    @fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}.Z"] =
-      proc { raise SocketError }
-    @fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}"] =
-      proc { raise SocketError }
-    @fetcher.data["#{@gem_repo}yaml.Z"] = proc { raise SocketError }
-    @fetcher.data["#{@gem_repo}yaml"] = @source_index.to_yaml
-
-    use_ui @ui do
-      fetched_index = @source_index.fetch_bulk_index @uri
-      assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
-                    @c1_2.full_name].sort,
-                   fetched_index.gems.map { |n,s| n }.sort
-    end
-
-    paths = @fetcher.paths
-
-    assert_equal "#{@gem_repo}Marshal.#{@marshal_version}.Z", paths.shift
-    assert_equal "#{@gem_repo}Marshal.#{@marshal_version}", paths.shift
-    assert_equal "#{@gem_repo}yaml.Z", paths.shift
-    assert_equal "#{@gem_repo}yaml", paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  end
-
-  def test_fetch_bulk_index_marshal_mismatch
-    marshal = @source_index.dump
-    marshal[0] = (Marshal::MAJOR_VERSION - 1).chr
-
-    @fetcher.data["#{@gem_repo}Marshal.#{@marshal_version}"] = marshal
-    @fetcher.data["#{@gem_repo}yaml"] = @source_index.to_yaml
-
-    use_ui @ui do
-      fetched_index = @source_index.fetch_bulk_index @uri
-      assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
-                    @c1_2.full_name].sort,
-                   fetched_index.gems.map { |n,s| n }.sort
-    end
-
-    paths = @fetcher.paths
-
-    assert_equal "#{@gem_repo}Marshal.#{@marshal_version}.Z", paths.shift
-    assert_equal "#{@gem_repo}Marshal.#{@marshal_version}", paths.shift
-    assert_equal "#{@gem_repo}yaml.Z", paths.shift
-    assert_equal "#{@gem_repo}yaml", paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  end
-
-  def test_fetch_bulk_index_uncompressed
-    util_setup_bulk_fetch false
-    use_ui @ui do
-      fetched_index = @source_index.fetch_bulk_index @uri
-      assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
-                    @c1_2.full_name].sort,
-                   fetched_index.gems.map { |n,s| n }.sort
-    end
-
-    paths = @fetcher.paths
-
-    assert_equal "#{@gem_repo}Marshal.#{@marshal_version}.Z", paths.shift
-    assert_equal "#{@gem_repo}Marshal.#{@marshal_version}", paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  end
-
-  def test_fetch_quick_index
-    index = util_zip @gem_names
-    latest_index = util_zip [@a2.full_name, @b2.full_name].join("\n")
-
-    @fetcher.data["#{@gem_repo}quick/index.rz"] = index
-    @fetcher.data["#{@gem_repo}quick/latest_index.rz"] = latest_index
-
-    quick_index = @source_index.fetch_quick_index @uri, false
-    assert_equal [@a2.full_name, @b2.full_name].sort,
-                 quick_index.sort
-
-    paths = @fetcher.paths
-
-    assert_equal "#{@gem_repo}quick/latest_index.rz", paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  end
-
-  def test_fetch_quick_index_all
-    index = util_zip @gem_names
-    latest_index = util_zip [@a2.full_name, @b2.full_name].join("\n")
-
-    @fetcher.data["#{@gem_repo}quick/index.rz"] = index
-    @fetcher.data["#{@gem_repo}quick/latest_index.rz"] = latest_index
-
-    quick_index = @source_index.fetch_quick_index @uri, true
-    assert_equal [@a1.full_name, @a2.full_name, @b2.full_name].sort,
-                 quick_index.sort
-
-    paths = @fetcher.paths
-
-    assert_equal "#{@gem_repo}quick/index.rz", paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  end
-
-  def test_fetch_quick_index_error
-    @fetcher.data["#{@gem_repo}quick/index.rz"] =
-      proc { raise Exception }
-
-    e = assert_raises Gem::OperationNotSupportedError do
-      @source_index.fetch_quick_index @uri, true
-    end
-
-    assert_equal 'No quick index found: Exception', e.message
-
-    paths = @fetcher.paths
-
-    assert_equal "#{@gem_repo}quick/index.rz", paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  end
-
-  def test_fetch_quick_index_fallback
-    index = util_zip @gem_names
-
-    @fetcher.data["#{@gem_repo}quick/index.rz"] = index
-
-    quick_index = @source_index.fetch_quick_index @uri, false
-    assert_equal @gem_names.split, quick_index.sort
-
-    paths = @fetcher.paths
-
-    assert_equal "#{@gem_repo}quick/latest_index.rz", paths.shift
-    assert_equal "#{@gem_repo}quick/index.rz", paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  end
-
-  def test_fetch_quick_index_subdir
-    latest_index = util_zip [@a2.full_name, @b2.full_name].join("\n")
-    repo = URI.parse "#{@gem_repo}~nobody/mirror/"
-
-    @fetcher.data["#{repo}quick/latest_index.rz"] = latest_index
-
-    quick_index = @source_index.fetch_quick_index repo, false
-    assert_equal [@a2.full_name, @b2.full_name].sort,
-                 quick_index.sort
-
-    paths = @fetcher.paths
-
-    assert_equal "#{repo}quick/latest_index.rz", paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  end
-
-  def test_fetch_single_spec
-    a1_spec_url = "#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{@a1.full_name}.gemspec.rz"
-    @fetcher.data[a1_spec_url] = util_zip Marshal.dump(@a1)
-
-    spec = @source_index.send :fetch_single_spec, URI.parse(@gem_repo),
-                              @a1.full_name
-
-    assert_equal @a1.full_name, spec.full_name
-
-    paths = @fetcher.paths
-
-    assert_equal a1_spec_url, paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  end
-
-  def test_fetch_single_spec_subdir
-    repo = URI.parse "#{@gem_repo}~nobody/mirror/"
-
-    a1_spec_url = "#{repo}quick/Marshal.#{Gem.marshal_version}/#{@a1.full_name}.gemspec.rz"
-    @fetcher.data[a1_spec_url] = util_zip Marshal.dump(@a1)
-
-    spec = @source_index.send :fetch_single_spec, repo, @a1.full_name
-
-    assert_equal @a1.full_name, spec.full_name
-
-    paths = @fetcher.paths
-
-    assert_equal a1_spec_url, paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  end
-
-  def test_fetch_single_spec_yaml
-    a1_spec_url = "#{@gem_repo}quick/#{@a1.full_name}.gemspec.rz"
-    @fetcher.data[a1_spec_url] = util_zip @a1.to_yaml
-
-    repo = URI.parse @gem_repo
-
-    spec = @source_index.send :fetch_single_spec, repo, @a1.full_name
-
-    assert_equal @a1.full_name, spec.full_name
-
-    paths = @fetcher.paths
-
-    assert_equal "#{@gem_repo}quick/Marshal.#{Gem.marshal_version}/#{@a1.full_name}.gemspec.rz", paths.shift
-    assert_equal a1_spec_url, paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  end
-
-  def test_fetch_single_spec_yaml_subdir
-    repo = URI.parse "#{@gem_repo}~nobody/mirror/"
-
-    a1_spec_url = "#{repo}quick/#{@a1.full_name}.gemspec.rz"
-    @fetcher.data[a1_spec_url] = util_zip @a1.to_yaml
-
-    spec = @source_index.send :fetch_single_spec, repo, @a1.full_name
-
-    assert_equal @a1.full_name, spec.full_name
-
-    paths = @fetcher.paths
-
-    assert_equal "#{repo}quick/Marshal.#{Gem.marshal_version}/#{@a1.full_name}.gemspec.rz", paths.shift
-    assert_equal a1_spec_url, paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  end
-
   def test_find_missing
     missing = @source_index.find_missing [@b2.full_name]
     assert_equal [@b2.full_name], missing
@@ -485,7 +222,7 @@
   end
 
   def test_find_name
-    assert_equal [@a1, @a2], @source_index.find_name('a')
+    assert_equal [@a1, @a2, @a3a], @source_index.find_name('a')
     assert_equal [@a2], @source_index.find_name('a', '= 2')
     assert_equal [], @source_index.find_name('bogusstring')
     assert_equal [], @source_index.find_name('a', '= 3')
@@ -593,14 +330,25 @@
     assert_equal [updated_platform.name], @source_index.outdated
   end
 
+  def test_prerelease_specs_kept_in_right_place
+    gem_a1_alpha = quick_gem 'abba', '1.a'
+    @source_index.add_spec gem_a1_alpha
+
+    refute @source_index.latest_specs.include?(gem_a1_alpha)
+    assert_nil @source_index.specification(gem_a1_alpha.full_name)
+    assert @source_index.prerelease_specs.include?(gem_a1_alpha)
+
+    # TODO: don't think this tests writing prerelease index to disk
+  end
+
   def test_refresh_bang
-    a1_spec = File.join @gemhome, "specifications", "#{@a1.full_name}.gemspec"
+    a1_spec = File.join @gemhome, "specifications", "#{@a1.full_name}.gemspec" 
 
     FileUtils.mv a1_spec, @tempdir
 
     source_index = Gem::SourceIndex.from_installed_gems
 
-    assert !source_index.gems.include?(@a1.full_name)
+    refute source_index.gems.include?(@a1.full_name)
 
     FileUtils.mv File.join(@tempdir, "#{@a1.full_name}.gemspec"), a1_spec
 
@@ -640,13 +388,28 @@
     assert_equal gems, @source_index.gems.map { |n,s| n }.sort
   end
 
+  def test_remove_spec
+    deleted = @source_index.remove_spec 'a-1'
+
+    assert_equal %w[a-2 a-3.a a_evil-9 c-1.2],
+                 @source_index.all_gems.values.map { |s| s.full_name }.sort
+
+    deleted = @source_index.remove_spec 'a-3.a'
+
+    assert_equal %w[a-2 a_evil-9 c-1.2],
+                 @source_index.all_gems.values.map { |s| s.full_name }.sort
+  end
+
   def test_search
     requirement = Gem::Requirement.create '= 9'
     with_version = Gem::Dependency.new(/^a/, requirement)
     assert_equal [@a_evil9], @source_index.search(with_version)
 
     with_default = Gem::Dependency.new(/^a/, Gem::Requirement.default)
-    assert_equal [@a1, @a2, @a_evil9], @source_index.search(with_default)
+    assert_equal [@a1, @a2, @a3a, @a_evil9], @source_index.search(with_default)
+
+    c1_1_dep = Gem::Dependency.new 'c', '~> 1.1'
+    assert_equal [@c1_2], @source_index.search(c1_1_dep)
   end
 
   def test_search_platform
@@ -692,186 +455,6 @@
     assert_equal 'some text', @source_index.unzip(input)
   end
 
-  def test_update_bulk
-    util_setup_bulk_fetch true
-
-    @source_index.gems.replace({})
-    assert_equal [], @source_index.gems.keys.sort
-
-    use_ui @ui do
-      @source_index.update @uri, true
-
-      assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
-                    @c1_2.full_name],
-                   @source_index.gems.keys.sort
-    end
-
-    paths = @fetcher.paths
-
-    assert_equal "#{@gem_repo}quick/index.rz", paths.shift
-    assert_equal "#{@gem_repo}Marshal.#{@marshal_version}.Z", paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  end
-
-  def test_update_incremental
-    old_gem_conf = Gem.configuration
-    Gem.configuration = Gem::ConfigFile.new([])
-
-    latest_names = [@a2, @a_evil9, @b2, @c1_2].map { |s| s.full_name }
-    latest_index = util_zip latest_names.join("\n")
-    @fetcher.data["#{@gem_repo}quick/latest_index.rz"] = latest_index
-
-    marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
-                            "#{@b2.full_name}.gemspec.rz"
-    @fetcher.data[marshal_uri] = util_zip Marshal.dump(@b2)
-
-    use_ui @ui do
-      @source_index.update @uri, false
-
-      assert_equal latest_names, @source_index.gems.keys.sort
-    end
-
-    paths = @fetcher.paths
-    assert_equal "#{@gem_repo}quick/latest_index.rz", paths.shift
-    assert_equal marshal_uri, paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  ensure
-    Gem.configuration = old_gem_conf
-  end
-
-  def test_update_incremental_all
-    old_gem_conf = Gem.configuration
-    Gem.configuration = Gem::ConfigFile.new([])
-
-    quick_index = util_zip @all_gem_names.join("\n")
-    @fetcher.data["#{@gem_repo}quick/index.rz"] = quick_index
-
-    marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
-                            "#{@b2.full_name}.gemspec.rz"
-    @fetcher.data[marshal_uri] = util_zip Marshal.dump(@b2)
-
-    use_ui @ui do
-      @source_index.update @uri, true
-
-      assert_equal @all_gem_names, @source_index.gems.keys.sort
-    end
-
-    paths = @fetcher.paths
-    assert_equal "#{@gem_repo}quick/index.rz", paths.shift
-    assert_equal marshal_uri, paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  ensure
-    Gem.configuration = old_gem_conf
-  end
-
-  def test_update_incremental_fallback
-    old_gem_conf = Gem.configuration
-    Gem.configuration = Gem::ConfigFile.new([])
-
-    quick_index = util_zip @all_gem_names.join("\n")
-    @fetcher.data["#{@gem_repo}quick/index.rz"] = quick_index
-
-    marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
-                            "#{@b2.full_name}.gemspec.rz"
-
-    yaml_uri = "#{@gem_repo}quick/#{@b2.full_name}.gemspec.rz"
-    @fetcher.data[yaml_uri] = util_zip @b2.to_yaml
-
-    use_ui @ui do
-      @source_index.update @uri, true
-
-      assert_equal @all_gem_names, @source_index.gems.keys.sort
-    end
-
-    paths = @fetcher.paths
-    assert_equal "#{@gem_repo}quick/index.rz", paths.shift
-    assert_equal marshal_uri, paths.shift
-    assert_equal yaml_uri, paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  ensure
-    Gem.configuration = old_gem_conf
-  end
-
-  def test_update_incremental_marshal_mismatch
-    old_gem_conf = Gem.configuration
-    Gem.configuration = Gem::ConfigFile.new([])
-
-    quick_index = util_zip @all_gem_names.join("\n")
-    @fetcher.data["#{@gem_repo}quick/index.rz"] = quick_index
-
-    marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
-                            "#{@b2.full_name}.gemspec.rz"
-    marshal_data = Marshal.dump(@b2)
-    marshal_data[0] = (Marshal::MAJOR_VERSION - 1).chr
-    @fetcher.data[marshal_uri] = util_zip marshal_data
-
-    yaml_uri = "#{@gem_repo}quick/#{@b2.full_name}.gemspec.rz"
-    @fetcher.data[yaml_uri] = util_zip @b2.to_yaml
-
-    use_ui @ui do
-      @source_index.update @uri, true
-
-      assert_equal @all_gem_names, @source_index.gems.keys.sort
-    end
-
-    paths = @fetcher.paths
-    assert_equal "#{@gem_repo}quick/index.rz", paths.shift
-    assert_equal marshal_uri, paths.shift
-    assert_equal yaml_uri, paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  ensure
-    Gem.configuration = old_gem_conf
-  end
-
-  def test_update_subdir
-    @gem_repo = @gem_repo + 'subdir/'
-
-    util_setup_bulk_fetch true
-
-    @source_index.gems.replace({})
-    assert_equal [], @source_index.gems.keys.sort
-
-    uri = @uri.to_s + 'subdir/'
-
-    use_ui @ui do
-      @source_index.update uri, true
-
-      assert_equal [@a1.full_name, @a2.full_name, @a_evil9.full_name,
-                    @c1_2.full_name],
-                   @source_index.gems.keys.sort
-    end
-
-    paths = @fetcher.paths
-
-    assert_equal "#{@gem_repo}quick/index.rz", paths.shift
-    assert_equal "#{@gem_repo}Marshal.#{@marshal_version}.Z", paths.shift
-
-    assert paths.empty?, paths.join(', ')
-  end
-
-  def test_update_with_missing
-    marshal_uri = File.join @gem_repo, "quick", "Marshal.#{@marshal_version}",
-                            "#{@c1_2.full_name}.gemspec.rz"
-    dumped = Marshal.dump @c1_2
-    @fetcher.data[marshal_uri] = util_zip(dumped)
-
-    use_ui @ui do
-      @source_index.update_with_missing @uri, [@c1_2.full_name]
-    end
-
-    spec = @source_index.specification(@c1_2.full_name)
-    # We don't care about the equality of undumped attributes
-    @c1_2.files = spec.files
-    @c1_2.loaded_from = spec.loaded_from
-
-    assert_equal @c1_2, spec
-  end
-
   def util_setup_bulk_fetch(compressed)
     source_index = @source_index.dump
 
Index: test/rubygems/mockgemui.rb
===================================================================
--- test/rubygems/mockgemui.rb	(revision 23658)
+++ test/rubygems/mockgemui.rb	(revision 23659)
@@ -56,7 +56,8 @@
   def terminate_interaction(status=0)
     @terminated = true
 
-    raise TermError
+    raise TermError unless status == 0
+    raise Gem::SystemExitException, status
   end
 
 end
Index: test/rubygems/simple_gem.rb
===================================================================
--- test/rubygems/simple_gem.rb	(revision 23658)
+++ test/rubygems/simple_gem.rb	(revision 23659)
@@ -5,63 +5,59 @@
 #++
 
     SIMPLE_GEM = <<-GEMDATA
-        MD5SUM = "954df67d9475aa2f4fbba20aa33649c8"
+        MD5SUM = "e3701f9db765a2358aef94c40ded71c8"
         if $0 == __FILE__
           require 'optparse'
-
+        
           options = {}
           ARGV.options do |opts|
             opts.on_tail("--help", "show this message") {puts opts; exit}
-            opts.on('--dir=DIRNAME', "Installation directory for the Gem") {|x|
-              options[:directory] = x
-            }
-            opts.on('--force', "Force Gem to intall, bypassing dependency checks") {|x|
-              options[:force] = x
-            }
-            opts.on('--gen-rdoc', "Generate RDoc documentation for the Gem") {|x|
-              options[:gen_rdoc] = x
-            }
+            opts.on('--dir=DIRNAME', "Installation directory for the Gem") {|options[:directory]|}
+            opts.on('--force', "Force Gem to intall, bypassing dependency checks") {|options[:force]|}
+            opts.on('--gen-rdoc', "Generate RDoc documentation for the Gem") {|options[:gen_rdoc]|}
             opts.parse!
           end
 
-          require 'rubygems/installer'
-
-          gem = Gem::Installer.new(__FILE__, options).install
+          require 'rubygems'
+          @directory = options[:directory] || Gem.dir  
+          @force = options[:force]
+  
+          gem = Gem::Installer.new(__FILE__).install(@force, @directory)      
           if options[:gen_rdoc]
             Gem::DocManager.new(gem).generate_rdoc
           end
-        end
+end
 
 __END__
---- !ruby/object:Gem::Specification
+--- !ruby/object:Gem::Specification 
 rubygems_version: "1.0"
 name: testing
-version: !ruby/object:Gem::Version
+version: !ruby/object:Gem::Version 
   version: 1.2.3
 date: 2004-03-18 22:01:52.859121 -05:00
-platform:
+platform: 
 summary: This exercise the gem testing stuff.
-require_paths:
+require_paths: 
   - lib
-files:
+files: 
   - lib/foo.rb
   - lib/test
   - lib/test.rb
   - lib/test/wow.rb
 autorequire: test
 test_suite_file: foo
-requirements:
+requirements: 
   - a computer processor
----
--
+--- 
+- 
   size: 109
   mode: 420
   path: lib/foo.rb
--
+- 
   size: 0
   mode: 420
   path: lib/test.rb
--
+- 
   size: 15
   mode: 420
   path: lib/test/wow.rb
Index: test/rubygems/test_gem_indexer.rb
===================================================================
--- test/rubygems/test_gem_indexer.rb	(revision 23658)
+++ test/rubygems/test_gem_indexer.rb	(revision 23659)
@@ -19,21 +19,45 @@
 
     util_make_gems
 
-    @d2_0 = quick_gem 'd', '2.0'
+    @d2_0 = quick_gem 'd', '2.0' do |s|
+      s.date = Gem::Specification::TODAY - 86400 * 3
+    end
     util_build_gem @d2_0
 
+    @d2_0_a = quick_gem 'd', '2.0.a'
+    util_build_gem @d2_0_a
+
+    @d2_0_b = quick_gem 'd', '2.0.b'
+    util_build_gem @d2_0_b
+
     gems = File.join(@tempdir, 'gems')
     FileUtils.mkdir_p gems
     cache_gems = File.join @gemhome, 'cache', '*.gem'
     FileUtils.mv Dir[cache_gems], gems
 
-    @indexer = Gem::Indexer.new @tempdir
+    @indexer = Gem::Indexer.new @tempdir, :rss_title => 'ExampleForge gems',
+                                :rss_host => 'example.com',
+                                :rss_gems_host => 'gems.example.com'
   end
 
   def test_initialize
     assert_equal @tempdir, @indexer.dest_directory
     assert_equal File.join(Dir.tmpdir, "gem_generate_index_#{$$}"),
                  @indexer.directory
+
+    indexer = Gem::Indexer.new @tempdir
+    assert indexer.build_legacy
+    assert indexer.build_modern
+
+    indexer = Gem::Indexer.new @tempdir, :build_legacy => false,
+                               :build_modern => true
+    refute indexer.build_legacy
+    assert indexer.build_modern
+
+    indexer = Gem::Indexer.new @tempdir, :build_legacy => true,
+                               :build_modern => false
+    assert indexer.build_legacy
+    refute indexer.build_modern
   end
 
   def test_build_indicies
@@ -137,32 +161,322 @@
 
     assert_indexed @tempdir, "latest_specs.#{@marshal_version}"
     assert_indexed @tempdir, "latest_specs.#{@marshal_version}.gz"
+
+    expected = <<-EOF
+<?xml version="1.0"?>
+<rss version="2.0">
+  <channel>
+    <title>ExampleForge gems</title>
+    <link>http://example.com</link>
+    <description>Recently released gems from http://example.com</description>
+    <generator>RubyGems v#{Gem::RubyGemsVersion}</generator>
+    <docs>http://cyber.law.harvard.edu/rss/rss.html</docs>
+    <item>
+      <title>a-2</title>
+      <description>
+&lt;pre&gt;This is a test description&lt;/pre&gt;
+      </description>
+      <author>example@e... (A User)</author>
+      <guid>a-2</guid>
+      <enclosure url="http://gems.example.com/gems/a-2.gem"
+                 length="3072" type="application/octet-stream" />
+      <pubDate>#{Gem::Specification::TODAY.rfc2822}</pubDate>
+      <link>http://example.com</link>
+    </item>
+    <item>
+      <title>a_evil-9</title>
+      <description>
+&lt;pre&gt;This is a test description&lt;/pre&gt;
+      </description>
+      <author>example@e... (A User)</author>
+      <guid>a_evil-9</guid>
+      <enclosure url="http://gems.example.com/gems/a_evil-9.gem"
+                 length="3072" type="application/octet-stream" />
+      <pubDate>#{Gem::Specification::TODAY.rfc2822}</pubDate>
+      <link>http://example.com</link>
+    </item>
+    <item>
+      <title>b-2</title>
+      <description>
+&lt;pre&gt;This is a test description&lt;/pre&gt;
+      </description>
+      <author>example@e... (A User)</author>
+      <guid>b-2</guid>
+      <enclosure url="http://gems.example.com/gems/b-2.gem"
+                 length="3072" type="application/octet-stream" />
+      <pubDate>#{Gem::Specification::TODAY.rfc2822}</pubDate>
+      <link>http://example.com</link>
+    </item>
+    <item>
+      <title>c-1.2</title>
+      <description>
+&lt;pre&gt;This is a test description&lt;/pre&gt;
+      </description>
+      <author>example@e... (A User)</author>
+      <guid>c-1.2</guid>
+      <enclosure url="http://gems.example.com/gems/c-1.2.gem"
+                 length="3072" type="application/octet-stream" />
+      <pubDate>#{Gem::Specification::TODAY.rfc2822}</pubDate>
+      <link>http://example.com</link>
+    </item>
+    <item>
+      <title>pl-1-x86-linux</title>
+      <description>
+&lt;pre&gt;This is a test description&lt;/pre&gt;
+      </description>
+      <author>example@e... (A User)</author>
+      <guid>pl-1-x86-linux</guid>
+      <enclosure url="http://gems.example.com/gems/pl-1-x86-linux.gem"
+                 length="3072" type="application/octet-stream" />
+      <pubDate>#{Gem::Specification::TODAY.rfc2822}</pubDate>
+      <link>http://example.com</link>
+    </item>
+    <item>
+      <title>a-1</title>
+      <description>
+&lt;pre&gt;This line is really, really long.  So long, in fact, that it is more than
+eighty characters long!  The purpose of this line is for testing wrapping
+behavior because sometimes people don't wrap their text to eighty characters. 
+Without the wrapping, the text might not look good in the RSS feed.
+
+Also, a list:
+  * An entry that's actually kind of sort
+  * an entry that's really long, which will probably get wrapped funny. 
+That's ok, somebody wasn't thinking straight when they made it more than
+eighty characters.&lt;/pre&gt;
+      </description>
+      <author>example@e... (Example), example2@e... (Example2)</author>
+      <guid>a-1</guid>
+      <enclosure url="http://gems.example.com/gems/a-1.gem"
+                 length="3584" type="application/octet-stream" />
+      <pubDate>#{(Gem::Specification::TODAY - 86400).rfc2822}</pubDate>
+      <link>http://a.example.com</link>
+    </item>
+  </channel>
+</rss>
+    EOF
+
+    gems_rss = File.read File.join(@tempdir, 'index.rss')
+
+    assert_equal expected, gems_rss
   end
 
+  def test_generate_index_legacy
+    @indexer.build_modern = false
+    @indexer.build_legacy = true
+
+    use_ui @ui do
+      @indexer.generate_index
+    end
+
+    assert_indexed @tempdir, 'yaml'
+    assert_indexed @tempdir, 'yaml.Z'
+    assert_indexed @tempdir, "Marshal.#{@marshal_version}"
+    assert_indexed @tempdir, "Marshal.#{@marshal_version}.Z"
+
+    quickdir = File.join @tempdir, 'quick'
+    marshal_quickdir = File.join quickdir, "Marshal.#{@marshal_version}"
+
+    assert File.directory?(quickdir)
+    assert File.directory?(marshal_quickdir)
+
+    assert_indexed quickdir, "index"
+    assert_indexed quickdir, "index.rz"
+
+    assert_indexed quickdir, "latest_index"
+    assert_indexed quickdir, "latest_index.rz"
+
+    assert_indexed quickdir, "#{@a1.full_name}.gemspec.rz"
+    assert_indexed quickdir, "#{@a2.full_name}.gemspec.rz"
+    assert_indexed quickdir, "#{@b2.full_name}.gemspec.rz"
+    assert_indexed quickdir, "#{@c1_2.full_name}.gemspec.rz"
+
+    assert_indexed quickdir, "#{@pl1.original_name}.gemspec.rz"
+    refute_indexed quickdir, "#{@pl1.full_name}.gemspec.rz"
+
+    assert_indexed marshal_quickdir, "#{@a1.full_name}.gemspec.rz"
+    assert_indexed marshal_quickdir, "#{@a2.full_name}.gemspec.rz"
+
+    refute_indexed quickdir, "#{@c1_2.full_name}.gemspec"
+    refute_indexed marshal_quickdir, "#{@c1_2.full_name}.gemspec"
+
+    refute_indexed @tempdir, "specs.#{@marshal_version}"
+    refute_indexed @tempdir, "specs.#{@marshal_version}.gz"
+
+    refute_indexed @tempdir, "latest_specs.#{@marshal_version}"
+    refute_indexed @tempdir, "latest_specs.#{@marshal_version}.gz"
+  end
+
+  def test_generate_index_legacy_back_to_back
+    @indexer.build_modern = true
+    @indexer.build_legacy = true
+
+    use_ui @ui do
+      @indexer.generate_index
+    end
+
+    @indexer = Gem::Indexer.new @tempdir
+    @indexer.build_modern = false
+    @indexer.build_legacy = true
+
+    use_ui @ui do
+      @indexer.generate_index
+    end
+
+    assert_indexed @tempdir, 'yaml'
+    assert_indexed @tempdir, 'yaml.Z'
+    assert_indexed @tempdir, "Marshal.#{@marshal_version}"
+    assert_indexed @tempdir, "Marshal.#{@marshal_version}.Z"
+
+    quickdir = File.join @tempdir, 'quick'
+    marshal_quickdir = File.join quickdir, "Marshal.#{@marshal_version}"
+
+    assert File.directory?(quickdir)
+    assert File.directory?(marshal_quickdir)
+
+    assert_indexed quickdir, "index"
+    assert_indexed quickdir, "index.rz"
+
+    assert_indexed quickdir, "latest_index"
+    assert_indexed quickdir, "latest_index.rz"
+
+    assert_indexed quickdir, "#{@a1.full_name}.gemspec.rz"
+    assert_indexed quickdir, "#{@a2.full_name}.gemspec.rz"
+    assert_indexed quickdir, "#{@b2.full_name}.gemspec.rz"
+    assert_indexed quickdir, "#{@c1_2.full_name}.gemspec.rz"
+
+    assert_indexed quickdir, "#{@pl1.original_name}.gemspec.rz"
+
+    assert_indexed marshal_quickdir, "#{@a1.full_name}.gemspec.rz"
+    assert_indexed marshal_quickdir, "#{@a2.full_name}.gemspec.rz"
+
+    assert_indexed @tempdir, "specs.#{@marshal_version}"
+    assert_indexed @tempdir, "specs.#{@marshal_version}.gz"
+
+    assert_indexed @tempdir, "latest_specs.#{@marshal_version}"
+    assert_indexed @tempdir, "latest_specs.#{@marshal_version}.gz"
+  end
+
+  def test_generate_index_modern
+    @indexer.build_modern = true
+    @indexer.build_legacy = false
+
+    use_ui @ui do
+      @indexer.generate_index
+    end
+
+    refute_indexed @tempdir, 'yaml'
+    refute_indexed @tempdir, 'yaml.Z'
+    refute_indexed @tempdir, "Marshal.#{@marshal_version}"
+    refute_indexed @tempdir, "Marshal.#{@marshal_version}.Z"
+
+    quickdir = File.join @tempdir, 'quick'
+    marshal_quickdir = File.join quickdir, "Marshal.#{@marshal_version}"
+
+    assert File.directory?(quickdir), 'quickdir should be directory'
+    assert File.directory?(marshal_quickdir)
+
+    refute_indexed quickdir, "index"
+    refute_indexed quickdir, "index.rz"
+
+    refute_indexed quickdir, "latest_index"
+    refute_indexed quickdir, "latest_index.rz"
+
+    refute_indexed quickdir, "#{@a1.full_name}.gemspec.rz"
+    refute_indexed quickdir, "#{@a2.full_name}.gemspec.rz"
+    refute_indexed quickdir, "#{@b2.full_name}.gemspec.rz"
+    refute_indexed quickdir, "#{@c1_2.full_name}.gemspec.rz"
+
+    refute_indexed quickdir, "#{@pl1.original_name}.gemspec.rz"
+    refute_indexed quickdir, "#{@pl1.full_name}.gemspec.rz"
+
+    assert_indexed marshal_quickdir, "#{@a1.full_name}.gemspec.rz"
+    assert_indexed marshal_quickdir, "#{@a2.full_name}.gemspec.rz"
+
+    refute_indexed quickdir, "#{@c1_2.full_name}.gemspec"
+    refute_indexed marshal_quickdir, "#{@c1_2.full_name}.gemspec"
+
+    assert_indexed @tempdir, "specs.#{@marshal_version}"
+    assert_indexed @tempdir, "specs.#{@marshal_version}.gz"
+
+    assert_indexed @tempdir, "latest_specs.#{@marshal_version}"
+    assert_indexed @tempdir, "latest_specs.#{@marshal_version}.gz"
+  end
+
+  def test_generate_index_modern_back_to_back
+    @indexer.build_modern = true
+    @indexer.build_legacy = true
+
+    use_ui @ui do
+      @indexer.generate_index
+    end
+
+    @indexer = Gem::Indexer.new @tempdir
+    @indexer.build_modern = true
+    @indexer.build_legacy = false
+
+    use_ui @ui do
+      @indexer.generate_index
+    end
+
+    assert_indexed @tempdir, 'yaml'
+    assert_indexed @tempdir, 'yaml.Z'
+    assert_indexed @tempdir, "Marshal.#{@marshal_version}"
+    assert_indexed @tempdir, "Marshal.#{@marshal_version}.Z"
+
+    quickdir = File.join @tempdir, 'quick'
+    marshal_quickdir = File.join quickdir, "Marshal.#{@marshal_version}"
+
+    assert File.directory?(quickdir)
+    assert File.directory?(marshal_quickdir)
+
+    assert_indexed quickdir, "index"
+    assert_indexed quickdir, "index.rz"
+
+    assert_indexed quickdir, "latest_index"
+    assert_indexed quickdir, "latest_index.rz"
+
+    assert_indexed quickdir, "#{@a1.full_name}.gemspec.rz"
+    assert_indexed quickdir, "#{@a2.full_name}.gemspec.rz"
+    assert_indexed quickdir, "#{@b2.full_name}.gemspec.rz"
+    assert_indexed quickdir, "#{@c1_2.full_name}.gemspec.rz"
+
+    assert_indexed quickdir, "#{@pl1.original_name}.gemspec.rz"
+
+    assert_indexed marshal_quickdir, "#{@a1.full_name}.gemspec.rz"
+    assert_indexed marshal_quickdir, "#{@a2.full_name}.gemspec.rz"
+
+    assert_indexed @tempdir, "specs.#{@marshal_version}"
+    assert_indexed @tempdir, "specs.#{@marshal_version}.gz"
+
+    assert_indexed @tempdir, "latest_specs.#{@marshal_version}"
+    assert_indexed @tempdir, "latest_specs.#{@marshal_version}.gz"
+  end
+
   def test_generate_index_ui
     use_ui @ui do
       @indexer.generate_index
     end
 
-    expected = <<-EOF
-Loading 7 gems from #{@tempdir}
-.......
-Loaded all gems
-Generating quick index gemspecs for 7 gems
-.......
-Complete
-Generating specs index
-Generating latest specs index
-Generating quick index
-Generating latest index
-Generating Marshal master index
-Generating YAML master index for 7 gems (this may take a while)
-.......
-Complete
-Compressing indicies
-    EOF
+    assert_match %r%^Loading 10 gems from #{Regexp.escape @tempdir}$%,
+                 @ui.output
+    assert_match %r%^\.\.\.\.\.\.\.\.\.\.$%, @ui.output
+    assert_match %r%^Loaded all gems$%, @ui.output
+    assert_match %r%^Generating Marshal quick index gemspecs for 7 gems$%,
+                 @ui.output
+    assert_match %r%^Generating YAML quick index gemspecs for 7 gems$%,
+                 @ui.output
+    assert_match %r%^Complete$%, @ui.output
+    assert_match %r%^Generating specs index$%, @ui.output
+    assert_match %r%^Generating latest specs index$%, @ui.output
+    assert_match %r%^Generating quick index$%, @ui.output
+    assert_match %r%^Generating latest index$%, @ui.output
+    assert_match %r%^Generating prerelease specs index$%, @ui.output
+    assert_match %r%^Generating Marshal master index$%, @ui.output
+    assert_match %r%^Generating YAML master index for 7 gems \(this may take a while\)$%, @ui.output
+    assert_match %r%^Complete$%, @ui.output
+    assert_match %r%^Compressing indicies$%, @ui.output
 
-    assert_equal expected, @ui.output
     assert_equal '', @ui.error
   end
 
@@ -248,6 +562,71 @@
                 'identical platforms not identical'
   end
 
+  def test_generate_index_prerelease_specs
+    use_ui @ui do
+      @indexer.generate_index
+    end
+
+    prerelease_specs_path = File.join @tempdir, "prerelease_specs.#{@marshal_version}"
+
+    prerelease_specs_dump = Gem.read_binary prerelease_specs_path
+    prerelease_specs = Marshal.load prerelease_specs_dump
+
+    assert_equal [['a', Gem::Version.new('3.a'),   'ruby'],
+                  ['d', Gem::Version.new('2.0.a'), 'ruby'],
+                  ['d', Gem::Version.new('2.0.b'), 'ruby']],
+                 prerelease_specs
+  end
+
+  def test_update_index
+    use_ui @ui do
+      @indexer.generate_index
+    end
+
+    quickdir = File.join @tempdir, 'quick'
+    marshal_quickdir = File.join quickdir, "Marshal.#{@marshal_version}"
+
+    assert File.directory?(quickdir)
+    assert File.directory?(marshal_quickdir)
+
+    @d2_1 = quick_gem 'd', '2.1'
+    util_build_gem @d2_1
+    @d2_1_tuple = [@d2_1.name, @d2_1.version, @d2_1.original_platform]
+
+    @d2_1_a = quick_gem 'd', '2.2.a'
+    util_build_gem @d2_1_a
+    @d2_1_a_tuple = [@d2_1_a.name, @d2_1_a.version, @d2_1_a.original_platform]
+
+    gems = File.join @tempdir, 'gems'
+    FileUtils.mv File.join(@gemhome, 'cache', "#{@d2_1.full_name}.gem"), gems
+    FileUtils.mv File.join(@gemhome, 'cache', "#{@d2_1_a.full_name}.gem"), gems
+
+    use_ui @ui do
+      @indexer.update_index
+    end
+
+    assert_indexed marshal_quickdir, "#{@d2_1.full_name}.gemspec.rz"
+
+    specs_index = Marshal.load Gem.read_binary(@indexer.dest_specs_index)
+
+    assert_includes specs_index, @d2_1_tuple
+    refute_includes specs_index, @d2_1_a_tuple
+
+    latest_specs_index = Marshal.load \
+      Gem.read_binary(@indexer.dest_latest_specs_index)
+
+    assert_includes latest_specs_index, @d2_1_tuple
+    assert_includes latest_specs_index,
+                    [@d2_0.name, @d2_0.version, @d2_0.original_platform]
+    refute_includes latest_specs_index, @d2_1_a_tuple
+
+    pre_specs_index = Marshal.load \
+      Gem.read_binary(@indexer.dest_prerelease_specs_index)
+
+    assert_includes pre_specs_index, @d2_1_a_tuple
+    refute_includes pre_specs_index, @d2_1_tuple
+  end
+
   def assert_indexed(dir, name)
     file = File.join dir, name
     assert File.exist?(file), "#{file} does not exist"
@@ -255,7 +634,7 @@
 
   def refute_indexed(dir, name)
     file = File.join dir, name
-    assert !File.exist?(file), "#{file} exists"
+    refute File.exist?(file), "#{file} exists"
   end
 
 end if ''.respond_to? :to_xs
Index: test/rubygems/test_gem_doc_manager.rb
===================================================================
--- test/rubygems/test_gem_doc_manager.rb	(revision 23658)
+++ test/rubygems/test_gem_doc_manager.rb	(revision 23659)
@@ -18,7 +18,13 @@
 
   def test_uninstall_doc_unwritable
     orig_mode = File.stat(@spec.installation_path).mode
-    File.chmod 0, @spec.installation_path
+    
+    # File.chmod has no effect on MS Windows directories (it needs ACL).
+    if win_platform?
+      skip("test_uninstall_doc_unwritable skipped on MS Windows")
+    else
+      File.chmod(0, @spec.installation_path)
+    end
 
     assert_raises Gem::FilePermissionError do
       @manager.uninstall_doc
Index: test/rubygems/test_gem_commands_unpack_command.rb
===================================================================
--- test/rubygems/test_gem_commands_unpack_command.rb	(revision 23658)
+++ test/rubygems/test_gem_commands_unpack_command.rb	(revision 23659)
@@ -14,7 +14,7 @@
   def test_execute
     util_make_gems
 
-    @cmd.options[:args] = %w[a]
+    @cmd.options[:args] = %w[a b]
 
     use_ui @ui do
       Dir.chdir @tempdir do
@@ -22,7 +22,8 @@
       end
     end
 
-    assert File.exist?(File.join(@tempdir, 'a-2'))
+    assert File.exist?(File.join(@tempdir, 'a-3.a')), 'a should be installed'
+    assert File.exist?(File.join(@tempdir, 'b-2')),   'b should be installed'
   end
 
   def test_execute_gem_path
@@ -43,7 +44,7 @@
       end
     end
 
-    assert File.exist?(File.join(@tempdir, 'a-2'))
+    assert File.exist?(File.join(@tempdir, 'a-3.a'))
   end
 
   def test_execute_gem_path_missing
@@ -80,7 +81,7 @@
       end
     end
 
-    assert File.exist?(File.join(@tempdir, target, 'a-2'))
+    assert File.exist?(File.join(@tempdir, target, 'a-3.a'))
   end
 
   def test_execute_exact_match
Index: test/rubygems/test_gem_commands_update_command.rb
===================================================================
--- test/rubygems/test_gem_commands_update_command.rb	(revision 23658)
+++ test/rubygems/test_gem_commands_update_command.rb	(revision 23659)
@@ -8,6 +8,9 @@
 
     @cmd = Gem::Commands::UpdateCommand.new
 
+    @cmd.options[:generate_rdoc] = false
+    @cmd.options[:generate_ri]   = false
+
     util_setup_fake_fetcher
 
     @a1_path = File.join @gemhome, 'cache', "#{@a1.full_name}.gem"
@@ -27,6 +30,8 @@
     Gem::Installer.new(@a1_path).install
 
     @cmd.options[:args] = []
+    @cmd.options[:generate_rdoc] = true
+    @cmd.options[:generate_ri]   = true
 
     use_ui @ui do
       @cmd.execute
@@ -37,8 +42,10 @@
     assert_equal "Updating #{@a2.name}", out.shift
     assert_equal "Successfully installed #{@a2.full_name}", out.shift
     assert_equal "Gems updated: #{@a2.name}", out.shift
+    assert_equal "Installing ri documentation for a-2...", out.shift
+    assert_equal "Installing RDoc documentation for a-2...", out.shift
 
-    assert out.empty?, out.inspect
+    assert_empty out
   end
 
   # before:
@@ -101,7 +108,7 @@
     assert_equal "Gems updated: #{@c2.name}, #{@b2.name}, #{@a2.name}",
                  out.shift
 
-    assert out.empty?, out.inspect
+    assert_empty out
   end
 
   def test_execute_named
@@ -121,7 +128,7 @@
     assert_equal "Successfully installed #{@a2.full_name}", out.shift
     assert_equal "Gems updated: #{@a2.name}", out.shift
 
-    assert out.empty?, out.inspect
+    assert_empty out
   end
 
   def test_execute_named_up_to_date
@@ -139,7 +146,7 @@
     assert_equal "Updating installed gems", out.shift
     assert_equal "Nothing to update", out.shift
 
-    assert out.empty?, out.inspect
+    assert_empty out
   end
 
   def test_execute_up_to_date
@@ -157,8 +164,6 @@
     assert_equal "Updating installed gems", out.shift
     assert_equal "Nothing to update", out.shift
 
-    assert out.empty?, out.inspect
+    assert_empty out
   end
-
 end
-
Index: test/rubygems/test_gem_server.rb
===================================================================
--- test/rubygems/test_gem_server.rb	(revision 23658)
+++ test/rubygems/test_gem_server.rb	(revision 23659)
@@ -222,7 +222,17 @@
     assert_equal Gem::Platform.local, spec.platform
   end
 
+  def test_rdoc
+    data = StringIO.new "GET /rdoc?q=a HTTP/1.0\r\n\r\n"
+    @req.parse data
 
+    @server.rdoc @req, @res
+
+    assert_equal 200, @res.status, @res.body
+    assert_match %r|No documentation found|, @res.body
+    assert_equal 'text/html', @res['content-type']
+  end
+
   def test_root
     data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
     @req.parse data
Index: test/rubygems/test_gem_commands_cert_command.rb
===================================================================
--- test/rubygems/test_gem_commands_cert_command.rb	(revision 23658)
+++ test/rubygems/test_gem_commands_cert_command.rb	(revision 23659)
@@ -105,7 +105,7 @@
     assert_equal "Removed '/CN=rubygems/DC=example/DC=com'\n", @ui.output
     assert_equal '', @ui.error
 
-    assert !File.exist?(@cert_file_name)
+    refute File.exist?(@cert_file_name)
   end
 
   def test_execute_sign
Index: test/rubygems/test_gem_dependency.rb
===================================================================
--- test/rubygems/test_gem_dependency.rb	(revision 23658)
+++ test/rubygems/test_gem_dependency.rb	(revision 23659)
@@ -20,6 +20,10 @@
     @r1_0 = Gem::Requirement.new ['> 1.0']
   end
 
+  def dep(name, version)
+    Gem::Dependency.new name, version
+  end
+
   def test_initialize
     assert_equal "pkg", @pkg1_0.name
     assert_equal @r1_0, @pkg1_0.version_requirements
@@ -96,10 +100,6 @@
   end
 
   def test_equals_tilde
-    def dep(name, version)
-      Gem::Dependency.new name, version
-    end
-
     a0   = dep 'a', '0'
     a1   = dep 'a', '1'
     b0   = dep 'b', '0'
@@ -108,16 +108,66 @@
     pa0r = dep(/a/, '>= 0')
     pab0r = dep(/a|b/, '>= 0')
 
-    assert((a0    =~ a0), 'match self')
-    assert((pa0   =~ a0), 'match version exact')
-    assert((pa0   =~ a1), 'match version')
-    assert((pa0r  =~ a0), 'match regex simple')
-    assert((pab0r =~ a0), 'match regex complex')
+    assert_match a0,    a0, 'match self'
+    assert_match pa0,   a0, 'match version exact'
+    assert_match pa0,   a1, 'match version'
+    assert_match pa0r,  a0, 'match regex simple'
+    assert_match pab0r, a0, 'match regex complex'
 
-    assert(!(pa0r =~ b0),         'fail match regex')
-    assert(!(pa0r =~ Object.new), 'fail match Object')
+    refute_match pa0r, b0,         'fail match regex'
+    refute_match pa0r, Object.new, 'fail match Object'
   end
 
+  def test_equals_tilde_escape
+    a1 = Gem::Dependency.new 'a', '1'
+
+    pab1  = Gem::Dependency.new 'a|b', '>= 1'
+    pab1r = Gem::Dependency.new(/a|b/, '>= 1')
+
+    refute_match pab1,  a1, 'escaped'
+    assert_match pab1r, a1, 'exact regexp'
+  end
+
+  def test_equals_tilde_object
+    a0 = Object.new
+
+    def a0.name() 'a' end
+    def a0.version() '0' end
+
+    pa0  = Gem::Dependency.new 'a', '>= 0'
+
+    assert_match pa0, a0, 'match version exact'
+  end
+
+  def test_equals_tilde_spec
+    def spec(name, version)
+      Gem::Specification.new do |spec|
+        spec.name = name
+        spec.version = version
+      end
+    end
+
+    a0   = spec 'a', '0'
+    a1   = spec 'a', '1'
+    b0   = spec 'b', '0'
+
+    pa0  = dep 'a', '>= 0'
+    pa0r = dep(/a/, '>= 0')
+    pab0r = dep(/a|b/, '>= 0')
+
+    assert_match pa0, a0,   'match version exact'
+    assert_match pa0, a1,   'match version'
+
+    assert_match pa0r, a0,  'match regex simple'
+    assert_match pa0r, a1,  'match regex simple'
+
+    assert_match pab0r, a0, 'match regex complex'
+    assert_match pab0r, b0, 'match regex complex'
+
+    refute_match pa0r, b0,         'fail match regex'
+    refute_match pa0r, Object.new, 'fail match Object'
+  end
+
   def test_hash
     assert_equal @pkg1_0.hash, @pkg1_0.dup.hash
     assert_equal @pkg1_0.dup.hash, @pkg1_0.hash
@@ -135,5 +185,6 @@
 
     refute_equal(runtime.hash, development.hash)
   end
+
 end
 
Index: test/rubygems/test_gem_local_remote_options.rb
===================================================================
--- test/rubygems/test_gem_local_remote_options.rb	(revision 23658)
+++ test/rubygems/test_gem_local_remote_options.rb	(revision 23659)
@@ -60,8 +60,9 @@
     s1 = URI.parse 'http://more-gems.example.com/'
     s2 = URI.parse 'http://even-more-gems.example.com/'
     s3 = URI.parse 'http://other-gems.example.com/some_subdir'
+    s4 = URI.parse 'http://more-gems.example.com/' # Intentional duplicate
 
-    @cmd.handle_options %W[--source #{s1} --source #{s2} --source #{s3}]
+    @cmd.handle_options %W[--source #{s1} --source #{s2} --source #{s3} --source #{s4}]
 
     assert_equal [s1.to_s, s2.to_s, "#{s3}/"], Gem.sources
   end
Index: test/rubygems/test_gem_specification.rb
===================================================================
--- test/rubygems/test_gem_specification.rb	(revision 23658)
+++ test/rubygems/test_gem_specification.rb	(revision 23659)
@@ -53,6 +53,7 @@
       s.test_file = 'test/suite.rb'
       s.requirements << 'A working computer'
       s.rubyforge_project = 'example'
+      s.license = 'MIT'
 
       s.add_dependency 'rake', '> 0.4'
       s.add_dependency 'jabber4r', '> 0.0.0'
@@ -91,6 +92,7 @@
       files
       has_rdoc
       homepage
+      licenses
       name
       platform
       post_install_message
@@ -195,8 +197,8 @@
     assert_equal [], spec.requirements
     assert_equal [], spec.dependencies
     assert_equal 'bin', spec.bindir
-    assert_equal false, spec.has_rdoc
-    assert_equal false, spec.has_rdoc?
+    assert_equal true, spec.has_rdoc
+    assert_equal true, spec.has_rdoc?
     assert_equal '>= 0', spec.required_ruby_version.to_s
     assert_equal '>= 0', spec.required_rubygems_version.to_s
   end
@@ -216,6 +218,80 @@
     assert_equal "1.3.5", spec.version.to_s
   end
 
+  def test_initialize_copy
+    spec = Gem::Specification.new do |s|
+      s.name = "blah"
+      s.version = "1.3.5"
+      s.summary = 'summary'
+      s.description = 'description'
+      s.authors = 'author a', 'author b'
+      s.licenses = 'BSD'
+      s.files = 'lib/file.rb'
+      s.test_files = 'test/file.rb'
+      s.rdoc_options = '--foo'
+      s.extra_rdoc_files = 'README.txt'
+      s.executables = 'exec'
+      s.extensions = 'ext/extconf.rb'
+      s.requirements = 'requirement'
+      s.add_dependency 'some_gem'
+    end
+
+    new_spec = spec.dup
+
+    assert_equal "blah", spec.name
+    assert_same  spec.name, new_spec.name
+
+    assert_equal "1.3.5", spec.version.to_s
+    assert_same spec.version, new_spec.version
+
+    assert_equal Gem::Platform::RUBY, spec.platform
+    assert_same spec.platform, new_spec.platform
+
+    assert_equal 'summary', spec.summary
+    assert_same spec.summary, new_spec.summary
+
+    assert_equal %w[lib/file.rb test/file.rb bin/exec README.txt
+                    ext/extconf.rb],
+                 spec.files
+    refute_same spec.files, new_spec.files, 'files'
+
+    assert_equal %w[test/file.rb], spec.test_files
+    refute_same spec.test_files, new_spec.test_files, 'test_files'
+
+    assert_equal %w[--foo], spec.rdoc_options
+    refute_same spec.rdoc_options, new_spec.rdoc_options, 'rdoc_options'
+
+    assert_equal %w[README.txt], spec.extra_rdoc_files
+    refute_same spec.extra_rdoc_files, new_spec.extra_rdoc_files,
+                'extra_rdoc_files'
+
+    assert_equal %w[exec], spec.executables
+    refute_same spec.executables, new_spec.executables, 'executables'
+
+    assert_equal %w[ext/extconf.rb], spec.extensions
+    refute_same spec.extensions, new_spec.extensions, 'extensions'
+
+    assert_equal %w[requirement], spec.requirements
+    refute_same spec.requirements, new_spec.requirements, 'requirements'
+
+    assert_equal [Gem::Dependency.new('some_gem', Gem::Requirement.default)],
+                 spec.dependencies
+    refute_same spec.dependencies, new_spec.dependencies, 'dependencies'
+
+    assert_equal 'bin', spec.bindir
+    assert_same spec.bindir, new_spec.bindir
+
+    assert_equal true, spec.has_rdoc
+    assert_same spec.has_rdoc, new_spec.has_rdoc
+
+    assert_equal '>= 0', spec.required_ruby_version.to_s
+    assert_same spec.required_ruby_version, new_spec.required_ruby_version
+
+    assert_equal '>= 0', spec.required_rubygems_version.to_s
+    assert_same spec.required_rubygems_version,
+                new_spec.required_rubygems_version
+  end
+
   def test__dump
     @a2.platform = Gem::Platform.local
     @a2.instance_variable_set :@original_platform, 'old_platform'
@@ -355,7 +431,7 @@
       s.homepage = %q{http://www.spice-of-life.net/download/cgikit/}
       s.autorequire = %q{cgikit}
       s.bindir = nil
-      s.has_rdoc = nil
+      s.has_rdoc = true
       s.required_ruby_version = nil
       s.platform = nil
       s.files = ["lib/cgikit", "lib/cgikit.rb", "lib/cgikit/components", "..."]
@@ -490,7 +566,7 @@
       'i386-mswin32_80'   => 'a-1-x86-mswin32-80',
       'i386-mingw32'      => 'a-1-x86-mingw32'
     }
-
+    
     test_cases.each do |arch, expected|
       util_set_arch arch
       @a1.platform = 'current'
@@ -502,18 +578,49 @@
     assert @a1.has_rdoc?
   end
 
+  def test_has_rdoc_equals
+
+    use_ui @ui do
+      @a1.has_rdoc = false
+    end
+
+    assert_equal '', @ui.output
+
+    assert_equal true, @a1.has_rdoc
+  end
+
   def test_hash
     assert_equal @a1.hash, @a1.hash
     assert_equal @a1.hash, @a1.dup.hash
     refute_equal @a1.hash, @a2.hash
   end
 
+  def test_installation_path
+    assert_equal @gemhome, @a1.installation_path
+
+    @a1.instance_variable_set :@loaded_from, nil
+
+    e = assert_raises Gem::Exception do
+      @a1.installation_path
+    end
+
+    assert_equal 'spec a-1 is not from an installed gem', e.message
+  end
+
   def test_lib_files
     @a1.files = %w[lib/foo.rb Rakefile]
 
     assert_equal %w[lib/foo.rb], @a1.lib_files
   end
 
+  def test_license
+    assert_equal 'MIT', @a1.license
+  end
+
+  def test_licenses
+    assert_equal ['MIT'], @a1.licenses
+  end
+
   def test_name
     assert_equal 'a', @a1.name
   end
@@ -568,6 +675,12 @@
     assert_equal Gem::Platform.new('ppc-darwin'), @a1.platform
   end
 
+  def test_prerelease_spec_adds_required_rubygems_version
+    @prerelease = quick_gem('tardis', '2.2.0.a')
+    refute @prerelease.required_rubygems_version.satisfied_by?(Gem::Version.new('1.3.1'))
+    assert @prerelease.required_rubygems_version.satisfied_by?(Gem::Version.new('1.4.0'))
+  end
+
   def test_require_paths
     @a1.require_path = 'lib'
     assert_equal %w[lib], @a1.require_paths
@@ -646,7 +759,6 @@
   s.description = %q{This is a test description}
   s.email = %q{example@e...}
   s.files = [\"lib/code.rb\"]
-  s.has_rdoc = true
   s.homepage = %q{http://example.com}
   s.require_paths = [\"lib\"]
   s.rubygems_version = %q{#{Gem::RubyGemsVersion}}
@@ -698,8 +810,8 @@
   s.executables = [\"exec\"]
   s.extensions = [\"ext/a/extconf.rb\"]
   s.files = [\"lib/code.rb\", \"test/suite.rb\", \"bin/exec\", \"ext/a/extconf.rb\"]
-  s.has_rdoc = %q{true}
   s.homepage = %q{http://example.com}
+  s.licenses = [\"MIT\"]
   s.require_paths = [\"lib\"]
   s.requirements = [\"A working computer\"]
   s.rubyforge_project = %q{example}
@@ -709,7 +821,7 @@
 
   if s.respond_to? :specification_version then
     current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
-    s.specification_version = 2
+    s.specification_version = 3
 
     if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
       s.add_runtime_dependency(%q<rake>, [\"> 0.4\"])
@@ -797,12 +909,16 @@
   end
 
   def test_validate
+    util_setup_validate
+
     Dir.chdir @tempdir do
       assert @a1.validate
     end
   end
 
   def test_validate_authors
+    util_setup_validate
+
     Dir.chdir @tempdir do
       @a1.authors = []
 
@@ -819,10 +935,28 @@
       end
 
       assert_equal 'authors must be Array of Strings', e.message
+
+      @a1.authors = ['FIXME (who is writing this software)']
+
+      e = assert_raises Gem::InvalidSpecificationException do
+        @a1.validate
+      end
+
+      assert_equal '"FIXME" or "TODO" is not an author', e.message
+
+      @a1.authors = ['TODO (who is writing this software)']
+
+      e = assert_raises Gem::InvalidSpecificationException do
+        @a1.validate
+      end
+
+      assert_equal '"FIXME" or "TODO" is not an author', e.message
     end
   end
 
   def test_validate_autorequire
+    util_setup_validate
+
     Dir.chdir @tempdir do
       @a1.autorequire = 'code'
 
@@ -835,7 +969,50 @@
     end
   end
 
+  def test_validate_description
+    util_setup_validate
+
+    Dir.chdir @tempdir do
+      @a1.description = ''
+
+      use_ui @ui do
+        @a1.validate
+      end
+
+      assert_equal "WARNING:  no description specified\n", @ui.error, 'error'
+
+      @ui = MockGemUi.new
+      @a1.summary = 'this is my summary'
+      @a1.description = @a1.summary
+
+      use_ui @ui do
+        @a1.validate
+      end
+
+      assert_equal "WARNING:  description and summary are identical\n",
+                   @ui.error, 'error'
+
+      @a1.description = 'FIXME (describe your package)'
+
+      e = assert_raises Gem::InvalidSpecificationException do
+        @a1.validate
+      end
+
+      assert_equal '"FIXME" or "TODO" is not a description', e.message
+
+      @a1.description = 'TODO (describe your package)'
+
+      e = assert_raises Gem::InvalidSpecificationException do
+        @a1.validate
+      end
+
+      assert_equal '"FIXME" or "TODO" is not a description', e.message
+    end
+  end
+
   def test_validate_email
+    util_setup_validate
+
     Dir.chdir @tempdir do
       @a1.email = ''
 
@@ -844,10 +1021,28 @@
       end
 
       assert_equal "WARNING:  no email specified\n", @ui.error, 'error'
+
+      @a1.email = 'FIXME (your e-mail)'
+
+      e = assert_raises Gem::InvalidSpecificationException do
+        @a1.validate
+      end
+
+      assert_equal '"FIXME" or "TODO" is not an email address', e.message
+
+      @a1.email = 'TODO (your e-mail)'
+
+      e = assert_raises Gem::InvalidSpecificationException do
+        @a1.validate
+      end
+
+      assert_equal '"FIXME" or "TODO" is not an email address', e.message
     end
   end
 
   def test_validate_empty
+    util_setup_validate
+
     e = assert_raises Gem::InvalidSpecificationException do
       Gem::Specification.new.validate
     end
@@ -856,8 +1051,11 @@
   end
 
   def test_validate_executables
+    util_setup_validate
+
     FileUtils.mkdir_p File.join(@tempdir, 'bin')
     File.open File.join(@tempdir, 'bin', 'exec'), 'w' do end
+    FileUtils.mkdir_p File.join(@tempdir, 'exec')
 
     use_ui @ui do
       Dir.chdir @tempdir do
@@ -865,45 +1063,94 @@
       end
     end
 
+    assert_equal %w[exec], @a1.executables
+
     assert_equal '', @ui.output, 'output'
     assert_equal "WARNING:  bin/exec is missing #! line\n", @ui.error, 'error'
   end
 
   def test_validate_empty_require_paths
-    @a1.require_paths = []
-    e = assert_raises Gem::InvalidSpecificationException do
-      @a1.validate
+    if win_platform? then
+      skip 'test_validate_empty_require_paths skipped on MS Windows (symlink)'
+    else
+      util_setup_validate
+
+      @a1.require_paths = []
+      e = assert_raises Gem::InvalidSpecificationException do
+        @a1.validate
+      end
+
+      assert_equal 'specification must have at least one require_path',
+                   e.message
     end
+  end
 
-    assert_equal 'specification must have at least one require_path', e.message
+  def test_validate_files
+    skip 'test_validate_files skipped on MS Windows (symlink)' if win_platform?
+    util_setup_validate
+
+    @a1.files += ['lib', 'lib2']
+
+    Dir.chdir @tempdir do
+      FileUtils.ln_s '/root/path', 'lib2' unless vc_windows?
+
+      e = assert_raises Gem::InvalidSpecificationException do
+        @a1.validate
+      end
+
+      assert_equal '["lib2"] are not files', e.message
+    end
+
+    assert_equal %w[lib/code.rb test/suite.rb bin/exec ext/a/extconf.rb lib2],
+                 @a1.files
   end
 
   def test_validate_homepage
+    util_setup_validate
+
     Dir.chdir @tempdir do
-      @a1.homepage = ''
+      @a1.homepage = nil
 
       use_ui @ui do
         @a1.validate
       end
 
       assert_equal "WARNING:  no homepage specified\n", @ui.error, 'error'
-    end
-  end
 
-  def test_validate_has_rdoc
-    Dir.chdir @tempdir do
-      @a1.has_rdoc = false
+      @ui = MockGemUi.new
 
+      @a1.homepage = ''
+
       use_ui @ui do
         @a1.validate
       end
 
-      assert_equal "WARNING:  RDoc will not be generated (has_rdoc == false)\n",
-                   @ui.error, 'error'
+      assert_equal "WARNING:  no homepage specified\n", @ui.error, 'error'
+
+      @a1.homepage = 'over at my cool site'
+
+      e = assert_raises Gem::InvalidSpecificationException do
+        @a1.validate
+      end
+
+      assert_equal '"over at my cool site" is not a URI', e.message
     end
   end
 
+  def test_validate_name
+    util_setup_validate
+
+    e = assert_raises Gem::InvalidSpecificationException do
+      @a1.name = :json
+      @a1.validate
+    end
+
+    assert_equal 'invalid value for attribute name: ":json"', e.message
+  end
+
   def test_validate_platform_legacy
+    util_setup_validate
+
     Dir.chdir @tempdir do
       @a1.platform = 'mswin32'
       assert @a1.validate
@@ -917,6 +1164,8 @@
   end
 
   def test_validate_rubyforge_project
+    util_setup_validate
+
     Dir.chdir @tempdir do
       @a1.rubyforge_project = ''
 
@@ -930,6 +1179,8 @@
   end
 
   def test_validate_rubygems_version
+    util_setup_validate
+
     @a1.rubygems_version = "3"
     e = assert_raises Gem::InvalidSpecificationException do
       @a1.validate
@@ -939,7 +1190,26 @@
                  e.message
   end
 
+  def test_validate_specification_version
+    util_setup_validate
+
+    Dir.chdir @tempdir do
+      @a1.specification_version = '1.0'
+
+      e = assert_raises Gem::InvalidSpecificationException do
+        use_ui @ui do
+          @a1.validate
+        end
+      end
+
+      err = 'specification_version must be a Fixnum (did you mean version?)'
+      assert_equal err, e.message
+    end
+  end
+
   def test_validate_summary
+    util_setup_validate
+
     Dir.chdir @tempdir do
       @a1.summary = ''
 
@@ -948,6 +1218,22 @@
       end
 
       assert_equal "WARNING:  no summary specified\n", @ui.error, 'error'
+
+      @a1.summary = 'FIXME (describe your package)'
+
+      e = assert_raises Gem::InvalidSpecificationException do
+        @a1.validate
+      end
+
+      assert_equal '"FIXME" or "TODO" is not a summary', e.message
+
+      @a1.summary = 'TODO (describe your package)'
+
+      e = assert_raises Gem::InvalidSpecificationException do
+        @a1.validate
+      end
+
+      assert_equal '"FIXME" or "TODO" is not a summary', e.message
     end
   end
 
@@ -955,5 +1241,17 @@
     assert_equal Gem::Version.new('1'), @a1.version
   end
 
+  def util_setup_validate
+    Dir.chdir @tempdir do
+      FileUtils.mkdir_p File.join('ext', 'a')
+      FileUtils.mkdir_p 'lib'
+      FileUtils.mkdir_p 'test'
+
+      FileUtils.touch File.join('ext', 'a', 'extconf.rb')
+      FileUtils.touch File.join('lib', 'code.rb')
+      FileUtils.touch File.join('test', 'suite.rb')
+    end
+  end
+
 end
 
Index: test/rubygems/test_gem_install_update_options.rb
===================================================================
--- test/rubygems/test_gem_install_update_options.rb	(revision 23658)
+++ test/rubygems/test_gem_install_update_options.rb	(revision 23659)
@@ -1,4 +1,3 @@
-require File.join(File.expand_path(File.dirname(__FILE__)), 'gemutilities')
 require File.join(File.expand_path(File.dirname(__FILE__)),
                   'gem_installer_test_case')
 require 'rubygems/install_update_options'
@@ -21,6 +20,11 @@
     assert @cmd.handles?(args)
   end
 
+  def test_prerelease
+    @cmd.handle_options %w[--prerelease]
+    assert_equal true, @cmd.options[:prerelease]
+  end
+
   def test_security_policy
     @cmd.handle_options %w[-P HighSecurity]
 
@@ -38,6 +42,8 @@
   def test_user_install_enabled
     @cmd.handle_options %w[--user-install]
 
+    assert @cmd.options[:user_install]
+
     @installer = Gem::Installer.new @gem, @cmd.options
     @installer.install
     assert File.exist?(File.join(Gem.user_dir, 'gems'))
@@ -46,15 +52,23 @@
   end
 
   def test_user_install_disabled_read_only
-    @cmd.handle_options %w[--no-user-install]
+    if win_platform?
+      skip('test_user_install_disabled_read_only test skipped on MS Windows')
+    else
+      @cmd.handle_options %w[--no-user-install]
 
-    File.chmod 0755, @userhome
-    FileUtils.chmod 0000, @gemhome
+      refute @cmd.options[:user_install]
 
-    assert_raises(Gem::FilePermissionError) do
-      @installer = Gem::Installer.new @gem, @cmd.options
+      File.chmod 0755, @userhome
+      FileUtils.chmod 0000, @gemhome
+
+      assert_raises(Gem::FilePermissionError) do
+        @installer = Gem::Installer.new @gem, @cmd.options
+      end
     end
   ensure
     FileUtils.chmod 0755, @gemhome
   end
+
 end
+
Index: test/rubygems/test_gem_version.rb
===================================================================
--- test/rubygems/test_gem_version.rb	(revision 23658)
+++ test/rubygems/test_gem_version.rb	(revision 23659)
@@ -12,9 +12,13 @@
   def setup
     super
 
+    version = Object.new
+    def version.to_s() '1.4.0' end
+
     @v1_0 = Gem::Version.new '1.0'
     @v1_2 = Gem::Version.new '1.2'
     @v1_3 = Gem::Version.new '1.3'
+    @v1_4_0 = Gem::Version.new version
   end
 
   def test_class_create
@@ -64,6 +68,11 @@
     assert_equal "5.3", v.bump.to_s
   end
 
+  def test_bump_alpha
+    v = Gem::Version.new("5.2.4.a")
+    assert_equal "5.3", v.bump.to_s
+  end
+
   def test_bump_one_level
     v = Gem::Version.new("5")
     assert_equal "6", v.bump.to_s
@@ -83,6 +92,20 @@
     assert_equal false, @v1_3.eql?(@v1_2)
   end
 
+  def test_eql_eh4
+    v1_4   = Gem::Version.new '1.4'
+    v1_4_0 = Gem::Version.new "1.4.0"
+
+    assert_equal true, v1_4_0.eql?(@v1_4_0)
+    assert_equal true, @v1_4_0.eql?(v1_4_0)
+
+    assert_equal false, v1_4.eql?(@v1_4_0)
+    assert_equal false, @v1_4_0.eql?(v1_4)
+
+    assert_equal false, @v1_4_0.eql?(@v1_3)
+    assert_equal false, @v1_3.eql?(@v1_4_0)
+  end
+
   def test_equals2
     v = Gem::Version.new("1.2")
 
@@ -96,12 +119,17 @@
   def test_hash
     v1_2   = Gem::Version.new "1.2"
     v1_2_0 = Gem::Version.new "1.2.0"
+    v1_4_0 = Gem::Version.new "1.4.0"
 
     assert_equal v1_2.hash, @v1_2.hash
 
     refute_equal v1_2_0.hash, @v1_2.hash
 
+    assert_equal v1_4_0.hash, @v1_4_0.hash
+
     refute_equal @v1_2.hash, @v1_3.hash
+
+    refute_equal @v1_2.hash, @v1_4_0.hash
   end
 
   def test_illformed_requirements
@@ -113,9 +141,12 @@
   end
 
   def test_normalize
-    assert_equal [1],    Gem::Version.new("1").to_ints
-    assert_equal [1],    Gem::Version.new("1.0").to_ints
-    assert_equal [1, 1], Gem::Version.new("1.1").to_ints
+    assert_equal [0],         Gem::Version.new("").normalize.map { |part| part.value }
+    assert_equal [0],         Gem::Version.new("0").normalize.map { |part| part.value }
+    assert_equal [1],         Gem::Version.new("1").normalize.map { |part| part.value }
+    assert_equal [1],         Gem::Version.new("1.0").normalize.map { |part| part.value }
+    assert_equal [1, 1],      Gem::Version.new("1.1").normalize.map { |part| part.value }
+    assert_equal [1, 1, "a"], Gem::Version.new("1.1.a").normalize.map { |part| part.value }
   end
 
   def test_ok
@@ -139,11 +170,43 @@
     assert_adequate( "",            "< 0.1")
     assert_adequate( "  ",          "< 0.1 ")
     assert_adequate( "",            " <  0.1")
+    assert_adequate( "  ",          "> 0.a ")
+    assert_adequate( "",            " >  0.a")
     assert_adequate( "0",           "=")
     assert_adequate( "0",           ">=")
     assert_adequate( "0",           "<=")
+    assert_adequate( "3.1",         "< 3.2.rc1")
+    assert_adequate( "3.2.0",       "> 3.2.0.rc1")
+    assert_adequate( "3.2.0.rc2",   "> 3.2.0.rc1")
+    assert_adequate( "3.0.rc2",     "< 3.0")
+    assert_adequate( "3.0.rc2",     "< 3.0.0")
+    assert_adequate( "3.0.rc2",     "< 3.0.1")
   end
 
+  def test_parse_parts_from_version_string
+    assert_equal [], part_values(Gem::Version.new("").parse_parts_from_version_string)
+    assert_equal [1], part_values(Gem::Version.new("1").parse_parts_from_version_string)
+    assert_equal [1, 0], part_values(Gem::Version.new("1.0").parse_parts_from_version_string)
+    assert_equal [1, 0, "a"], part_values(Gem::Version.new("1.0.a").parse_parts_from_version_string)
+  end
+
+  def test_prerelease
+    assert Gem::Version.new('1.2.0.a').prerelease?
+    assert Gem::Version.new('2.9.b').prerelease?
+    assert Gem::Version.new('22.1.50.0.d').prerelease?
+
+    refute Gem::Version.new('1.2.0').prerelease?
+    refute Gem::Version.new('2.9').prerelease?
+    refute Gem::Version.new('22.1.50.0').prerelease?
+  end
+  
+  def test_release
+    assert_equal Gem::Version.new('1.2.0'), Gem::Version.new('1.2.0.a').release
+    assert_equal Gem::Version.new('1.1'),   Gem::Version.new('1.1.rc10').release
+    assert_equal Gem::Version.new('1.9.3'), Gem::Version.new('1.9.3.alpha.5').release
+    assert_equal Gem::Version.new('1.9.3'), Gem::Version.new('1.9.3').release
+  end
+
   def test_satisfied_by_eh_boxed
     assert_inadequate("1.3", "~> 1.4")
     assert_adequate(  "1.4", "~> 1.4")
@@ -156,6 +219,11 @@
     assert_adequate(  "1.4.5", "~> 1.4.4")
     assert_inadequate("1.5",   "~> 1.4.4")
     assert_inadequate("2.0",   "~> 1.4.4")
+    
+    assert_inadequate("1.1.pre", "~> 1.0.0")
+    assert_adequate(  "1.1.pre", "~> 1.1")
+    assert_inadequate("2.0.a",   "~> 1.0")
+    assert_adequate(  "2.0.a",   "~> 2.0")
   end
 
   def test_satisfied_by_eh_multiple
@@ -169,7 +237,12 @@
   end
 
   def test_spaceship
+    assert_equal 0, Gem::Version.new('1.0') <=> Gem::Version.new('1.0.0')
+    assert_equal 1, Gem::Version.new('1.0') <=> Gem::Version.new('1.0.a')
     assert_equal 1, Gem::Version.new('1.8.2') <=> Gem::Version.new('0.0.0')
+    assert_equal 1, Gem::Version.new('1.8.2') <=> Gem::Version.new('1.8.2.a')
+    assert_equal 1, Gem::Version.new('1.8.2.b') <=> Gem::Version.new('1.8.2.a')
+    assert_equal 0, Gem::Version.new('') <=> Gem::Version.new('0')
   end
 
   def test_boxed
@@ -201,7 +274,7 @@
   def assert_inadequate(version, requirement)
     ver = Gem::Version.new(version)
     req = Gem::Version::Requirement.new(requirement)
-    assert ! req.satisfied_by?(ver),
+    refute req.satisfied_by?(ver),
       "Version #{version} should not be adequate for Requirement #{requirement}"
   end
 
@@ -210,5 +283,34 @@
     assert_equal @v1_0.version, actual.version
   end
 
+  def part_values(*parts)
+    parts.flatten.map { |part| part.value }
+  end
 end
 
+class TestGemVersionPart < RubyGemTestCase
+  def test_initialize
+    assert_equal 1, Gem::Version::Part.new(1).value
+    assert_equal 1, Gem::Version::Part.new("1").value
+    assert_equal "a", Gem::Version::Part.new("a").value
+  end
+
+  def test_spaceship
+    assert_equal(-1, Gem::Version::Part.new(1) <=> Gem::Version::Part.new(2))
+    assert_equal( 0, Gem::Version::Part.new(2) <=> Gem::Version::Part.new(2))
+    assert_equal( 1, Gem::Version::Part.new(2) <=> Gem::Version::Part.new(1))
+
+    assert_equal(-1, Gem::Version::Part.new("a") <=> Gem::Version::Part.new("b"))
+    assert_equal( 0, Gem::Version::Part.new("b") <=> Gem::Version::Part.new("b"))
+    assert_equal( 1, Gem::Version::Part.new("b") <=> Gem::Version::Part.new("a"))
+
+    assert_equal(-1, Gem::Version::Part.new("a") <=> Gem::Version::Part.new(1))
+    assert_equal( 1, Gem::Version::Part.new(1)   <=> Gem::Version::Part.new("a"))
+  end
+
+  def test_succ
+    assert_equal 2, Gem::Version::Part.new(1).succ.value
+    assert_equal "b", Gem::Version::Part.new("a").succ.value
+  end
+end
+

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]