class FileIndexer::Indexer
A simple file indexer, keeps a database of files and associated metadata
Attributes
This is a Proc that will be called for every file and its result will be stored in the database
This is the filename which will be used as the persistent database
The directories that will be indexed
Only files with these extensions will be considered. Just use '*' for all files.
This is the actual database of files, it is a Hash
Public Class Methods
# File lib/file_indexer/indexer.rb, line 25 def initialize(dirs, exts, db_file, &action) @dirs = dirs.map { |d| sanitize_dirpath(d) } @exts = exts @db_file = db_file @action = action @files = {} @listener = nil @files.merge!(read_db) prune! index_all! end
Public Instance Methods
Index a list of files
# File lib/file_indexer/indexer.rb, line 52 def index(fs) fs.map do |file| next if files.key?(file) [file, action.(file)] end.compact.to_h end
@see index
# File lib/file_indexer/indexer.rb, line 60 def index!(fs) files.merge!(index(fs)) changed! files end
Index multiple directories
# File lib/file_indexer/indexer.rb, line 40 def index_all(dirs = @dirs, exts = @exts) dirs.map { |dir| index(glob(dir, exts)) }.reduce(&:merge) end
@see index_all
# File lib/file_indexer/indexer.rb, line 45 def index_all!(dirs = @dirs, exts = @exts) files.merge!(index_all(dirs, exts)) changed! files end
Prune nonexistant files from the index
# File lib/file_indexer/indexer.rb, line 67 def prune! files.select! { |f,_| File.exist?(f) }.to_h end
Read the database from disk
# File lib/file_indexer/indexer.rb, line 93 def read_db return {} unless File.exist?(db_file) File.open(db_file, 'r') { |f| Marshal.load(f.read) } end
Stop watching directories for changes
# File lib/file_indexer/indexer.rb, line 83 def stop @listener&.stop end
Watch directories for changes using the listen gem, when called make sure to call stop
when done watching.
# File lib/file_indexer/indexer.rb, line 73 def watch(dirs = @dirs, exts = @exts) @listener = Listen.to(*dirs, only: /\.(#{exts.join('|')})$/) do |mod, add, del| del.each { |f| files.delete(f) } index!(mod + add) end @listener.start end
Write the databse to disk
# File lib/file_indexer/indexer.rb, line 88 def write_db File.open(db_file, 'w') { |f| f.puts(Marshal.dump(files)) } end
Private Instance Methods
Notify observers of changes and rewrite the database file
# File lib/file_indexer/indexer.rb, line 111 def changed!(*args) changed write_db notify_observers(*args) end
Glob all files with certain extensions in a directory
# File lib/file_indexer/indexer.rb, line 106 def glob(dir, exts = @exts) Dir.glob("#{dir}**/*.{#{exts.join(',')}}") end
Makes sure a directory exists, and sanitizes it
# File lib/file_indexer/indexer.rb, line 101 def sanitize_dirpath(dir) Pathname.new(File.expand_path(dir)).realpath.to_s end