Fix up Rubinius specific library specs.
[rbx.git] / lib / rubygems / gem_path_searcher.rb
blobdadad662899a55c3a21baa63606d43dee8ce266c
1 #--
2 # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
3 # All rights reserved.
4 # See LICENSE.txt for permissions.
5 #++
7 require 'rubygems'
10 # GemPathSearcher has the capability to find loadable files inside
11 # gems.  It generates data up front to speed up searches later.
13 class Gem::GemPathSearcher
15   #
16   # Initialise the data we need to make searches later.
17   #
18   def initialize
19     # We want a record of all the installed gemspecs, in the order
20     # we wish to examine them.
21     @gemspecs = init_gemspecs
22     # Map gem spec to glob of full require_path directories.
23     # Preparing this information may speed up searches later.
24     @lib_dirs = {}
25     @gemspecs.each do |spec|
26       @lib_dirs[spec.object_id] = lib_dirs_for(spec)
27     end
28   end
30   # 
31   # Look in all the installed gems until a matching _path_ is found.
32   # Return the _gemspec_ of the gem where it was found.  If no match
33   # is found, return nil.
34   #
35   # The gems are searched in alphabetical order, and in reverse
36   # version order.
37   #
38   # For example:
39   #
40   #   find('log4r')              # -> (log4r-1.1 spec)
41   #   find('log4r.rb')           # -> (log4r-1.1 spec)
42   #   find('rake/rdoctask')      # -> (rake-0.4.12 spec)
43   #   find('foobarbaz')          # -> nil
44   #
45   # Matching paths can have various suffixes ('.rb', '.so', and
46   # others), which may or may not already be attached to _file_.
47   # This method doesn't care about the full filename that matches;
48   # only that there is a match.
49   # 
50   def find(path)
51     @gemspecs.each do |spec|
52       return spec if matching_file(spec, path)
53     end
54     nil
55   end
57   private
59   # Attempts to find a matching path using the require_paths of the
60   # given _spec_.
61   #
62   # Some of the intermediate results are cached in @lib_dirs for
63   # speed.
64   def matching_file(spec, path)  # :doc:
65     glob = File.join @lib_dirs[spec.object_id], "#{path}#{Gem.suffix_pattern}"
66     return true unless Dir[glob].select { |f| File.file?(f.untaint) }.empty?
67   end
69   # Return a list of all installed gemspecs, sorted by alphabetical
70   # order and in reverse version order.
71   def init_gemspecs
72     Gem.source_index.map { |_, spec| spec }.sort { |a,b|
73       (a.name <=> b.name).nonzero? || (b.version <=> a.version)
74     }
75   end
77   # Returns library directories glob for a gemspec.  For example,
78   #   '/usr/local/lib/ruby/gems/1.8/gems/foobar-1.0/{lib,ext}'
79   def lib_dirs_for(spec)
80     "#{spec.full_gem_path}/{#{spec.require_paths.join(',')}}"
81   end
83 end