[macruby-changes] [3330] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Mon Jan 25 12:26:54 PST 2010


Revision: 3330
          http://trac.macosforge.org/projects/ruby/changeset/3330
Author:   eloy.de.enige at gmail.com
Date:     2010-01-25 12:26:51 -0800 (Mon, 25 Jan 2010)
Log Message:
-----------
Updated RubyGems to 1.3.5

Modified Paths:
--------------
    MacRuby/trunk/bin/gem
    MacRuby/trunk/gem_prelude.rb
    MacRuby/trunk/lib/rubygems/builder.rb
    MacRuby/trunk/lib/rubygems/command.rb
    MacRuby/trunk/lib/rubygems/command_manager.rb
    MacRuby/trunk/lib/rubygems/commands/check_command.rb
    MacRuby/trunk/lib/rubygems/commands/cleanup_command.rb
    MacRuby/trunk/lib/rubygems/commands/contents_command.rb
    MacRuby/trunk/lib/rubygems/commands/generate_index_command.rb
    MacRuby/trunk/lib/rubygems/commands/install_command.rb
    MacRuby/trunk/lib/rubygems/commands/query_command.rb
    MacRuby/trunk/lib/rubygems/commands/rdoc_command.rb
    MacRuby/trunk/lib/rubygems/commands/search_command.rb
    MacRuby/trunk/lib/rubygems/commands/server_command.rb
    MacRuby/trunk/lib/rubygems/commands/sources_command.rb
    MacRuby/trunk/lib/rubygems/commands/specification_command.rb
    MacRuby/trunk/lib/rubygems/commands/uninstall_command.rb
    MacRuby/trunk/lib/rubygems/commands/unpack_command.rb
    MacRuby/trunk/lib/rubygems/commands/update_command.rb
    MacRuby/trunk/lib/rubygems/commands/which_command.rb
    MacRuby/trunk/lib/rubygems/config_file.rb
    MacRuby/trunk/lib/rubygems/defaults.rb
    MacRuby/trunk/lib/rubygems/dependency.rb
    MacRuby/trunk/lib/rubygems/dependency_installer.rb
    MacRuby/trunk/lib/rubygems/dependency_list.rb
    MacRuby/trunk/lib/rubygems/digest/digest_adapter.rb
    MacRuby/trunk/lib/rubygems/digest/sha1.rb
    MacRuby/trunk/lib/rubygems/digest/sha2.rb
    MacRuby/trunk/lib/rubygems/doc_manager.rb
    MacRuby/trunk/lib/rubygems/exceptions.rb
    MacRuby/trunk/lib/rubygems/ext/builder.rb
    MacRuby/trunk/lib/rubygems/ext/configure_builder.rb
    MacRuby/trunk/lib/rubygems/ext/ext_conf_builder.rb
    MacRuby/trunk/lib/rubygems/ext/rake_builder.rb
    MacRuby/trunk/lib/rubygems/format.rb
    MacRuby/trunk/lib/rubygems/gem_openssl.rb
    MacRuby/trunk/lib/rubygems/gem_path_searcher.rb
    MacRuby/trunk/lib/rubygems/gem_runner.rb
    MacRuby/trunk/lib/rubygems/indexer.rb
    MacRuby/trunk/lib/rubygems/install_update_options.rb
    MacRuby/trunk/lib/rubygems/installer.rb
    MacRuby/trunk/lib/rubygems/local_remote_options.rb
    MacRuby/trunk/lib/rubygems/old_format.rb
    MacRuby/trunk/lib/rubygems/package/f_sync_dir.rb
    MacRuby/trunk/lib/rubygems/package/tar_header.rb
    MacRuby/trunk/lib/rubygems/package/tar_input.rb
    MacRuby/trunk/lib/rubygems/package/tar_output.rb
    MacRuby/trunk/lib/rubygems/package/tar_reader/entry.rb
    MacRuby/trunk/lib/rubygems/package/tar_reader.rb
    MacRuby/trunk/lib/rubygems/package/tar_writer.rb
    MacRuby/trunk/lib/rubygems/platform.rb
    MacRuby/trunk/lib/rubygems/remote_fetcher.rb
    MacRuby/trunk/lib/rubygems/require_paths_builder.rb
    MacRuby/trunk/lib/rubygems/requirement.rb
    MacRuby/trunk/lib/rubygems/server.rb
    MacRuby/trunk/lib/rubygems/source_index.rb
    MacRuby/trunk/lib/rubygems/source_info_cache_entry.rb
    MacRuby/trunk/lib/rubygems/spec_fetcher.rb
    MacRuby/trunk/lib/rubygems/specification.rb
    MacRuby/trunk/lib/rubygems/timer.rb
    MacRuby/trunk/lib/rubygems/uninstaller.rb
    MacRuby/trunk/lib/rubygems/user_interaction.rb
    MacRuby/trunk/lib/rubygems/validator.rb
    MacRuby/trunk/lib/rubygems/version.rb
    MacRuby/trunk/lib/rubygems/version_option.rb
    MacRuby/trunk/lib/rubygems.rb

Added Paths:
-----------
    MacRuby/trunk/lib/rubygems/commands/setup_command.rb
    MacRuby/trunk/lib/rubygems/package_task.rb
    MacRuby/trunk/lib/rubygems/text.rb

Removed Paths:
-------------
    MacRuby/trunk/lib/rubygems/indexer/abstract_index_builder.rb
    MacRuby/trunk/lib/rubygems/indexer/latest_index_builder.rb
    MacRuby/trunk/lib/rubygems/indexer/marshal_index_builder.rb
    MacRuby/trunk/lib/rubygems/indexer/master_index_builder.rb
    MacRuby/trunk/lib/rubygems/indexer/quick_index_builder.rb
    MacRuby/trunk/lib/rubygems/rubygems_version.rb

Modified: MacRuby/trunk/bin/gem
===================================================================
--- MacRuby/trunk/bin/gem	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/bin/gem	2010-01-25 20:26:51 UTC (rev 3330)
@@ -15,10 +15,7 @@
   abort "Expected Ruby Version #{required_version}, was #{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

Modified: MacRuby/trunk/gem_prelude.rb
===================================================================
--- MacRuby/trunk/gem_prelude.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/gem_prelude.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -1,9 +1,7 @@
 # depends on: array.rb dir.rb env.rb file.rb hash.rb module.rb regexp.rb
+# vim: filetype=ruby
+# THIS FILE WAS AUTOGENERATED, DO NOT EDIT
 
-# empty gem_prelude.rb
-#
-# p defined?(Gem)
-
 if defined?(Gem) then
 
   module Kernel
@@ -17,6 +15,7 @@
   module Gem
 
     ConfigMap = {
+      :BASERUBY => RbConfig::CONFIG["BASERUBY"],
       :sitedir => RbConfig::CONFIG["sitedir"],
       :ruby_version => RbConfig::CONFIG["ruby_version"],
       :libdir => RbConfig::CONFIG["libdir"],
@@ -28,73 +27,201 @@
       :ruby_install_name => RbConfig::CONFIG["ruby_install_name"]
     }
 
-    class << self
+    def self.dir
+      @gem_home ||= nil
+      set_home(ENV['GEM_HOME'] || default_dir) unless @gem_home
+      @gem_home
+    end
 
-      def default_dir
-        if defined? RUBY_FRAMEWORK_VERSION
-          return File.join(File.dirname(ConfigMap[:sitedir]), "Gems")
-        else
-          File.join(ConfigMap[:libdir], 'ruby', 'gems', ConfigMap[:ruby_version])
-        end
+    def self.path
+      @gem_path ||= nil
+      unless @gem_path
+        paths = [ENV['GEM_PATH']]
+        paths << APPLE_GEM_HOME if defined? APPLE_GEM_HOME
+        set_paths(paths.compact.join(File::PATH_SEPARATOR))
       end
+      @gem_path
+    end
 
-      def dir
-        @gem_home ||= nil
-        set_home(ENV['GEM_HOME'] || default_dir) unless @gem_home
-        @gem_home
+    def self.post_install(&hook)
+      @post_install_hooks << hook
+    end
+
+    def self.post_uninstall(&hook)
+      @post_uninstall_hooks << hook
+    end
+
+    def self.pre_install(&hook)
+      @pre_install_hooks << hook
+    end
+
+    def self.pre_uninstall(&hook)
+      @pre_uninstall_hooks << hook
+    end
+
+    def self.set_home(home)
+      @gem_home = home
+      ensure_gem_subdirectories(@gem_home)
+    end
+
+    def self.set_paths(gpaths)
+      if gpaths
+        @gem_path = gpaths.split(File::PATH_SEPARATOR)
+        @gem_path << Gem.dir
+      else
+        @gem_path = [Gem.dir]
       end
+      @gem_path.uniq!
+      @gem_path.each do |gp| ensure_gem_subdirectories(gp) end
+    end
 
-      def path
-        @gem_path ||= nil
-        unless @gem_path
-          paths = [ENV['GEM_PATH']]
-          paths << APPLE_GEM_HOME if defined? APPLE_GEM_HOME
-          set_paths(paths.compact.join(File::PATH_SEPARATOR))
-        end
-        @gem_path
+    def self.ensure_gem_subdirectories(path)
+    end
+
+  
+    @post_install_hooks   ||= []
+    @post_uninstall_hooks ||= []
+    @pre_uninstall_hooks  ||= []
+    @pre_install_hooks    ||= []
+  
+    ##
+    # An Array of the default sources that come with RubyGems
+  
+    def self.default_sources
+      %w[http://gems.rubyforge.org/]
+    end
+  
+    ##
+    # Default home directory path to be used if an alternate value is not
+    # specified in the environment
+  
+    def self.default_dir
+      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
+        File.join(ConfigMap[:libdir], ruby_engine, 'gems',
+                  ConfigMap[:ruby_version])
       end
+    end
+  
+    ##
+    # Path for gems in the user's home directory
+  
+    def self.user_dir
+      File.join(Gem.user_home, '.gem', ruby_engine,
+                ConfigMap[:ruby_version])
+    end
+  
+    ##
+    # Default gem load path
+  
+    def self.default_path
+      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
+      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
+  
+    ##
+    # The default directory for binaries
+  
+    def self.default_bindir
+      if defined? RUBY_FRAMEWORK_VERSION then # mac framework support
+        '/usr/bin'
+      else # generic install
+        ConfigMap[:bindir]
+      end
+    end
+  
+    ##
+    # The default system-wide source info cache directory
+  
+    def self.default_system_source_cache_dir
+      File.join Gem.dir, 'source_cache'
+    end
+  
+    ##
+    # The default user-specific source info cache directory
+  
+    def self.default_user_source_cache_dir
+      File.join Gem.user_home, '.gem', 'source_cache'
+    end
+  
+    ##
+    # A wrapper around RUBY_ENGINE const that may not be defined
+  
+    def self.ruby_engine
+      if defined? RUBY_ENGINE then
+        RUBY_ENGINE
+      else
+        'ruby'
+      end
+    end
+  
+  
 
-      # Set the Gem home directory (as reported by +dir+).
-      def set_home(home)
-        @gem_home = home
-        ensure_gem_subdirectories(@gem_home)
+    # Methods before this line will be removed when QuickLoader is replaced
+    # with the real RubyGems
+
+    GEM_PRELUDE_METHODS = Gem.methods(false)
+
+    begin
+      verbose, debug = $VERBOSE, $DEBUG
+      $VERBOSE = $DEBUG = nil
+
+      begin
+        require 'rubygems/defaults/operating_system'
+      rescue LoadError
       end
 
-      def set_paths(gpaths)
-        if gpaths
-          @gem_path = gpaths.split(File::PATH_SEPARATOR)
-          @gem_path << Gem.dir
-        else
-          @gem_path = [Gem.dir]
+      if defined?(RUBY_ENGINE) then
+        begin
+          require "rubygems/defaults/#{RUBY_ENGINE}"
+        rescue LoadError
         end
-        @gem_path.uniq!
-        @gem_path.each do |gp| ensure_gem_subdirectories(gp) end
       end
-
-      def ensure_gem_subdirectories(path)
-      end
-
+    ensure
+      $VERBOSE, $DEBUG = verbose, debug
     end
 
     module QuickLoader
 
-      class << self
-        def load_full_rubygems_library
-          class << Gem
-            Gem.methods(false).each do |method_name|
-              undef_method method_name
-            end
+      def self.load_full_rubygems_library
+        class << Gem
+          Gem::GEM_PRELUDE_METHODS.each do |method_name|
+            undef_method method_name
           end
+        end
 
-          Kernel.module_eval do
-            undef_method :gem if method_defined? :gem
-          end
+        Kernel.module_eval do
+          undef_method :gem if method_defined? :gem
+        end
 
-          $".delete File.join(Gem::ConfigMap[:libdir], 'ruby',
-                              Gem::ConfigMap[:ruby_version], 'rubygems.rb')
+        $".delete File.join(Gem::ConfigMap[:libdir],
+                            Gem::ConfigMap[:ruby_install_name],
+                            Gem::ConfigMap[:ruby_version], 'rubygems.rb')
 
