Class: Gem::GemPathSearcher

Inherits:
Object
  • Object
show all
Extended by:
Deprecate
Defined in:
lib/rubygems/gem_path_searcher.rb

Overview

GemPathSearcher has the capability to find loadable files inside gems. It generates data up front to speed up searches later.

Instance Method Summary collapse

Methods included from Deprecate

deprecate, skip, skip=, skip_during

Constructor Details

#initializeGemPathSearcher

Initialise the data we need to make searches later.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/rubygems/gem_path_searcher.rb', line 13

def initialize
  # We want a record of all the installed gemspecs, in the order we wish to
  # examine them.
  # TODO: remove this stupid method
  @gemspecs = init_gemspecs

  # Map gem spec to glob of full require_path directories.  Preparing this
  # information may speed up searches later.
  @lib_dirs = {}

  @gemspecs.each do |spec|
    @lib_dirs[spec.object_id] = lib_dirs_for spec
  end
end

Instance Method Details

#find(glob) ⇒ Object

Look in all the installed gems until a matching glob is found. Return the gemspec of the gem where it was found. If no match is found, return nil.

The gems are searched in alphabetical order, and in reverse version order.

For example:

find('log4r')              # -> (log4r-1.1 spec)
find('log4r.rb')           # -> (log4r-1.1 spec)
find('rake/rdoctask')      # -> (rake-0.4.12 spec)
find('foobarbaz')          # -> nil

Matching paths can have various suffixes ('.rb', '.so', and others), which may or may not already be attached to file. This method doesn't care about the full filename that matches; only that there is a match.



48
49
50
51
52
53
54
# File 'lib/rubygems/gem_path_searcher.rb', line 48

def find(glob)
  # HACK violation of encapsulation
  @gemspecs.find do |spec|
    # TODO: inverted responsibility
    matching_file? spec, glob
  end
end

#find_active(glob) ⇒ Object



65
66
67
68
69
70
71
# File 'lib/rubygems/gem_path_searcher.rb', line 65

def find_active(glob)
  # HACK violation of encapsulation
  @gemspecs.find do |spec|
    # TODO: inverted responsibility
    spec.loaded? and matching_file? spec, glob
  end
end

#find_all(glob) ⇒ Object

Works like #find, but finds all gemspecs matching glob.



76
77
78
79
80
81
82
# File 'lib/rubygems/gem_path_searcher.rb', line 76

def find_all(glob)
  # HACK violation of encapsulation
  @gemspecs.select do |spec|
    # TODO: inverted responsibility
    matching_file? spec, glob
  end || []
end

#find_in_unresolved(glob) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
# File 'lib/rubygems/gem_path_searcher.rb', line 84

def find_in_unresolved(glob)
  # HACK violation
  specs = Gem.unresolved_deps.values.map { |dep|
    Gem.source_index.search dep, true
  }.flatten

  specs.select do |spec|
    # TODO: inverted responsibility
    matching_file? spec, glob
  end || []
end

#find_in_unresolved_tree(glob) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/rubygems/gem_path_searcher.rb', line 96

def find_in_unresolved_tree glob
  # HACK violation
  # TODO: inverted responsibility
  specs = Gem.unresolved_deps.values.map { |dep|
    Gem.source_index.search dep, true
  }.flatten

  specs.reverse_each do |spec|
    trails = matching_paths(spec, glob)
    next if trails.empty?
    return trails.map(&:reverse).sort.first.reverse
  end

  []
end

#find_spec_for_file(file) ⇒ Object

Looks through the available gemspecs and finds the first one that contains file as a requirable file.



59
60
61
62
63
# File 'lib/rubygems/gem_path_searcher.rb', line 59

def find_spec_for_file(file)
  @gemspecs.find do |spec|
    return spec if spec.contains_requirable_file?(file)
  end
end

#init_gemspecsObject

Return a list of all installed gemspecs, sorted by alphabetical order and in reverse version order. (bar-2, bar-1, foo-2)



146
147
148
149
150
151
152
# File 'lib/rubygems/gem_path_searcher.rb', line 146

def init_gemspecs
  Gem::Specification.sort { |a, b|
    names = a.name <=> b.name
    next names if names.nonzero?
    b.version <=> a.version
  }
end

#lib_dirs_for(spec) ⇒ Object

Returns library directories glob for a gemspec. For example,

'/usr/local/lib/ruby/gems/1.8/gems/foobar-1.0/{lib,ext}'


158
159
160
161
# File 'lib/rubygems/gem_path_searcher.rb', line 158

def lib_dirs_for(spec)
  "#{spec.full_gem_path}/{#{spec.require_paths.join(',')}}" if
    spec.require_paths
end

#matching_file?(spec, path) ⇒ Boolean

Attempts to find a matching path using the require_paths of the given spec.

Returns:

  • (Boolean)


116
117
118
# File 'lib/rubygems/gem_path_searcher.rb', line 116

def matching_file?(spec, path)
  not matching_files(spec, path).empty?
end

#matching_files(spec, path) ⇒ Object

Returns files matching path in spec. -- Some of the intermediate results are cached in @lib_dirs for speed.



136
137
138
139
140
# File 'lib/rubygems/gem_path_searcher.rb', line 136

def matching_files(spec, path)
  return [] unless @lib_dirs[spec.object_id] # case no paths
  glob = File.join @lib_dirs[spec.object_id], "#{path}#{Gem.suffix_pattern}"
  Dir[glob].select { |f| File.file? f.untaint }
end

#matching_paths(spec, path) ⇒ Object



120
121
122
123
124
125
126
127
128
129
# File 'lib/rubygems/gem_path_searcher.rb', line 120

def matching_paths(spec, path)
  trails = []

  spec.traverse do |from_spec, dep, to_spec, trail|
    next unless to_spec.conflicts.empty?
    trails << trail unless matching_files(to_spec, path).empty?
  end

  trails
end