class Utils::Finder
finder.search
finder = Utils::Finder.new(args: { l: true }, roots: [‘.’])
@example
file sets.
optimize performance when dealing with large codebases or frequently accessed
pattern matching. It supports both indexed and direct search approaches to
based on various criteria including file extensions, directory pruning, and
This class provides functionality for traversing file systems to locate files
filters.
A class for finding and searching files with configurable patterns and
def build_paths
-
(Array)
- an array of file system path strings, with directories
def build_paths paths = [] visit = -> filename { s = filename.stat bn = filename.pathname.basename if !s || s.directory? && @config.discover.prune?(bn) || s.file? && @config.discover.skip?(bn) then @args[?v] and warn "Pruning #{filename.inspect}." prune end true } find(*@roots, visit: visit) do |filename| filename.stat.directory? and filename << ?/ paths << filename end paths.uniq! paths end
def create_paths
-
(Array)
- an array containing the paths that were built and written
def create_paths paths = build_paths File.secure_write(index_path) do |output| output.puts paths end paths end
def discover_roots(roots)
-
(Array
- an array of expanded directory paths that match)
Parameters:
-
roots
(Array
) -- an array of root patterns or nil, nil
def discover_roots(roots) roots ||= [] roots.inject([]) { |rs, r| rs.concat Dir[r] } end
def index_expired?(path)
-
(TrueClass, FalseClass)
- true if the index file has expired, false otherwise
Parameters:
-
path
(String
) -- the filesystem path to the index file being checked
def index_expired?(path) if duration = @config.discover.index_expire_after Time.now - duration >= File.mtime(path) else false end rescue Errno::ENOENT false end
def index_path
-
(String)
- the full file path where finder results should be stored
def index_path roots = @roots.map { |r| File.expand_path(r) }.uniq.sort filename = "finder-paths-" + Digest::MD5.new.update(roots.inspect).hexdigest dirname = File.join(Dir.tmpdir, File.basename($0)) FileUtils.mkdir_p dirname File.join(dirname, filename) end
def initialize(opts = {})
(**opts)
-
:config
(Utils::ConfigFile
) -- the configuration file object -
:roots
(Array
) -- the root directories to search in -
:args
(Hash
) -- the argument options for the finder
Parameters:
-
opts
(Hash
) -- the options hash containing configuration settings
def initialize(opts = {}) @args = opts[:args] || {} @roots = discover_roots(opts[:roots]) @config = opts[:config] || Utils::ConfigFile.new if @args[?l] || @args[?L] @pattern = nil else pattern_opts = opts.subhash(:pattern) | { :cset => @args[?a], :icase => @args[?i] != ?n, } @pattern = choose(@args[?p], pattern_opts) end @paths = [] reset_index end
def load_paths
def load_paths lines = File.readlines(index_path) @args[?v] and warn "Loaded index #{index_path.inspect}." lines.empty? and raise Errno::ENOENT @args[?d] or lines = lines.grep_v(%r{/$}) lines.map(&:chomp!) rescue Errno::ENOENT return create_paths end
def reset_index
-
(Utils::Finder)
- returns self to allow for method chaining
def reset_index path = index_path if @args[?r] || index_expired?(path) @args[?v] and warn "Resetting index #{path.inspect}." FileUtils.rm_f path mize_cache_clear end self end
def search_directly
-
(Object)
- the result of the search operation performed on the built paths
def search_directly search_paths build_paths end
def search_index
filter and return relevant results based on the current search
a search operation, applying the configured pattern matching criteria to
This method utilizes the loaded paths from the internal storage to execute
paths.
The search_index method performs a pattern search across previously loaded
def search_index search_paths load_paths end
def search_paths(paths)
-
(Utils::Finder)
- returns self to allow for method chaining
Parameters:
-
paths
(Array
) -- the collection of file paths to be processed
def search_paths(paths) suffixes = Array(@args[?I]) suffixes.full? do |s| paths.select! { |path| s.include?(File.extname(path)[1..-1]) } end paths = paths.map! do |path| if @pattern.nil? [ [ path.count(?/), path ], path, path ] elsif match = @pattern.match(path) if FuzzyPattern === @pattern current = 0 marked_path = '' score, e = path.size, nil for i in 1...match.size match[i] or next b = match.begin(i) e ||= b marked_path << path[current...b] marked_path << red(path[b, 1]) score += (b - e) * (path.size - b) e = match.end(i) current = b + 1 end marked_path << match.post_match [ score, path, marked_path ] else marked_path = path[0...match.begin(0)] << red(path[match.begin(0)...match.end(0)]) << path[match.end(0)..-1] [ 0, path, marked_path ] end end end paths.compact! @paths, @output = paths.sort.transpose.values_at(-2, -1) if n = @args[?n]&.to_i @paths = @paths&.first(n) || [] @output = @output&.first(n) || [] end self end