-          require 'rubygems'
-        end
+        require 'rubygems'
       end
 
       GemPaths = {}
@@ -103,7 +230,7 @@
       def push_gem_version_on_load_path(gem_name, *version_requirements)
         if version_requirements.empty?
           unless GemPaths.has_key?(gem_name)
-            raise LoadError.new("Could not find RubyGem #{gem_name} (>= 0)\n") 
+            raise LoadError.new("Could not find RubyGem #{gem_name} (>= 0)\n")
           end
 
           # highest version gems already active
@@ -119,7 +246,7 @@
 
           if requirement == ">" || requirement == ">="
             if (GemVersions[gem_name] <=> Gem.calculate_integers_for_gem_version(version)) >= 0
-              return false 
+              return false
             end
           elsif requirement == "~>"
             loaded_version = GemVersions[gem_name]
@@ -167,12 +294,16 @@
 
         require_paths = []
 
-        GemPaths.values.each do |path|
-          if File.exist?(File.join(path, ".require_paths"))
-            require_paths.concat(File.read(File.join(path, ".require_paths")).split.map {|require_path| File.join(path, require_path)})
+        GemPaths.each_value do |path|
+          if File.exist?(file = File.join(path, ".require_paths")) then
+            paths = File.read(file).split.map do |require_path|
+              File.join path, require_path
+            end
+
+            require_paths.concat paths
           else
-            require_paths << File.join(path, "bin") if File.exist?(File.join(path, "bin"))
-            require_paths << File.join(path, "lib") if File.exist?(File.join(path, "lib"))
+            require_paths << file if File.exist?(file = File.join(path, "bin"))
+            require_paths << file if File.exist?(file = File.join(path, "lib"))
           end
         end
 
@@ -208,7 +339,7 @@
 
   begin
     Gem.push_all_highest_version_gems_on_load_path
-    $" << File.join(Gem::ConfigMap[:libdir], "ruby",
+    $" << File.join(Gem::ConfigMap[:libdir], Gem::ConfigMap[:ruby_install_name],
                     Gem::ConfigMap[:ruby_version], "rubygems.rb")
   rescue Exception => e
     puts "Error loading gem paths on load path in gem_prelude"

Modified: MacRuby/trunk/lib/rubygems/builder.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/builder.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/builder.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
-  
-    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"
+  # spec:: [Gem::Specification] The specification instance
 
-      @spec = spec
-    end
+  def initialize(spec)
+    require "yaml"
+    require "rubygems/package"
+    require "rubygems/security"
 
-    ##
-    # 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
-    
-    def success
-      <<-EOM
+    @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
+
+  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

Modified: MacRuby/trunk/lib/rubygems/command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
+

Modified: MacRuby/trunk/lib/rubygems/command_manager.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/command_manager.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/command_manager.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
-    
-    # Return the authoritative instance of the command manager.
-    def self.instance
-      @command_manager ||= CommandManager.new
+class Gem::CommandManager
+
+  include Gem::UserInteraction
+
+  ##
+  # Return the authoritative instance of the command manager.
+
+  def self.instance
+    @command_manager ||= new
+  end
+
+  ##
+  # 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
+
+  ##
+  # 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)
     end
-    
-    # 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
-    
-    # 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 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
+    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)
-    rescue Interrupt
-      alert_error "Interrupted"
-      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
-    
-    private
+    command_names.select { |n| cmd_name == n[0, len] }
+  end
 
-    def load_and_instantiate(command_name)
-      command_name = command_name.to_s
-      retried = false
+  private
 
-      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
+  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
     end
   end
-end 
+
+end
+

Modified: MacRuby/trunk/lib/rubygems/commands/check_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/check_command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/commands/check_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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"
+        else
+          say "#{key} is error-free" if options[:verbose]
         end
         say
       end

Modified: MacRuby/trunk/lib/rubygems/commands/cleanup_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/cleanup_command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/commands/cleanup_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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}"

Modified: MacRuby/trunk/lib/rubygems/commands/contents_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/contents_command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/commands/contents_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Modified: MacRuby/trunk/lib/rubygems/commands/generate_index_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/generate_index_command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/commands/generate_index_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Modified: MacRuby/trunk/lib/rubygems/commands/install_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/install_command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/commands/install_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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 => false,
-      :generate_ri   => false,
+      :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

Modified: MacRuby/trunk/lib/rubygems/commands/query_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/query_command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/commands/query_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Modified: MacRuby/trunk/lib/rubygems/commands/rdoc_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/rdoc_command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/commands/rdoc_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
+

Modified: MacRuby/trunk/lib/rubygems/commands/search_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/search_command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/commands/search_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
+

Modified: MacRuby/trunk/lib/rubygems/commands/server_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/server_command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/commands/server_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Added: MacRuby/trunk/lib/rubygems/commands/setup_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/setup_command.rb	                        (rev 0)
+++ MacRuby/trunk/lib/rubygems/commands/setup_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -0,0 +1,363 @@
+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::Version.new '1.8.3'
+
+    unless Gem.ruby_version > required_version then
+      alert_error "Ruby version > #{required_version} required, 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
+    @verbose = Gem.configuration.really_verbose
+
+    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
+
+    say "RubyGems #{Gem::VERSION} installed"
+
+    install_rdoc
+
+    say
+    if @verbose then
+      say "-" * 78
+      say
+    end
+
+    release_notes = File.join Dir.pwd, 'History.txt'
+
+    release_notes = if File.exist? release_notes then
+                      open release_notes do |io|
+                        text = io.gets '==='
+                        text << io.gets('===')
+                        text[0...-3]
+                      end
+                    else
+                      "Oh-no! Unable to find release notes!"
+                    end
+
+    say release_notes
+
+    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" if @verbose
+
+    @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
+ at 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" if @verbose
+
+    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" if @verbose
+      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}" if @verbose
+        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}" if @verbose
+        run_rdoc '--op', rdoc_dir
+      end
+    elsif @verbose then
+      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" if Gem.configuration.really_verbose
+      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
+

Modified: MacRuby/trunk/lib/rubygems/commands/sources_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/sources_command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/commands/sources_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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

Modified: MacRuby/trunk/lib/rubygems/commands/specification_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/specification_command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/commands/specification_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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

Modified: MacRuby/trunk/lib/rubygems/commands/uninstall_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/uninstall_command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/commands/uninstall_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
+

Modified: MacRuby/trunk/lib/rubygems/commands/unpack_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/unpack_command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/commands/unpack_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Modified: MacRuby/trunk/lib/rubygems/commands/update_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/update_command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/commands/update_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 
@@ -48,9 +48,6 @@
     hig = {}
 
     if options[:system] then
-      # XXX We can't allow people to self-update RubyGems at this point.
-      raise "This version of RubyGems cannot be self-updated."
-
       say "Updating RubyGems"
 
       unless options[:args].empty? then
@@ -83,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
 
@@ -109,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

Modified: MacRuby/trunk/lib/rubygems/commands/which_command.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/commands/which_command.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/commands/which_command.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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

Modified: MacRuby/trunk/lib/rubygems/config_file.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/config_file.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/config_file.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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.
@@ -30,14 +29,21 @@
 
   PLATFORM_DEFAULTS = {}
 
-  system_config_path = 
+  system_config_path =
     begin
       require 'Win32API'
 
       CSIDL_COMMON_APPDATA = 0x0023
       path = 0.chr * 260
-      SHGetFolderPath = Win32API.new 'shell32', 'SHGetFolderPath', 'LLLLP', 'L'
-      SHGetFolderPath.call 0, CSIDL_COMMON_APPDATA, 0, 1, path
+      if RUBY_VERSION > '1.9' then
+        SHGetFolderPath = Win32API.new 'shell32', 'SHGetFolderPath', 'PLPLP',
+                                       'L', :stdcall
+        SHGetFolderPath.call nil, CSIDL_COMMON_APPDATA, nil, 1, path
+      else
+        SHGetFolderPath = Win32API.new 'shell32', 'SHGetFolderPath', 'LLLLP',
+                                       'L'
+        SHGetFolderPath.call 0, CSIDL_COMMON_APPDATA, 0, 1, path
+      end
 
       path.strip
     rescue LoadError
@@ -45,7 +51,7 @@
     end
 
   SYSTEM_WIDE_CONFIG_FILE = File.join system_config_path, 'gemrc'
-  
+
   # List of arguments supplied to the config file object.
   attr_reader :args
 

Modified: MacRuby/trunk/lib/rubygems/defaults.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/defaults.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/defaults.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 
   ##

Modified: MacRuby/trunk/lib/rubygems/dependency.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/dependency.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/dependency.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Modified: MacRuby/trunk/lib/rubygems/dependency_installer.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/dependency_installer.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/dependency_installer.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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

Modified: MacRuby/trunk/lib/rubygems/dependency_list.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/dependency_list.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/dependency_list.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Modified: MacRuby/trunk/lib/rubygems/digest/digest_adapter.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/digest/digest_adapter.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/digest/digest_adapter.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -1,40 +1,49 @@
-#!/usr/bin/env ruby
 #--
 # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
 # All rights reserved.
 # See LICENSE.txt for permissions.
 #++
 
