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,