lib/ver/vendor/fuzzy_file_finder.rb in ver-2009.12.14 vs lib/ver/vendor/fuzzy_file_finder.rb in ver-2010.02
- old
+ new
@@ -35,11 +35,11 @@
# And so forth.
class FuzzyFileFinder
module Version
MAJOR = 1
MINOR = 0
- TINY = 2
+ TINY = 4
STRING = [MAJOR, MINOR, TINY].join(".")
end
# This is the exception that is raised if you try to scan a
# directory tree with too many entries. By default, a ceiling of
@@ -56,11 +56,10 @@
"(#{string})"
else
string
end
end
- alias to_str to_s
end
# Used internally to represent a file within the directory tree.
class FileSystemEntry #:nodoc:
attr_reader :parent
@@ -101,15 +100,18 @@
attr_reader :ceiling
# The prefix shared by all +roots+.
attr_reader :shared_prefix
+ # The list of glob patterns to ignore.
+ attr_reader :ignores
+
# Initializes a new FuzzyFileFinder. This will scan the
# given +directories+, using +ceiling+ as the maximum number
# of entries to scan. If there are more than +ceiling+ entries
# a TooManyEntries exception will be raised.
- def initialize(directories=['.'], ceiling=10_000)
+ def initialize(directories=['.'], ceiling=10_000, ignores=nil)
directories = Array(directories)
directories << "." if directories.empty?
# expand any paths with ~
root_dirnames = directories.map { |d| File.expand_path(d) }.select { |d| File.directory?(d) }.uniq
@@ -119,10 +121,12 @@
@shared_prefix_re = Regexp.new("^#{Regexp.escape(shared_prefix)}" + (shared_prefix.empty? ? "" : "/"))
@files = []
@ceiling = ceiling
+ @ignores = Array(ignores)
+
rescan!
end
# Rescans the subtree. If the directory contents every change,
# you'll need to call this to force the finder to be aware of
@@ -164,11 +168,11 @@
# character.
# * :score refers to a value between 0 and 1 indicating how closely
# the file matches the given pattern. A score of 1 means the
# pattern matches the file exactly.
def search(pattern, &block)
- pattern.strip!
+ pattern.gsub!(" ", "")
path_parts = pattern.split("/")
path_parts.push "" if pattern[-1,1] == "/"
file_name_part = path_parts.pop || ""
@@ -211,22 +215,29 @@
# Recursively scans +directory+ and all files and subdirectories
# beneath it, depth-first.
def follow_tree(directory)
Dir.entries(directory.name).each do |entry|
next if entry[0,1] == "."
+ next if ignore?(directory.name) # Ignore whole directory hierarchies
raise TooManyEntries if files.length > ceiling
full = File.join(directory.name, entry)
if File.directory?(full)
follow_tree(Directory.new(full))
- else
+ elsif !ignore?(full.sub(@shared_prefix_re, ""))
files.push(FileSystemEntry.new(directory, entry))
end
end
end
+ # Returns +true+ if the given name matches any of the ignore
+ # patterns.
+ def ignore?(name)
+ ignores.any? { |pattern| File.fnmatch(pattern, name) }
+ end
+
# Takes the given pattern string "foo" and converts it to a new
# string "(f)([^/]*?)(o)([^/]*?)(o)" that can be used to create
# a regular expression.
def make_pattern(pattern)
pattern = pattern.split(//)
@@ -283,11 +294,13 @@
# If +path+ is already cached in the path_matches cache, just return the cached
# value.
def match_path(path, path_matches, path_regex, path_segments)
return path_matches[path] if path_matches.key?(path)
- matchable_name = path.name.sub(@shared_prefix_re, "")
+ name_with_slash = path.name + "/" # add a trailing slash for matching the prefix
+ matchable_name = name_with_slash.sub(@shared_prefix_re, "")
+ matchable_name.chop! # kill the trailing slash
if path_regex
match = matchable_name.match(path_regex)
path_matches[path] =
@@ -301,11 +314,12 @@
# Match +file+ against +file_regex+. If it matches, yield the match
# metadata to the block.
def match_file(file, file_regex, path_match, &block)
if file_match = file.name.match(file_regex)
match_result = build_match_result(file_match, 1)
- full_match_result = File.join(path_match[:result], match_result[:result])
- abbr = File.join(path_match[:result].gsub(/[^\/]+/) { |m| m.index("(") ? m : m[0,1] }, match_result[:result])
+ full_match_result = path_match[:result].empty? ? match_result[:result] : File.join(path_match[:result], match_result[:result])
+ shortened_path = path_match[:result].gsub(/[^\/]+/) { |m| m.index("(") ? m : m[0,1] }
+ abbr = shortened_path.empty? ? match_result[:result] : File.join(shortened_path, match_result[:result])
result = { :path => file.path,
:abbr => abbr,
:directory => file.parent.name,
:name => file.name,