-module Gem
-  
-  # There is an incompatibility between the way Ruby 1.8.5 and 1.8.6 
-  # handles digests. This DigestAdapter will take a pre-1.8.6 digest 
-  # and adapt it to the 1.8.6 API.
-  #
-  # Note that only the digest and hexdigest methods are adapted, 
-  # since these are the only functions used by Gems.
-  #
-  class DigestAdapter
+require 'rubygems'
 
-    # Initialize a digest adapter.
-    def initialize(digest_class)
-      @digest_class = digest_class
-    end
+##
+# There is an incompatibility between the way Ruby 1.8.5 and 1.8.6 handles
+# digests. This DigestAdapter will take a pre-1.8.6 digest and adapt it to
+# the 1.8.6 API.
+#
+# Note that only the digest and hexdigest methods are adapted, since these
+# are the only functions used by RubyGems.
 
-    # Return a new digester.  Since we are only implementing the stateless
-    # methods, we will return ourself as the instance.
-    def new
-      self
-    end
+class Gem::DigestAdapter
 
-    # Return the digest of +string+ as a hex string.
-    def hexdigest(string)
-      @digest_class.new(string).hexdigest
-    end
+  ##
+  # Initialize a digest adapter.
 
-    # Return the digest of +string+ as a binary string.
-    def digest(string)
-      @digest_class.new(string).digest
-    end
+  def initialize(digest_class)
+    @digest_class = digest_class
   end
-end
\ No newline at end of file
+
+  ##
+  # Return a new digester.  Since we are only implementing the stateless
+  # methods, we will return ourself as the instance.
+
+  def new
+    self
+  end
+
+  ##
+  # Return the digest of +string+ as a hex string.
+
+  def hexdigest(string)
+    @digest_class.new(string).hexdigest
+  end
+
+  ##
+  # Return the digest of +string+ as a binary string.
+
+  def digest(string)
+    @digest_class.new(string).digest
+  end
+
+end
+

Modified: MacRuby/trunk/lib/rubygems/digest/sha1.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/digest/sha1.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/digest/sha1.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -7,11 +7,16 @@
 
 require 'digest/sha1'
 
+# :stopdoc:
 module Gem
+
   if RUBY_VERSION >= '1.8.6'
     SHA1 = Digest::SHA1
   else
     require 'rubygems/digest/digest_adapter'
     SHA1 = DigestAdapter.new(Digest::SHA1)
   end
-end
\ No newline at end of file
+
+end
+# :startdoc:
+

Modified: MacRuby/trunk/lib/rubygems/digest/sha2.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/digest/sha2.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/digest/sha2.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -7,11 +7,16 @@
 
 require 'digest/sha2'
 
+# :stopdoc:
 module Gem
+
   if RUBY_VERSION >= '1.8.6'
     SHA256 = Digest::SHA256
   else
     require 'rubygems/digest/digest_adapter'
     SHA256 = DigestAdapter.new(Digest::SHA256)
   end
+
 end
+# :startdoc:
+

Modified: MacRuby/trunk/lib/rubygems/doc_manager.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/doc_manager.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/doc_manager.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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

Modified: MacRuby/trunk/lib/rubygems/exceptions.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/exceptions.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/exceptions.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -1,5 +1,3 @@
-require 'rubygems'
-
 ##
 # Base exception class for RubyGems.  All exception raised by RubyGems are a
 # subclass of this one.

Modified: MacRuby/trunk/lib/rubygems/ext/builder.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/ext/builder.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/ext/builder.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -4,8 +4,6 @@
 # See LICENSE.txt for permissions.
 #++
 
-require 'rubygems/ext'
-
 class Gem::Ext::Builder
 
   def self.class_name

Modified: MacRuby/trunk/lib/rubygems/ext/configure_builder.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/ext/configure_builder.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/ext/configure_builder.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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

Modified: MacRuby/trunk/lib/rubygems/ext/ext_conf_builder.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/ext/ext_conf_builder.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/ext/ext_conf_builder.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Modified: MacRuby/trunk/lib/rubygems/ext/rake_builder.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/ext/rake_builder.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/ext/rake_builder.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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

Modified: MacRuby/trunk/lib/rubygems/format.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/format.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/format.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
-  
-    ##
-    # 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
+  # gem:: [String] The file name of the gem
+  #
+  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, 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
 
-      unless File.exist?(file_path)
-        raise Gem::Exception, "Cannot load gem at [#{file_path}] in #{Dir.pwd}"
+    # check for old version gem
+    if File.read(file_path, 20).include?("MD5SUM =")
+      require 'rubygems/old_format'
+
+      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
+

Modified: MacRuby/trunk/lib/rubygems/gem_openssl.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/gem_openssl.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/gem_openssl.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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:
+

Modified: MacRuby/trunk/lib/rubygems/gem_path_searcher.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/gem_path_searcher.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/gem_path_searcher.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Modified: MacRuby/trunk/lib/rubygems/gem_runner.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/gem_runner.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/gem_runner.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
+

Deleted: MacRuby/trunk/lib/rubygems/indexer/abstract_index_builder.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/indexer/abstract_index_builder.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/indexer/abstract_index_builder.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -1,88 +0,0 @@
-require 'zlib'
-
-require 'rubygems/indexer'
-
-# Abstract base class for building gem indicies.  Uses the template pattern
-# with subclass specialization in the +begin_index+, +end_index+ and +cleanup+
-# methods.
-class Gem::Indexer::AbstractIndexBuilder
-
-  # Directory to put index files in
-  attr_reader :directory
-
-  # File name of the generated index
-  attr_reader :filename
-
-  # List of written files/directories to move into production
-  attr_reader :files
-
-  def initialize(filename, directory)
-    @filename = filename
-    @directory = directory
-    @files = []
-  end
-
-  ##
-  # Build a Gem index.  Yields to block to handle the details of the
-  # actual building.  Calls +begin_index+, +end_index+ and +cleanup+ at
-  # appropriate times to customize basic operations.
-
-  def build
-    FileUtils.mkdir_p @directory unless File.exist? @directory
-    raise "not a directory: #{@directory}" unless File.directory? @directory
-
-    file_path = File.join @directory, @filename
-
-    @files << @filename
-
-    File.open file_path, "wb" do |file|
-      @file = file
-      start_index
-      yield
-      end_index
-    end
-
-    cleanup
-  ensure
-    @file = nil
-  end
-
-  ##
-  # Compress the given file.
-
-  def compress(filename, ext="rz")
-    data = open filename, 'rb' do |fp| fp.read end
-
-    zipped = zip data
-
-    File.open "#{filename}.#{ext}", "wb" do |file|
-      file.write zipped
-    end
-  end
-
-  # Called immediately before the yield in build.  The index file is open and
-  # available as @file.
-  def start_index
-  end
-
-  # Called immediately after the yield in build.  The index file is still open
-  # and available as @file.
-  def end_index
-  end
-
-  # Called from within builder after the index file has been closed.
-  def cleanup
-  end
-
-  # Return an uncompressed version of a compressed string.
-  def unzip(string)
-    Zlib::Inflate.inflate(string)
-  end
-
-  # Return a compressed version of the given string.
-  def zip(string)
-    Zlib::Deflate.deflate(string)
-  end
-
-end
-

Deleted: MacRuby/trunk/lib/rubygems/indexer/latest_index_builder.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/indexer/latest_index_builder.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/indexer/latest_index_builder.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -1,35 +0,0 @@
-require 'rubygems/indexer'
-
-##
-# Construct the latest Gem index file.
-
-class Gem::Indexer::LatestIndexBuilder < Gem::Indexer::AbstractIndexBuilder
-
-  def start_index
-    super
-
-    @index = Gem::SourceIndex.new
-  end
-
-  def end_index
-    super
-
-    latest = @index.latest_specs.sort.map { |spec| spec.original_name }
-
-    @file.write latest.join("\n")
-  end
-
-  def cleanup
-    super
-
-    compress @file.path
-
-    @files.delete 'latest_index' # HACK installed via QuickIndexBuilder :/
-  end
-
-  def add(spec)
-    @index.add_spec(spec)
-  end
-
-end
-

Deleted: MacRuby/trunk/lib/rubygems/indexer/marshal_index_builder.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/indexer/marshal_index_builder.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/indexer/marshal_index_builder.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -1,17 +0,0 @@
-require 'rubygems/indexer'
-
-# Construct the master Gem index file.
-class Gem::Indexer::MarshalIndexBuilder < Gem::Indexer::MasterIndexBuilder
-  def end_index
-    gems = {}
-    index = Gem::SourceIndex.new
-
-    @index.each do |name, gemspec|
-      gems[gemspec.original_name] = gemspec
-    end
-
-    index.instance_variable_get(:@gems).replace gems
-
-    @file.write index.dump
-  end
-end

Deleted: MacRuby/trunk/lib/rubygems/indexer/master_index_builder.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/indexer/master_index_builder.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/indexer/master_index_builder.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -1,54 +0,0 @@
-require 'rubygems/indexer'
-
-##
-# Construct the master Gem index file.
-
-class Gem::Indexer::MasterIndexBuilder < Gem::Indexer::AbstractIndexBuilder
-
-  def start_index
-    super
-    @index = Gem::SourceIndex.new
-  end
-
-  def end_index
-    super
-
-    @file.puts "--- !ruby/object:#{@index.class}"
-    @file.puts "gems:"
-
-    gems = @index.sort_by { |name, gemspec| gemspec.sort_obj }
-    gems.each do |name, gemspec|
-      yaml = gemspec.to_yaml.gsub(/^/, '    ')
-      yaml = yaml.sub(/\A    ---/, '') # there's a needed extra ' ' here
-      @file.print "  #{gemspec.original_name}:"
-      @file.puts yaml
-    end
-  end
-
-  def cleanup
-    super
-
-    index_file_name = File.join @directory, @filename
-
-    compress index_file_name, "Z"
-    paranoid index_file_name, "#{index_file_name}.Z"
-
-    @files << "#{@filename}.Z"
-  end
-
-  def add(spec)
-    @index.add_spec(spec)
-  end
-
-  private
-
-  def paranoid(path, compressed_path)
-    data = Gem.read_binary path
-    compressed_data = Gem.read_binary compressed_path
-
-    if data != unzip(compressed_data) then
-      raise "Compressed file #{compressed_path} does not match uncompressed file #{path}"
-    end
-  end
-
-end

