hi!

here's my solution (first submission ever ;-).

first the cheating one (no extra credit):

  ARGV.each { |mod|
    puts "require '#{mod}' => #{%x{gem which #{mod}}.split(/\n/).last}"
  }

now on to the real one. it uses ruby's "magic constant" SCRIPT_LINES__ and (as
fallback) rubygem's 'which' command (which does not only find gems, actually;
see above).

contrary to the quiz "rules", information is output to STDERR instead of STDOUT.
the script takes a list of library names as arguments and a few options.

examples:

  ww@blackwinter:~/devel/scratch> ./modwhich.rb set date nuggets
  require 'set' => /usr/lib/ruby/1.8/set.rb
  require 'date' => /usr/lib/ruby/1.8/date.rb
  require 'nuggets' =>
/usr/lib/ruby/gems/1.8/gems/ruby-nuggets-0.3.1.277/lib/nuggets.rb

  ww@blackwinter:~/devel/scratch> ./modwhich.rb -r set date nuggets
  require 'set' => /usr/lib/ruby/1.8/set.rb
  require 'date' => /usr/lib/ruby/1.8/date.rb
  require 'rational' => /usr/lib/ruby/1.8/rational.rb
  require 'date/format' => /usr/lib/ruby/1.8/date/format.rb
  require 'nuggets' =>
/usr/lib/ruby/gems/1.8/gems/ruby-nuggets-0.3.1.277/lib/nuggets.rb
  require 'fileutils' => /usr/lib/ruby/1.8/fileutils.rb
  require 'etc' => /usr/lib/ruby/1.8/i486-linux/etc.so

  ww@blackwinter:~/devel/scratch> ./modwhich.rb -v set date nuggets
  /usr/lib/ruby/1.8/set.rb
  /usr/lib/ruby/1.8/rational.rb
  /usr/lib/ruby/1.8/date/format.rb
  /usr/lib/ruby/1.8/date.rb
  /usr/lib/ruby/1.8/i486-linux/etc.so
  /usr/lib/ruby/1.8/fileutils.rb
  /usr/lib/ruby/gems/1.8/gems/ruby-nuggets-0.3.1.277/lib/nuggets.rb

  ww@blackwinter:~/devel/scratch> ruby -rmodwhich test_modwhich.rb
  #<Set: {}>
  require 'set' => /usr/lib/ruby/1.8/set.rb
  require 'date' => /usr/lib/ruby/1.8/date.rb
  require 'rational' => /usr/lib/ruby/1.8/rational.rb
  require 'date/format' => /usr/lib/ruby/1.8/date/format.rb

  ww@blackwinter:~/devel/scratch> cat test_modwhich.rb
  require 'set'
  require 'date'
  p Set.new

  ww@blackwinter:~/devel/scratch> irb -r modwhich.rb
    require 'set'
  0.0096 => true
    require 'date', true
  /usr/lib/ruby/1.8/date.rb
  0.0084 => false
    require 'hen', true
  /usr/lib/ruby/gems/1.8/gems/hen-0.1.2.273/lib/hen.rb
  0.1735 => true
    ModWhich.to_h
  0.0003 => ...snip... (see for yourself ;-)
    x
  require 'set' => /usr/lib/ruby/1.8/set.rb
  require 'date' => /usr/lib/ruby/1.8/date.rb
  require 'hen' => /usr/lib/ruby/gems/1.8/gems/hen-0.1.2.273/lib/hen.rb
  require 'yaml' => /usr/lib/ruby/1.8/yaml.rb
  require 'forwardable' => /usr/lib/ruby/1.8/forwardable.rb
  require 'rubygems' => /usr/local/lib/site_ruby/1.8/rubygems.rb
  require 'rake' => /usr/lib/ruby/1.8/rake.rb
  require 'rbconfig' => /usr/lib/ruby/1.8/i486-linux/rbconfig.rb
  require 'ftools' => /usr/lib/ruby/1.8/ftools.rb
  require 'getoptlong' => /usr/lib/ruby/1.8/getoptlong.rb
  require 'fileutils' => /usr/lib/ruby/1.8/fileutils.rb
  require 'singleton' => /usr/lib/ruby/1.8/singleton.rb
  require 'thread' => /usr/lib/ruby/1.8/thread.rb
  require 'ostruct' => /usr/lib/ruby/1.8/ostruct.rb
  [...]

you can also find it on github:
<http://github.com/blackwinter/scratch/tree/master/modwhich.rb>.

cheers
jens

----[ modwhich.rb ]----

#! /usr/bin/env ruby

