class FileIndexer::Indexer

A simple file indexer, keeps a database of files and associated metadata

Attributes

action[RW]

This is a Proc that will be called for every file and its result will be stored in the database

db_file[R]

This is the filename which will be used as the persistent database

dirs[RW]

The directories that will be indexed

exts[RW]

Only files with these extensions will be considered. Just use '*' for all files.

files[RW]

This is the actual database of files, it is a Hash

Public Class Methods

new(dirs, exts, db_file, &action) click to toggle source
# 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(fs) click to toggle source

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
index!(fs) click to toggle source

@see index

# File lib/file_indexer/indexer.rb, line 60
def index!(fs)
  files.merge!(index(fs))
  changed!
  files
end
index_all(dirs = @dirs, exts = @exts) click to toggle source

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
index_all!(dirs = @dirs, exts = @exts) click to toggle source

@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!() click to toggle source

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_db() click to toggle source

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() click to toggle source

Stop watching directories for changes

# File lib/file_indexer/indexer.rb, line 83
def stop
  @listener&.stop
end
watch(dirs = @dirs, exts = @exts) click to toggle source

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_db() click to toggle source

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

changed!(*args) click to toggle source

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(dir, exts = @exts) click to toggle source

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
sanitize_dirpath(dir) click to toggle source

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