Deleted: MacRuby/trunk/lib/rubygems/indexer/quick_index_builder.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/indexer/quick_index_builder.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/indexer/quick_index_builder.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -1,50 +0,0 @@
-require 'rubygems/indexer'
-
-##
-# Construct a quick index file and all of the individual specs to support
-# incremental loading.
-
-class Gem::Indexer::QuickIndexBuilder < Gem::Indexer::AbstractIndexBuilder
-
-  def initialize(filename, directory)
-    directory = File.join directory, 'quick'
-
-    super filename, directory
-  end
-
-  def cleanup
-    super
-
-    quick_index_file = File.join @directory, @filename
-    compress quick_index_file
-
-    # the complete quick index is in a directory, so move it as a whole
-    @files.delete 'index'
-    @files << 'quick'
-  end
-
-  def add(spec)
-    @file.puts spec.original_name
-    add_yaml(spec)
-    add_marshal(spec)
-  end
-
-  def add_yaml(spec)
-    fn = File.join @directory, "#{spec.original_name}.gemspec.rz"
-    zipped = zip spec.to_yaml
-    File.open fn, "wb" do |gsfile| gsfile.write zipped end
-  end
-
-  def add_marshal(spec)
-    # HACK why does this not work in #initialize?
-    FileUtils.mkdir_p File.join(@directory, "Marshal.#{Gem.marshal_version}")
-
-    fn = File.join @directory, "Marshal.#{Gem.marshal_version}",
-                   "#{spec.original_name}.gemspec.rz"
-
-    zipped = zip Marshal.dump(spec)
-    File.open fn, "wb" do |gsfile| gsfile.write zipped end
-  end
-
-end
-

Modified: MacRuby/trunk/lib/rubygems/indexer.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/indexer.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/indexer.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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.released_gems.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.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.released_specs.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
@@ -294,7 +534,7 @@
     FileUtils.rm_rf @directory
   end
 
-   ##
+  ##
   # Zlib::GzipWriter wrapper that gzips +filename+ on disk.
 
   def gzip(filename)
@@ -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.released_gems, @dest_specs_index, @specs_index
+      update_specs_index index.released_gems, @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
 

Modified: MacRuby/trunk/lib/rubygems/install_update_options.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/install_update_options.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/install_update_options.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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

Modified: MacRuby/trunk/lib/rubygems/installer.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/installer.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/installer.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -13,13 +13,18 @@
 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
 
@@ -98,17 +103,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
@@ -119,7 +124,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
@@ -129,7 +134,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
@@ -430,7 +435,7 @@
 end
 
 gem '#{@spec.name}', version
-load '#{bin_file_name}'
+load Gem.bin_path('#{@spec.name}', '#{bin_file_name}', version)
 TEXT
   end
 
@@ -441,10 +446,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
 
@@ -454,7 +459,6 @@
 
   def build_extensions
     return if @spec.extensions.empty?
-    raise "MacRuby does not support native extensions yet. Be patient :-)"
     say "Building native extensions.  This could take a while..."
     start_dir = Dir.pwd
     dest_path = File.join @gem_dir, @spec.require_paths.first
@@ -530,6 +534,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|

Modified: MacRuby/trunk/lib/rubygems/local_remote_options.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/local_remote_options.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/local_remote_options.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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]

Modified: MacRuby/trunk/lib/rubygems/old_format.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/old_format.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/old_format.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
-  
-    ##
-    # 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
+  # gem:: [String] The file name of the gem
+
+  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
-    
-    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
+  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
-    
-    ##
-    # 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
+
+  ##
+  # 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
+

Modified: MacRuby/trunk/lib/rubygems/package/f_sync_dir.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package/f_sync_dir.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/package/f_sync_dir.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -3,8 +3,6 @@
 # See LICENSE.txt for additional licensing information.
 #--
 
-require 'rubygems/package'
-
 module Gem::Package::FSyncDir
 
   private

Modified: MacRuby/trunk/lib/rubygems/package/tar_header.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package/tar_header.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/package/tar_header.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
@@ -233,7 +253,7 @@
     ]
 
     header = header.pack PACK_FORMAT
-                  
+
     header << ("\0" * ((512 - header.size) % 512))
   end
 

Modified: MacRuby/trunk/lib/rubygems/package/tar_input.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package/tar_input.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/package/tar_input.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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

Modified: MacRuby/trunk/lib/rubygems/package/tar_output.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package/tar_output.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/package/tar_output.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Modified: MacRuby/trunk/lib/rubygems/package/tar_reader/entry.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package/tar_reader/entry.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/package/tar_reader/entry.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Modified: MacRuby/trunk/lib/rubygems/package/tar_reader.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package/tar_reader.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/package/tar_reader.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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'
+

Modified: MacRuby/trunk/lib/rubygems/package/tar_writer.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package/tar_writer.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/package/tar_writer.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Added: MacRuby/trunk/lib/rubygems/package_task.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/package_task.rb	                        (rev 0)
+++ MacRuby/trunk/lib/rubygems/package_task.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
+

Modified: MacRuby/trunk/lib/rubygems/platform.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/platform.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/platform.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Modified: MacRuby/trunk/lib/rubygems/remote_fetcher.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/remote_fetcher.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/remote_fetcher.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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?
@@ -231,27 +253,28 @@
   # read from the filesystem instead.
 
   def open_uri_or_path(uri, last_modified = nil, head = false, depth = 0)
-    if RUBY_ENGINE == 'macruby'
-      # XXX we are taking a _much faster_ code path here, this change should be
-      # removed once we re-implement the IO subsystem (and therefore Net::HTTP)
-      # on top of CF.
-      framework 'Foundation'
-      url = NSURL.URLWithString(uri.to_s)
-      data = NSMutableData.dataWithContentsOfURL(url)
-      if data.nil?
-        raise Gem::RemoteFetcher::FetchError, "error when fetching data from #{uri}"
-      end
-      string = String.__new_bytestring__(data)
-      #block.call(string) if block
-      return string
-    end
     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
 
@@ -340,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
 

Modified: MacRuby/trunk/lib/rubygems/require_paths_builder.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/require_paths_builder.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/require_paths_builder.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
+

Modified: MacRuby/trunk/lib/rubygems/requirement.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/requirement.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/requirement.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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)
@@ -80,11 +78,6 @@
     @version = nil   # Avoid warnings.
   end
 
-  def yaml_initialize(tags, values)
-    @requirements = values['requirements']
-    @version = nil
-  end
-  
   ##
   # Marshal raw requirements, rather than the full object
 
@@ -104,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
@@ -134,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')]

Deleted: MacRuby/trunk/lib/rubygems/rubygems_version.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/rubygems_version.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/rubygems_version.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -1,6 +0,0 @@
-# DO NOT EDIT
-# This file is auto-generated by build scripts.
-# See:  rake update_version
-module Gem
-  RubyGemsVersion = '1.3.1'
-end

Modified: MacRuby/trunk/lib/rubygems/server.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/server.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/server.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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,

Modified: MacRuby/trunk/lib/rubygems/source_index.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/source_index.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/source_index.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
@@ -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,23 +108,38 @@
         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 = {}
+    specifications.each{ |full_name, spec| add_spec spec }
     @spec_dirs = nil
   end
 
+  # TODO: remove method
+  def all_gems
+    @gems
+  end
+
+  def prerelease_gems
+    @gems.reject{ |name, gem| !gem.version.prerelease? }
+  end
+
+  def released_gems
+    @gems.reject{ |name, gem| gem.version.prerelease? }
+  end
+
   ##
   # Reconstruct the source index from the specifications in +spec_dirs+.
 
@@ -140,8 +159,8 @@
   end
 
   ##
-  # Returns an Array specifications for the latest versions of each gem in
-  # this index.
+  # Returns an Array specifications for the latest released versions
+  # of each gem in this index.
 
   def latest_specs
     result = Hash.new { |h,k| h[k] = [] }
@@ -152,6 +171,7 @@
       curr_ver = spec.version
       prev_ver = latest.key?(name) ? latest[name].version : nil
 
+      next if curr_ver.prerelease?
       next unless prev_ver.nil? or curr_ver >= prev_ver or
                   latest[name].platform != Gem::Platform::RUBY
 
@@ -170,14 +190,32 @@
       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
+
+  ##
+  # An array including only the released gemspecs
+
+  def released_specs
+    released_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.
+    @gems[name] = gem_spec
   end
 
   ##
@@ -193,7 +231,7 @@
   # Remove a gem specification named +full_name+.
 
   def remove_spec(full_name)
-    @gems.delete(full_name)
+    @gems.delete full_name
   end
 
   ##
@@ -238,7 +276,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 +295,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 +320,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
@@ -545,15 +583,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:
 

Modified: MacRuby/trunk/lib/rubygems/source_info_cache_entry.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/source_info_cache_entry.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/source_info_cache_entry.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Modified: MacRuby/trunk/lib/rubygems/spec_fetcher.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/spec_fetcher.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/spec_fetcher.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -1,6 +1,6 @@
 require 'zlib'
+require 'fileutils'
 
-require 'rubygems'
 require 'rubygems/remote_fetcher'
 require 'rubygems/user_interaction'
 
@@ -22,10 +22,15 @@
   attr_reader :latest_specs # :nodoc:
 
   ##
-  # Cache of all spces
+  # Cache of all released specs
 
   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
@@ -55,11 +61,12 @@
 
   ##
   # Fetch specs matching +dependency+.  If +all+ is true, all matching
-  # versions are returned.  If +matching_platform+ is false, all platforms are
-  # returned.
+  # (released) versions are returned.  If +matching_platform+ is
+  # false, all platforms are 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]
@@ -106,14 +113,14 @@
   end
 
   ##
-  # Find spec names that match +dependency+.  If +all+ is true, all matching
-  # versions are returned.  If +matching_platform+ is false, gems for all
-  # platforms are returned.
+  # Find spec names that match +dependency+.  If +all+ is true, all
+  # matching released 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,27 +162,42 @@
 
   ##
   # 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 released 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
+      list[source_uri] = cache[source_uri]
+    end
 
-        cache[source_uri] = specs
-        list[source_uri] = specs
+    if type == :all
+      list.values.map do |gems|
+        gems.reject! { |g| g[1].prerelease? }
       end
     end
 
@@ -206,8 +228,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

Modified: MacRuby/trunk/lib/rubygems/specification.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/specification.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/specification.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -4,1258 +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
+  # Allows deinstallation of gems with legacy platforms.
+
+  attr_accessor :original_platform # :nodoc:
+
+  ##
+  # The the version number of a specification that does not specify one
+  # (i.e. RubyGems 0.7 or earlier).
+
+  NONEXISTENT_SPECIFICATION_VERSION = -1
+
+  ##
+  # 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.
   #
-  # 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.
+  # NOTE RubyGems < 1.2 cannot load specification versions > 2.
 
-  class Specification
+  CURRENT_SPECIFICATION_VERSION = 3
 
-    ##
-    # Allows deinstallation of gems with legacy platforms.
+  ##
+  # An informal list of changes to the specification.  The highest-valued
+  # key should be equal to the CURRENT_SPECIFICATION_VERSION.
 
-    attr_accessor :original_platform # :nodoc:
+  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'
+    ]
+  }
 
-    ##
-    # The the version number of a specification that does not specify one
-    # (i.e. RubyGems 0.7 or earlier).
+  # :stopdoc:
+  MARSHAL_FIELDS = { -1 => 16, 1 => 16, 2 => 16, 3 => 17 }
 
