From: Jens Wille Date: 2008-09-01T01:42:33+09:00 Subject: Re: [QUIZ][SOLUTION] Where the Required Things Are (#175) 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 # 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: . 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 # # # # 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 . # # # ############################################################################### #++ 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: %x{gem which #{mod}}.split(/\n/).last 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] ... #{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�r Forschung & Lehre Kunsthistorisches Institut der Universit�t zu K�ln Albertus-Magnus-Platz, D-50923 K�ln Tel.: +49 (0)221 470-6668, E-Mail: jens.wille@uni-koeln.de http://www.prometheus-bildarchiv.de/