#--
###############################################################################
#                                                                             #
# modwhich -- Find the location of a library. Solution for Ruby Quiz          #
# "Where the Required Things Are" (#175) by Matthew Moss, 2008/08/29.         #
#                                                                             #
# Copyright (C) 2008 Jens Wille <jens.wille / uni-koeln.de>                     #
#                                                                             #
# modwhich is free software; you can redistribute it and/or modify it under   #
# the terms of the GNU General Public License as published by the Free        #
# Software Foundation; either version 3 of the License, or (at your option)   #
# any later version.                                                          #
#                                                                             #
# modwhich is distributed in the hope that it will be useful, but WITHOUT     #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
# more details.                                                               #
#                                                                             #
# You should have received a copy of the GNU General Public License along     #
# with modwhich. If not, see <http://www.gnu.org/licenses/>.                  #
#                                                                             #
###############################################################################
#++

begin
  require 'rubygems'
  require 'rubygems/commands/which_command'
rescue LoadError
end

class ModWhich

  @verbose, @recursive = false, false

  class << self

    include Enumerable

    attr_writer :verbose, :recursive

    def init(args = nil, recursive = recursive? || args.nil?)
      @args, @recursive = args, recursive

      @which, @load_order, @added_paths = {}, [], []

      unless Object.const_defined?(:SCRIPT_LINES__)
        Object.const_set(:SCRIPT_LINES__, {})
      end

      unless Object.ancestors.include?(Require)
        Object.send(:include, Require)
      end
    end

    def which(mod)
      self.require(mod)
      @which[mod] if @which
    end

    def require(mod, verbose = verbose?)
      if @which && !required?(mod)
        @load_order << mod
        current_paths = loaded_paths

        ret = _modwhich_original_require(mod)

        @added_paths.concat(loaded_paths - current_paths)
        @which[mod] = @added_paths.pop || gemwhich(mod)

        warn @which[mod] if verbose

        ret
      end
    end

    def required?(mod)
      @which && @which.has_key?(mod)
    end

    def verbose?
      @verbose
    end

    def recursive?
      @recursive
    end

    def include?(mod)
      !to_a.assoc(mod).nil?
    end

    def each
      if @load_order
        if @args
          @args.each { |mod| self.require(mod) }
          @load_order &= @args unless recursive?
          @args = nil
        end

        @load_order.each { |mod| yield mod, which(mod) }
      end
    end

    def to_h
      inject({}) { |h, (mod, path)| h.update(mod => path) }
    end

    private

    # basically equivalent to: <tt>%x{gem which #{mod}}.split(/\n/).last</tt>
    def gemwhich(mod)
      if defined?(Gem::Commands::WhichCommand)
        @gemwhich ||= Gem::Commands::WhichCommand.new
        @searcher ||= Gem::GemPathSearcher.new

        dirs = $LOAD_PATH

        if spec = @searcher.find(mod)
          dirs += @gemwhich.gem_paths(spec)
        end

        # return the last (only?) one
        @gemwhich.find_paths(mod, dirs).last
      end
    end

    def loaded_paths
      SCRIPT_LINES__.keys - (@which ? @which.values : [])
    end

  end

  module Require
    unless respond_to?(:_modwhich_original_require)
      alias_method :_modwhich_original_require, :require
    end

    def require(*args) ModWhich.require(*args) end
  end

end

if $0 == __FILE__
  progname = File.basename($0)

  usage = <<-EOT.gsub(/^\s+/, '')
    #{progname} [-v|--verbose] [-r|--recursive] <mod> ...
    #{progname} [-h|--help]
  EOT

  help      = ARGV.delete('-h') || ARGV.delete('--help')
  verbose   = ARGV.delete('-v') || ARGV.delete('--verbose')
  recursive = ARGV.delete('-r') || ARGV.delete('--recursive')

  abort usage if help || ARGV.empty?

  ModWhich.verbose = verbose
  ModWhich.init(ARGV, recursive)

  ARGV.each { |mod| require mod }
else
  ModWhich.init
end

at_exit {
  ModWhich.each { |mod, path|
    warn "require '#{mod}' => #{path || 'NOT FOUND'}"
  } unless ModWhich.verbose?
}

-----------------------

-- 
Jens Wille, Dipl.-Bibl. (FH)
prometheus - Das verteilte digitale Bildarchiv f Forschung & Lehre
Kunsthistorisches Institut der UniversitÁ’ zu KŲžn
Albertus-Magnus-Platz, D-50923 KŲžn
Tel.: +49 (0)221 470-6668, E-Mail: jens.wille / uni-koeln.de
http://www.prometheus-bildarchiv.de/