-    NONEXISTENT_SPECIFICATION_VERSION = -1
+  now = Time.at(Time.now.to_i)
+  TODAY = now - ((now.to_i + now.gmt_offset) % 86400)
+  # :startdoc:
 
-    ##
-    # 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.
+  ##
+  # Optional block used to gather newly defined instances.
 
-    CURRENT_SPECIFICATION_VERSION = 2
+  @@gather = nil
 
-    ##
-    # An informal list of changes to the specification.  The highest-valued
-    # key should be equal to the CURRENT_SPECIFICATION_VERSION.
+  ##
+  # List of attribute names: [:name, :version, ...]
 
-    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',
-      ],
-    }
+  @@required_attributes = []
 
-    # :stopdoc:
-    MARSHAL_FIELDS = { -1 => 16, 1 => 16, 2 => 16 }
+  ##
+  # List of _all_ attributes and default values:
+  #
+  #   [[:name, nil],
+  #    [:bindir, 'bin'],
+  #    ...]
 
-    now = Time.at(Time.now.to_i)
-    TODAY = now - ((now.to_i + now.gmt_offset) % 86400)
-    # :startdoc:
+  @@attributes = []
 
-    ##
-    # List of Specification instances.
+  @@nil_attributes = []
+  @@non_nil_attributes = [:@original_platform]
 
-    @@list = []
+  ##
+  # List of array attributes
 
-    ##
-    # Optional block used to gather newly defined instances.
+  @@array_attributes = []
 
-    @@gather = nil
+  ##
+  # Map of attribute names to default values.
 
-    ##
-    # List of attribute names: [:name, :version, ...]
-    @@required_attributes = []
+  @@default_value = {}
 
-    ##
-    # List of _all_ attributes and default values:
-    #
-    #   [[:name, nil],
-    #    [:bindir, 'bin'],
-    #    ...]
+  ##
+  # Names of all specification attributes
 
-    @@attributes = []
+  def self.attribute_names
+    @@attributes.map { |name, default| name }
+  end
 
-    @@nil_attributes = []
-    @@non_nil_attributes = [:@original_platform]
+  ##
+  # Default values for specification attributes
 
-    ##
-    # List of array attributes
+  def self.attribute_defaults
+    @@attributes.dup
+  end
 
-    @@array_attributes = []
+  ##
+  # The default value for specification attribute +name+
 
-    ##
-    # Map of attribute names to default values.
+  def self.default_value(name)
+    @@default_value[name]
+  end
 
-    @@default_value = {}
+  ##
+  # Required specification attributes
 
-    ##
-    # Names of all specification attributes
+  def self.required_attributes
+    @@required_attributes.dup
+  end
 
-    def self.attribute_names
-      @@attributes.map { |name, default| name }
-    end
+  ##
+  # Is +name+ a required attribute?
 
-    ##
-    # Default values for specification attributes
+  def self.required_attribute?(name)
+    @@required_attributes.include? name.to_sym
+  end
 
-    def self.attribute_defaults
-      @@attributes.dup
-    end
+  ##
+  # Specification attributes that are arrays (appendable and so-forth)
 
-    ##
-    # The default value for specification attribute +name+
+  def self.array_attributes
+    @@array_attributes.dup
+  end
 
-    def self.default_value(name)
-      @@default_value[name]
+  ##
+  # 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.attribute(name, default=nil)
+    ivar_name = "@#{name}".intern
+    if default.nil? then
+      @@nil_attributes << ivar_name
+    else
+      @@non_nil_attributes << [ivar_name, default]
     end
 
-    ##
-    # Required specification attributes
+    @@attributes << [name, default]
+    @@default_value[name] = default
+    attr_accessor(name)
+  end
 
-    def self.required_attributes
-      @@required_attributes.dup
-    end
+  ##
+  # Same as :attribute, but ensures that values assigned to the attribute
+  # are array values by applying :to_a to the value.
 
-    ##
-    # Is +name+ a required attribute?
+  def self.array_attribute(name)
+    @@non_nil_attributes << ["@#{name}".intern, []]
 
-    def self.required_attribute?(name)
-      @@required_attributes.include? name.to_sym
-    end
+    @@array_attributes << name
+    @@attributes << [name, []]
+    @@default_value[name] = []
+    code = %{
+      def #{name}
+        @#{name} ||= []
+      end
+      def #{name}=(value)
+        @#{name} = Array(value)
+      end
+    }
 
-    ##
-    # Specification attributes that are arrays (appendable and so-forth)
+    module_eval code, __FILE__, __LINE__ - 9
+  end
 
-    def self.array_attributes
-      @@array_attributes.dup
+  ##
+  # Same as attribute above, but also records this attribute as mandatory.
+
+  def self.required_attribute(*args)
+    @@required_attributes << args.first
+    attribute(*args)
+  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.
+
+  def self.read_only(*names)
+    names.each do |name|
+      private "#{name}="
     end
+  end
 
-    ##
-    # A list of Specification instances that have been defined in this Ruby
-    # instance.
+  # Shortcut for creating several attributes at once (each with a default
+  # value of +nil+).
 
-    def self.list
-      @@list
+  def self.attributes(*args)
+    args.each do |arg|
+      attribute(arg, nil)
     end
+  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.
+  ##
+  # Some attributes require special behaviour when they are accessed.  This
+  # allows for that.
 
-    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
+  def self.overwrite_accessor(name, &block)
+    remove_method name
+    define_method(name, &block)
+  end
 
-      @@attributes << [name, default]
-      @@default_value[name] = default
-      attr_accessor(name)
-    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
 
-    ##
-    # Same as :attribute, but ensures that values assigned to the attribute
-    # are array values by applying :to_a to the value.
+  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.array_attribute(name)
-      @@non_nil_attributes << ["@#{name}".intern, []]
+  ##
+  # Dump only crucial instance variables.
+  #--
+  # MAINTAIN ORDER!
 
-      @@array_attributes << name
-      @@attributes << [name, []]
-      @@default_value[name] = []
-      code = %{
-        def #{name}
-          @#{name} ||= []
-        end
-        def #{name}=(value)
-          @#{name} = Array(value)
-        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
 
-      module_eval code, __FILE__, __LINE__ - 9
-    end
+  ##
+  # Load custom marshal format, re-initializing defaults as needed
 
-    ##
-    # Same as attribute above, but also records this attribute as mandatory.
+  def self._load(str)
+    array = Marshal.load str
 
-    def self.required_attribute(*args)
-      @@required_attributes << args.first
-      attribute(*args)
+    spec = Gem::Specification.new
+    spec.instance_variable_set :@specification_version, array[1]
+
+    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
 
-    ##
-    # 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.
+    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.read_only(*names)
-      names.each do |name|
-        private "#{name}="
-      end
+    spec
+  end
+
+  ##
+  # List of depedencies that will automatically be activated at runtime.
+
+  def runtime_dependencies
+    dependencies.select { |d| d.type == :runtime || d.type == nil }
+  end
+
+  ##
+  # List of dependencies that are used for development
+
+  def development_dependencies
+    dependencies.select { |d| d.type == :development }
+  end
+
+  def test_suite_file # :nodoc:
+    warn 'test_suite_file deprecated, use test_files'
+    test_files.first
+  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
+
+  ##
+  # true when this gemspec has been loaded from a specifications directory.
+  # This attribute is not persisted.
+
+  attr_accessor :loaded
+
+  ##
+  # Path this gemspec was loaded from.  This attribute is not persisted.
+
+  attr_accessor :loaded_from
+
+  ##
+  # 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
 
-    # Shortcut for creating several attributes at once (each with a default
-    # value of +nil+).
+  ##
+  # Files in the Gem under one of the require_paths
 
-    def self.attributes(*args)
-      args.each do |arg|
-        attribute(arg, nil)
+  def lib_files
+    @files.select do |file|
+      require_paths.any? do |path|
+        file.index(path) == 0
       end
     end
+  end
 
-    ##
-    # Some attributes require special behaviour when they are accessed.  This
-    # allows for that.
+  ##
+  # True if this gem was loaded from disk
 
-    def self.overwrite_accessor(name, &block)
-      remove_method name
-      define_method(name, &block)
-    end
+  alias :loaded? :loaded
 
-    ##
-    # 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 
+  ##
+  # True if this gem has files in test_files
 
-    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 has_unit_tests?
+    not test_files.empty?
+  end
 
-    ##
-    # Dump only crucial instance variables.
-    #--
-    # MAINTAIN ORDER!
+  # :stopdoc:
+  alias has_test_suite? has_unit_tests?
+  # :startdoc:
 
-    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,
-      ]
-    end
+  ##
+  # Specification constructor.  Assigns the default values to the attributes
+  # and yields itself for further initialization.
 
-    ##
-    # Load custom marshal format, re-initializing defaults as needed
+  def initialize
+    @new_platform = nil
+    assign_defaults
+    @loaded = false
+    @loaded_from = nil
 
-    def self._load(str)
-      array = Marshal.load str
+    yield self if block_given?
 
-      spec = Gem::Specification.new
-      spec.instance_variable_set :@specification_version, array[1]
+    @@gather.call(self) if @@gather
+  end
 
-      current_version = CURRENT_SPECIFICATION_VERSION
+  ##
+  # Duplicates array_attributes from +other_spec+ so state isn't shared.
 
-      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
+  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 }
 
-      if array.size < field_count then
-        raise TypeError, "invalid Gem::Specification format #{array.inspect}"
-      end
+    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
 
-      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
+  ##
+  # 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.
 
-      spec
+  def assign_defaults
+    @@nil_attributes.each do |name|
+      instance_variable_set name, nil
     end
 
-    ##
-    # List of depedencies that will automatically be activated at runtime.
+    @@non_nil_attributes.each do |name, default|
+      value = case default
+              when Time, Numeric, Symbol, true, false, nil then default
+              else default.dup
+              end
 
-    def runtime_dependencies
-      dependencies.select { |d| d.type == :runtime || d.type == nil }
+      instance_variable_set name, value
     end
 
-    ##
-    # List of dependencies that are used for development
+    # HACK
+    instance_variable_set :@new_platform, Gem::Platform::RUBY
+  end
 
-    def development_dependencies
-      dependencies.select { |d| d.type == :development }
+  ##
+  # 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.
+
+  def self.from_yaml(input)
+    input = normalize_yaml_input input
+    spec = YAML.load input
+
+    if spec && spec.class == FalseClass then
+      raise Gem::EndOfYAMLException
     end
 
-    def test_suite_file # :nodoc:
-      warn 'test_suite_file deprecated, use test_files'
-      test_files.first
+    unless Gem::Specification === spec then
+      raise Gem::Exception, "YAML data doesn't evaluate to gem specification"
     end
 
-    def test_suite_file=(val) # :nodoc:
-      warn 'test_suite_file= deprecated, use test_files='
-      @test_files = [] unless defined? @test_files
-      @test_files << val
+    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
 
-    ##
-    # true when this gemspec has been loaded from a specifications directory.
-    # This attribute is not persisted.
+    spec
+  end
 
-    attr_accessor :loaded
+  ##
+  # Loads ruby format gemspec from +filename+
 
-    ##
-    # Path this gemspec was loaded from.  This attribute is not persisted.
+  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
 
-    attr_accessor :loaded_from
+  ##
+  # Make sure the YAML specification is properly formatted with dashes
 
-    ##
-    # Returns an array with bindir attached to each executable in the
-    # executables list
+  def self.normalize_yaml_input(input)
+    result = input.respond_to?(:read) ? input.read : input
+    result = "--- " + result unless result =~ /^--- /
+    result
+  end
 
-    def add_bindir(executables)
-      return nil if executables.nil?
+  ##
+  # Sets the rubygems_version to the current RubyGems version
 
-      if @bindir then
-        Array(executables).map { |e| File.join(@bindir, e) }
-      else
-        executables
-      end
-    rescue
-      return nil
-    end
+  def mark_version
+    @rubygems_version = Gem::RubyGemsVersion
+  end
 
-    ##
-    # Files in the Gem under one of the require_paths
+  ##
+  # Ignore unknown attributes while loading
 
-    def lib_files
-      @files.select do |file|
-        require_paths.any? do |path|
-          file.index(path) == 0
-        end
-      end
+  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
 
-    ##
-    # True if this gem was loaded from disk
+  ##
+  # 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.
 
-    alias :loaded? :loaded
+  def add_development_dependency(gem, *requirements)
+    add_dependency_with_type(gem, :development, *requirements)
+  end
 
-    ##
-    # True if this gem has files in test_files
+  ##
+  # Adds a runtime dependency named +gem+ with +requirements+ to this Gem.
+  # For example:
+  #
+  #   spec.add_runtime_dependency 'jabber4r', '> 0.1', '<= 0.5'
 
-    def has_unit_tests?
-      not test_files.empty?
-    end
+  def add_runtime_dependency(gem, *requirements)
+    add_dependency_with_type(gem, :runtime, *requirements)
+  end
 
-    alias has_test_suite? has_unit_tests? # :nodoc: deprecated
-    
-    ##
-    # 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.
+  ##
+  # Adds a runtime dependency
 
-    def initialize
-      @new_platform = nil
-      assign_defaults
-      @loaded = false
-      @loaded_from = nil
-      @@list << self
+  alias add_dependency add_runtime_dependency
 
-      yield self if block_given?
+  ##
+  # 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.
 
-      @@gather.call(self) if @@gather
+  def full_name
+    if platform == Gem::Platform::RUBY or platform.nil? then
+      "#{@name}-#{@version}"
+    else
+      "#{@name}-#{@version}-#{platform}"
     end
+  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.
+  ##
+  # Returns the full name (name-version) of this gemspec using the original
+  # platform.  For use with legacy gems.
 
-    def assign_defaults
-      @@nil_attributes.each do |name|
-        instance_variable_set name, nil
-      end
+  def original_name # :nodoc:
+    if platform == Gem::Platform::RUBY or platform.nil? then
+      "#{@name}-#{@version}"
+    else
+      "#{@name}-#{@version}-#{@original_platform}"
+    end
+  end
 
-      @@non_nil_attributes.each do |name, default|
-        value = case default
-                when Time, Numeric, Symbol, true, false, nil then default
-                else default.dup
-                end
+  ##
+  # The full path to the gem (install path + full name).
 
-        instance_variable_set name, value
-      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
 
-      # HACK
-      instance_variable_set :@new_platform, Gem::Platform::RUBY
+  ##
+  # The default (generated) file name of the gem.
+
+  def file_name
+    full_name + ".gem"
+  end
+
+  ##
+  # The directory that this gem was installed into.
+
+  def installation_path
+    unless @loaded_from then
+      raise Gem::Exception, "spec #{full_name} is not from an installed gem"
     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. 
+    File.expand_path File.dirname(File.dirname(@loaded_from))
+  end
 
-    def self.from_yaml(input)
-      input = normalize_yaml_input input
-      spec = YAML.load input
+  ##
+  # Checks if this specification meets the requirement of +dependency+.
 
-      if spec && spec.class == FalseClass then
-        raise Gem::EndOfYAMLException
-      end
+  def satisfies_requirement?(dependency)
+    return @name == dependency.name &&
+      dependency.version_requirements.satisfied_by?(@version)
+  end
 
-      unless Gem::Specification === spec then
-        raise Gem::Exception, "YAML data doesn't evaluate to gem specification"
-      end
+  ##
+  # Returns an object you can use to sort specifications in #sort_by.
 
-      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 sort_obj
+    [@name, @version, @new_platform == Gem::Platform::RUBY ? -1 : 1]
+  end
 
-      spec
-    end 
+  def <=>(other) # :nodoc:
+    sort_obj <=> other.sort_obj
+  end
 
-    ##
-    # Loads ruby format gemspec from +filename+
+  ##
+  # Tests specs for equality (across all attributes).
 
-    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 ==(other) # :nodoc:
+    self.class === other && same_attributes?(other)
+  end
 
-    ##
-    # Make sure the YAML specification is properly formatted with dashes
+  alias eql? == # :nodoc:
 
-    def self.normalize_yaml_input(input)
-      result = input.respond_to?(:read) ? input.read : input
-      result = "--- " + result unless result =~ /^--- /
-      result
-    end
-    
-    ##
-    # Sets the rubygems_version to the current RubyGems version
+  ##
+  # True if this gem has the same attributes as +other+.
 
-    def mark_version
-      @rubygems_version = RubyGemsVersion
+  def same_attributes?(other)
+    @@attributes.each do |name, default|
+      return false unless self.send(name) == other.send(name)
     end
+    true
+  end
 
-    ##
-    # Ignore unknown attributes while loading
+  private :same_attributes?
 
-    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
+  def hash # :nodoc:
+    @@attributes.inject(0) { |hash_code, (name, default_value)|
+      n = self.send(name).hash
+      hash_code + n
+    }
+  end
+
+  def to_yaml(opts = {}) # :nodoc:
+    mark_version
+
+    attributes = @@attributes.map { |name,| name.to_s }.sort
+    attributes = attributes - %w[name version platform]
+
+    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
     end
+  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.
-
-    def add_development_dependency(gem, *requirements)
-      add_dependency_with_type(gem, :development, *requirements)
+  def yaml_initialize(tag, vals) # :nodoc:
+    vals.each do |ivar, val|
+      instance_variable_set "@#{ivar}", val
     end
 
-    ##
-    # Adds a runtime dependency named +gem+ with +requirements+ to this Gem.
-    # For example:
-    #
-    #   spec.add_runtime_dependency 'jabber4r', '> 0.1', '<= 0.5'
+    @original_platform = @platform # for backwards compatibility
+    self.platform = Gem::Platform.new @platform
+  end
 
-    def add_runtime_dependency(gem, *requirements)
-      add_dependency_with_type(gem, :runtime, *requirements)
+  ##
+  # 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.
+
+  def to_ruby
+    mark_version
+    result = []
+    result << "# -*- encoding: utf-8 -*-"
+    result << nil
+    result << "Gem::Specification.new do |s|"
+
+    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="
 
-    ##
-    # Adds a runtime dependency
+    handled = [
+      :dependencies,
+      :name,
+      :platform,
+      :required_rubygems_version,
+      :specification_version,
+      :version,
+    ]
 
-    alias add_dependency add_runtime_dependency
+    attributes = @@attributes.sort_by { |attr_name,| attr_name.to_s }
 
-    ##
-    # 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}"
+    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
     end
 
-    ##
-    # Returns the full name (name-version) of this gemspec using the original
-    # platform.  For use with legacy gems.
+    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 original_name # :nodoc:
-      if platform == Gem::Platform::RUBY or platform.nil? then
-        "#{@name}-#{@version}"
-      else
-        "#{@name}-#{@version}-#{@original_platform}"
+    result << "    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then"
+
+    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
 
-    ##
-    # The full path to the gem (install path + full name).
+    result << "    else"
 
-    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
+    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
 
-    ##
-    # The default (generated) file name of the gem.
+    result << '    end'
 
-    def file_name
-      full_name + ".gem"
-    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"
 
-    ##
-    # The directory that this gem was installed into.
+    result << "end"
+    result << nil
 
-    def installation_path
-      path = File.dirname(@loaded_from).split(File::SEPARATOR)[0..-2]
-      path = path.join File::SEPARATOR
-      File.expand_path path
+    result.join "\n"
+  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..
+
+  def validate
+    extend Gem::UserInteraction
+    normalize
+
+    if rubygems_version != Gem::RubyGemsVersion then
+      raise Gem::InvalidSpecificationException,
+            "expected RubyGems version #{Gem::RubyGemsVersion}, was #{rubygems_version}"
     end
 
-    ##
-    # Checks if this specification meets the requirement of +dependency+.
+    @@required_attributes.each do |symbol|
+      unless self.send symbol then
+        raise Gem::InvalidSpecificationException,
+              "missing value for attribute #{symbol}"
+      end
+    end
 
-    def satisfies_requirement?(dependency)
-      return @name == dependency.name && 
-        dependency.version_requirements.satisfied_by?(@version)
+    unless String === name then
+      raise Gem::InvalidSpecificationException,
+            "invalid value for attribute name: \"#{name.inspect}\""
     end
 
-    ##
-    # Returns an object you can use to sort specifications in #sort_by.
+    if require_paths.empty? then
+      raise Gem::InvalidSpecificationException,
+            'specification must have at least one require_path'
+    end
 
-    def sort_obj
-      [@name, @version.to_ints, @new_platform == Gem::Platform::RUBY ? -1 : 1]
+    @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
 
-    def <=>(other) # :nodoc:
-      sort_obj <=> other.sort_obj
+    non_files = files.select do |file|
+      !File.file? file
     end
 
-    ##
-    # Tests specs for equality (across all attributes).
+    unless non_files.empty? then
+      non_files = non_files.map { |file| file.inspect }
+      raise Gem::InvalidSpecificationException,
+            "[#{non_files.join ", "}] are not files"
+    end
 
-    def ==(other) # :nodoc:
-      self.class === other && same_attributes?(other)
+    unless specification_version.is_a?(Fixnum)
+      raise Gem::InvalidSpecificationException,
+            'specification_version must be a Fixnum (did you mean version?)'
     end
 
-    alias eql? == # :nodoc:
+    case platform
+    when Gem::Platform, Gem::Platform::RUBY then # ok
+    else
+      raise Gem::InvalidSpecificationException,
+            "invalid platform #{platform.inspect}, see Gem::Platform"
+    end
 
-    ##
-    # True if this gem has the same attributes as +other+.
+    unless Array === authors and
+           authors.all? { |author| String === author } then
+      raise Gem::InvalidSpecificationException,
+            'authors must be Array of Strings'
+    end
 
-    def same_attributes?(other)
-      @@attributes.each do |name, default|
-        return false unless self.send(name) == other.send(name)
+    licenses.each { |license|
+      if license.length > 64
+        raise Gem::InvalidSpecificationException,
+          "each license must be 64 characters or less"
       end
-      true
-    end
+    }
 
-    private :same_attributes?
+    # reject FIXME and TODO
 
-    def hash # :nodoc:
-      @@attributes.inject(0) { |hash_code, (name, default_value)|
-        n = self.send(name).hash
-        hash_code + n
-      } / @@attributes.length # XXX NSObject#hash won't accept Bignum
+    unless authors.grep(/FIXME|TODO/).empty? then
+      raise Gem::InvalidSpecificationException,
+            '"FIXME" or "TODO" is not an author'
     end
 
-    def to_yaml(opts = {}) # :nodoc:
-      mark_version
+    unless Array(email).grep(/FIXME|TODO/).empty? then
+      raise Gem::InvalidSpecificationException,
+            '"FIXME" or "TODO" is not an email address'
+    end
 
-      attributes = @@attributes.map { |name,| name.to_s }.sort
-      attributes = attributes - %w[name version platform]
+    if description =~ /FIXME|TODO/ then
+      raise Gem::InvalidSpecificationException,
+            '"FIXME" or "TODO" is not a description'
+    end
 
-      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
+    if summary =~ /FIXME|TODO/ then
+      raise Gem::InvalidSpecificationException,
+            '"FIXME" or "TODO" is not a summary'
+    end
 
-          attributes.each do |name|
-            map.add name, instance_variable_get("@#{name}")
-          end
-        end
-      end
+    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
 
-    def yaml_initialize(tag, vals) # :nodoc:
-      vals.each do |ivar, val|
-        instance_variable_set "@#{ivar}", val
-      end
+    # Warnings
 
-      @original_platform = @platform # for backwards compatibility
-      self.platform = Gem::Platform.new @platform
+    %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
 
-    ##
-    # 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.
+    if summary and not summary.empty? and description == summary then
+      alert_warning 'description and summary are identical'
+    end
 
-    def to_ruby
-      mark_version
-      result = []
-      result << "# -*- encoding: utf-8 -*-"
-      result << nil
-      result << "Gem::Specification.new do |s|"
+    alert_warning "deprecated autorequire specified" if autorequire
 
-      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="
+    executables.each do |executable|
+      executable_path = File.join bindir, executable
+      shebang = File.read(executable_path, 2) == '#!'
 
-      handled = [
-        :dependencies,
-        :name,
-        :platform,
-        :required_rubygems_version,
-        :specification_version,
-        :version,
-      ]
+      alert_warning "#{executable_path} is missing #! line" unless shebang
+    end
 
-      attributes = @@attributes.sort_by { |attr_name,| attr_name.to_s }
+    true
+  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
-      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.
 
-      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 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
 
-      result << "    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then"
+  ##
+  # 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]]
 
-      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})"
+  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
+    end
+    out
+  end
 
-      result << "    else"
+  def to_s # :nodoc:
+    "#<Gem::Specification name=#{@name} version=#{@version}>"
+  end
 
-      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
+  def pretty_print(q) # :nodoc:
+    q.group 2, 'Gem::Specification.new do |s|', 'end' do
+      q.breakable
 
-      result << '    end'
+      attributes = @@attributes.sort_by { |attr_name,| attr_name.to_s }
 
-      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"
+      attributes.each do |attr_name, default|
+        current_value = self.send attr_name
+        if current_value != default or
+           self.class.required_attribute? attr_name then
 
-      result << "end"
-      result << nil
+          q.text "s.#{attr_name} = "
 
-      result.join "\n"
-    end
+          if attr_name == :date then
+            current_value = current_value.utc
 
-    ##
-    # 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..
+            q.text "Time.utc(#{current_value.year}, #{current_value.month}, #{current_value.day})"
+          else
+            q.pp current_value
+          end
 
-    def validate
-      extend Gem::UserInteraction
-      normalize
-
-      if rubygems_version != RubyGemsVersion then
-        raise Gem::InvalidSpecificationException,
-              "expected RubyGems version #{RubyGemsVersion}, was #{rubygems_version}"
+          q.breakable
+        end
       end
+    end
+  end
 
-      @@required_attributes.each do |symbol|
-        unless self.send symbol then
-          raise Gem::InvalidSpecificationException,
-                "missing value for attribute #{symbol}"
-        end
-      end 
+  ##
+  # Adds a dependency on gem +dependency+ with type +type+ that requires
+  # +requirements+.  Valid types are currently <tt>:runtime</tt> and
+  # <tt>:development</tt>.
 
-      if require_paths.empty? then
-        raise Gem::InvalidSpecificationException,
-              "specification must have at least one require_path"
-      end
+  def add_dependency_with_type(dependency, type, *requirements)
+    requirements = if requirements.empty? then
+                     Gem::Requirement.default
+                   else
+                     requirements.flatten
+                   end
 
-      case platform
-      when Gem::Platform, Platform::RUBY then # ok
-      else
-        raise Gem::InvalidSpecificationException,
-              "invalid platform #{platform.inspect}, see Gem::Platform"
-      end
+    unless dependency.respond_to?(:name) &&
+      dependency.respond_to?(:version_requirements)
 
-      unless Array === authors and
-             authors.all? { |author| String === author } then
-        raise Gem::InvalidSpecificationException,
-              'authors must be Array of Strings'
-      end
+      dependency = Gem::Dependency.new(dependency, requirements, type)
+    end
 
-      # Warnings
+    dependencies << dependency
+  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
+  private :add_dependency_with_type
 
-      alert_warning "RDoc will not be generated (has_rdoc == false)" unless
-        has_rdoc
+  ##
+  # Finds all gems that satisfy +dep+
 
-      alert_warning "deprecated autorequire specified" if autorequire
+  def find_all_satisfiers(dep)
+    Gem.source_index.each do |_, gem|
+      yield gem if gem.satisfies_requirement? dep
+    end
+  end
 
-      executables.each do |executable|
-        executable_path = File.join bindir, executable
-        shebang = File.read(executable_path, 2) == '#!'
+  private :find_all_satisfiers
 
-        alert_warning "#{executable_path} is missing #! line" unless shebang
-      end
+  ##
+  # Return a string containing a Ruby code representation of the given
+  # object.
 
-      true
+  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
 
-    ##
-    # 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. 
+  private :ruby_code
 
-    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
+  # :section: Required gemspec attributes
 
-    ##
-    # 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]]
+  ##
+  # :attr_accessor: rubygems_version
+  #
+  # The version of RubyGems used to create this gem
 
-    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
-      end
-      out
-    end
+  required_attribute :rubygems_version, Gem::RubyGemsVersion
 
-    def to_s
-      "#<Gem::Specification name=#{@name} version=#{@version}>"
-    end
+  ##
+  # :attr_accessor: specification_version
+  #
+  # The Gem::Specification version of this gemspec
 
-    def add_dependency_with_type(dependency, type, *requirements)
-      requirements = if requirements.empty? then
-                       Gem::Requirement.default
-                     else
-                       requirements.flatten
-                     end
+  required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION
 
-      unless dependency.respond_to?(:name) &&
-        dependency.respond_to?(:version_requirements)
+  ##
+  # :attr_accessor: name
+  #
+  # This gem's name
 
-        dependency = Dependency.new(dependency, requirements, type)
-      end
+  required_attribute :name
 
-      dependencies << dependency
-    end
+  ##
+  # :attr_accessor: version
+  #
+  # This gem's version
 
-    private :add_dependency_with_type
+  required_attribute :version
 
-    def find_all_satisfiers(dep)
-      Gem.source_index.each do |name,gem|
-        if(gem.satisfies_requirement?(dep)) then
-          yield gem
-        end
-      end
-    end
+  ##
+  # :attr_accessor: date
+  #
+  # The date this gem was created
 
-    private :find_all_satisfiers
+  required_attribute :date, TODAY
 
-    ##
-    # Return a string containing a Ruby code representation of the given
-    # object.
+  ##
+  # :attr_accessor: summary
+  #
+  # A short summary of this gem's description.  Displayed in `gem list -d`.
 
-    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
-    end
-    
-    private :ruby_code
+  required_attribute :summary
 
-    # :section: Required gemspec attributes
-    
-    ##
-    # The version of RubyGems used to create this gem
+  ##
+  # :attr_accessor: require_paths
+  #
+  # Paths in the gem to add to $LOAD_PATH when this gem is activated
 
-    required_attribute :rubygems_version, Gem::RubyGemsVersion
+  required_attribute :require_paths, ['lib']
 
-    ##
-    # The Gem::Specification version of this gemspec
+  # :section: Optional gemspec attributes
 
-    required_attribute :specification_version, CURRENT_SPECIFICATION_VERSION
+  ##
+  # :attr_accessor: email
+  #
+  # A contact email for this gem
 
-    ##
-    # This gem's name
+  attribute :email
 
-    required_attribute :name
+  ##
+  # :attr_accessor: homepage
+  #
+  # The URL of this gem's home page
 
-    ##
-    # This gem's version
+  attribute :homepage
 
-    required_attribute :version
+  ##
+  # :attr_accessor: rubyforge_project
+  #
+  # The rubyforge project this gem lives under.  i.e. RubyGems'
+  # rubyforge_project is "rubygems".
 
-    ##
-    # The date this gem was created
+  attribute :rubyforge_project
 
-    required_attribute :date, TODAY
+  ##
+  # :attr_accessor: description
+  #
+  # A long description of this gem
 
-    ##
-    # A short summary of this gem's description.  Displayed in `gem list -d`.
+  attribute :description
 
-    required_attribute :summary
+  ##
+  # :attr_accessor: autorequire
+  #
+  # Autorequire was used by old RubyGems to automatically require a file.
+  # It no longer is supported.
 
-    ##
-    # Paths in the gem to add to $LOAD_PATH when this gem is activated
+  attribute :autorequire
 
-    required_attribute :require_paths, ['lib']
+  ##
+  # :attr_accessor: default_executable
+  #
+  # The default executable for this gem.
 
-    # :section: Optional gemspec attributes
+  attribute :default_executable
 
-    ##
-    # A contact email for this gem
-    
-    attribute :email
+  ##
+  # :attr_accessor: bindir
+  #
+  # The path in the gem for executable scripts
 
-    ##
-    # The URL of this gem's home page
+  attribute :bindir, 'bin'
 
-    attribute :homepage
+  ##
+  # :attr_accessor: has_rdoc
+  #
+  # Deprecated and ignored, defaults to true.
+  #
+  # Formerly used to indicate this gem was RDoc-capable.
 
-    ##
-    # The rubyforge project this gem lives under.  i.e. RubyGems'
-    # rubyforge_project is "rubygems".
-    
-    attribute :rubyforge_project
+  attribute :has_rdoc, true
 
-    ##
-    # A long description of this gem
+  ##
+  # True if this gem supports RDoc
 
-    attribute :description
+  alias :has_rdoc? :has_rdoc
 
-    ##
-    # Autorequire was used by old RubyGems to automatically require a file.
-    # It no longer is supported.
+  ##
+  # :attr_accessor: required_ruby_version
+  #
+  # The ruby of version required by this gem
 
-    attribute :autorequire
+  attribute :required_ruby_version, Gem::Requirement.default
 
-    ##
-    # The default executable for this gem.
+  ##
+  # :attr_accessor: required_rubygems_version
+  #
+  # The RubyGems version required by this gem
 
-    attribute :default_executable
+  attribute :required_rubygems_version, Gem::Requirement.default
 
-    ##
-    # The path in the gem for executable scripts
+  ##
+  # :attr_accessor: platform
+  #
+  # The platform this gem runs on.  See Gem::Platform for details.
 
-    attribute :bindir, 'bin'
+  attribute :platform, Gem::Platform::RUBY
 
-    ##
-    # True if this gem is RDoc-compliant
+  ##
+  # :attr_accessor: signing_key
+  #
+  # The key used to sign this gem.  See Gem::Security for details.
 
-    attribute :has_rdoc, false
+  attribute :signing_key, nil
 
-    ##
-    # True if this gem supports RDoc
+  ##
+  # :attr_accessor: cert_chain
+  #
+  # The certificate chain used to sign this gem.  See Gem::Security for
+  # details.
 
-    alias :has_rdoc? :has_rdoc
+  attribute :cert_chain, []
 
-    ##
-    # The ruby of version required by this gem
+  ##
+  # :attr_accessor: post_install_message
+  #
+  # A message that gets displayed after the gem is installed
 
-    attribute :required_ruby_version, Gem::Requirement.default
+  attribute :post_install_message, nil
 
-    ##
-    # The RubyGems version required by this gem
+  ##
+  # :attr_accessor: authors
+  #
+  # The list of authors who wrote this gem
 
-    attribute :required_rubygems_version, Gem::Requirement.default
+  array_attribute :authors
 
-    ##
-    # The platform this gem runs on.  See Gem::Platform for details.
+  ##
+  # :attr_accessor: licenses
+  #
+  # The license(s) for the library.  Each license must be a short name, no
+  # more than 64 characters.
 
-    attribute :platform, Gem::Platform::RUBY
+  array_attribute :licenses
 
-    ##
-    # The key used to sign this gem.  See Gem::Security for details.
+  ##
+  # :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.
 
-    attribute :signing_key, nil
+  array_attribute :files
 
-    ##
-    # The certificate chain used to sign this gem.  See Gem::Security for
-    # details.
+  ##
+  # :attr_accessor: test_files
+  #
+  # Test files included in this gem.  You cannot append to this accessor, you
+  # must assign to it.
 
-    attribute :cert_chain, []
+  array_attribute :test_files
 
-    ##
-    # A message that gets displayed after the gem is installed
+  ##
+  # :attr_accessor: rdoc_options
+  #
+  # An ARGV-style array of options to RDoc
 
-    attribute :post_install_message, nil
+  array_attribute :rdoc_options
 
-    ##
-    # The list of authors who wrote this gem
+  ##
+  # :attr_accessor: extra_rdoc_files
+  #
+  # Extra files to add to RDoc
 
-    array_attribute :authors
+  array_attribute :extra_rdoc_files
 
-    ##
-    # Files included in this gem
+  ##
+  # :attr_accessor: executables
+  #
+  # Executables included in the gem
 
-    array_attribute :files
+  array_attribute :executables
 
-    ##
-    # Test files included in this gem
+  ##
+  # :attr_accessor: extensions
+  #
+  # Extensions to build when installing the gem.  See
+  # Gem::Installer#build_extensions for valid values.
 
-    array_attribute :test_files
+  array_attribute :extensions
 
-    ##
-    # An ARGV-style array of options to RDoc
+  ##
+  # :attr_accessor: requirements
+  #
+  # An array or things required by this gem.  Not used by anything
+  # presently.
 
-    array_attribute :rdoc_options
+  array_attribute :requirements
 
-    ##
-    # Extra files to add to RDoc
+  ##
+  # :attr_reader: dependencies
+  #
+  # A list of Gem::Dependency objects this gem depends on.
 
-    array_attribute :extra_rdoc_files
+  array_attribute :dependencies
 
-    ##
-    # Executables included in the gem
+  read_only :dependencies
 
-    array_attribute :executables
+  # :section: Aliased gemspec attributes
 
-    ##
-    # Extensions to build when installing the gem.  See
-    # Gem::Installer#build_extensions for valid values.
+  ##
+  # Singular accessor for #executables
 
-    array_attribute :extensions
+  attribute_alias_singular :executable, :executables
 
-    ##
-    # An array or things required by this gem.  Not used by anything
-    # presently.
+  ##
+  # Singular accessor for #authors
 
-    array_attribute :requirements
+  attribute_alias_singular :author, :authors
 
-    ##
-    # A list of Gem::Dependency objects this gem depends on.  Only appendable.
+  ##
+  # Singular accessor for #licenses
 
-    array_attribute :dependencies
+  attribute_alias_singular :license, :licenses
 
-    read_only :dependencies
+  ##
+  # Singular accessor for #require_paths
 
-    # :section: Aliased gemspec attributes
+  attribute_alias_singular :require_path, :require_paths
 
-    ##
-    # Singular accessor for executables
-    
-    attribute_alias_singular :executable, :executables
+  ##
+  # Singular accessor for #test_files
 
-    ##
-    # Singular accessor for authors
+  attribute_alias_singular :test_file, :test_files
 
-    attribute_alias_singular :author, :authors
+  ##
+  # has_rdoc is now ignored
 
-    ##
-    # Singular accessor for require_paths
+  overwrite_accessor :has_rdoc do
+    true
+  end
 
-    attribute_alias_singular :require_path, :require_paths
+  ##
+  # has_rdoc is now ignored
 
-    ##
-    # Singular accessor for test_files
+  overwrite_accessor :has_rdoc= do |value|
+    @has_rdoc = true
+  end
 
-    attribute_alias_singular :test_file, :test_files
+  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 :version= do |version|
-      @version = Version.create(version)
-    end
+  overwrite_accessor :platform do
+    @new_platform
+  end
 
-    overwrite_accessor :platform do
-      @new_platform
+  overwrite_accessor :platform= do |platform|
+    if @original_platform.nil? or
+       @original_platform == Gem::Platform::RUBY then
+      @original_platform = platform
     end
 
-    overwrite_accessor :platform= do |platform|
-      if @original_platform.nil? or
-         @original_platform == Gem::Platform::RUBY then
-        @original_platform = platform
-      end
+    case platform
+    when Gem::Platform::CURRENT then
+      @new_platform = Gem::Platform.local
+      @original_platform = @new_platform.to_s
 
-      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
 
-      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
 
-      # 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
+    @platform = @new_platform.to_s
 
-      @platform = @new_platform.to_s
+    @new_platform
+  end
 
-      @new_platform
-    end
+  overwrite_accessor :required_ruby_version= do |value|
+    @required_ruby_version = Gem::Requirement.create(value)
+  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 :required_rubygems_version= do |value|
-      @required_rubygems_version = Gem::Requirement.create(value)
+  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 :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 :date do
+    self.date = nil if @date.nil?  # HACK Sets the default value for date
+    @date
+  end
 
-    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 :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 :description= do |str|
-      @description = if str then
-                       str.strip.
-                       gsub(/(\w-)\n[ \t]*(\w)/, '\1\2').
-                       gsub(/\n[ \t]*/, " ")
-                     end
-    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
-    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 :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

Added: MacRuby/trunk/lib/rubygems/text.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/text.rb	                        (rev 0)
+++ MacRuby/trunk/lib/rubygems/text.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
+

Modified: MacRuby/trunk/lib/rubygems/timer.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/timer.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/timer.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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:
 

Modified: MacRuby/trunk/lib/rubygems/uninstaller.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/uninstaller.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/uninstaller.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Modified: MacRuby/trunk/lib/rubygems/user_interaction.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/user_interaction.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/user_interaction.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
+

Modified: MacRuby/trunk/lib/rubygems/validator.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/validator.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/validator.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -10,6 +10,13 @@
 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
 
@@ -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 Gem::MD5.hexdigest(f.read).to_s ==
+                    Gem::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

Modified: MacRuby/trunk/lib/rubygems/version.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/version.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/version.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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".
@@ -132,28 +207,36 @@
   end
 
   def hash # :nodoc:
-    #@version.hash
-    @version.hash / 2 # XXX NSObject#hash won't accept Bignum
+    @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

Modified: MacRuby/trunk/lib/rubygems/version_option.rb
===================================================================
--- MacRuby/trunk/lib/rubygems/version_option.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems/version_option.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -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
 

Modified: MacRuby/trunk/lib/rubygems.rb
===================================================================
--- MacRuby/trunk/lib/rubygems.rb	2010-01-25 13:52:22 UTC (rev 3329)
+++ MacRuby/trunk/lib/rubygems.rb	2010-01-25 20:26:51 UTC (rev 3330)
@@ -5,14 +5,33 @@
 # See LICENSE.txt for permissions.
 #++
 
-require 'rubygems/rubygems_version'
 require 'rubygems/defaults'
 require 'thread'
+require 'etc'
 
 module Gem
+
+  RubyGemsVersion = VERSION = '1.3.5'
+
+  ##
+  # 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 +73,105 @@
 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 at weirichhouse.org]
+#
+# 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'
+  # :stopdoc:
   RbConfig = Config unless defined? ::RbConfig
+  # :startdoc:
 
   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 +185,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 +213,7 @@
 
   @configuration = nil
   @loaded_specs = {}
+  @loaded_stacks = {}
   @platforms = []
   @ruby = nil
   @sources = []
@@ -128,6 +240,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 +266,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 +289,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 +359,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)
+  end
+
+  ##
   # The mode needed to read a file as straight binary.
 
   def self.binary_mode
@@ -351,14 +511,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
 
   ##
@@ -487,7 +660,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
 
@@ -495,15 +668,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
@@ -597,6 +761,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
@@ -638,15 +829,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
 
@@ -672,7 +871,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
 
@@ -721,7 +926,9 @@
         next unless File.directory? Gem.user_home
         unless win_platform? then
           # only create by matching user
-          next if Etc.getpwuid.uid != File::Stat.new(Gem.user_home).uid
+          if Etc.getpwuid.nil? || Etc.getpwuid.uid != File::Stat.new(Gem.user_home).uid
+            next
+          end
         end
       end
       ensure_gem_subdirectories path
@@ -778,6 +985,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.
 
@@ -807,6 +1039,9 @@
 
   class << self
 
+    ##
+    # Hash of loaded Gem::Specification keyed by name
+
     attr_reader :loaded_specs
 
     ##
@@ -838,8 +1073,14 @@
 
   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
@@ -882,9 +1123,19 @@
 
 require 'rubygems/config_file'
 
-# MacRuby requires this hack.
-#if RUBY_VERSION < '1.9' then
+if RUBY_VERSION < '1.9' then
   require 'rubygems/custom_require'
-#end
+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
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100125/e459cc9f/attachment-0001.html>


More information about the macruby-changes mailing list