Class: FileIndexer::Indexer

Inherits:
Object
  • Object
show all
Includes:
Observable
Defined in:
lib/file_indexer/indexer.rb

Overview

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dirs, exts, db_file, &action) ⇒ Indexer

Returns a new instance of Indexer.



25
26
27
28
29
30
31
32
33
34
35
36
37
# 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

Instance Attribute Details

#actionObject

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



19
20
21
# File 'lib/file_indexer/indexer.rb', line 19

def action
  @action
end

#db_fileObject (readonly)

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



23
24
25
# File 'lib/file_indexer/indexer.rb', line 23

def db_file
  @db_file
end

#dirsObject

The directories that will be indexed



13
14
15
# File 'lib/file_indexer/indexer.rb', line 13

def dirs
  @dirs
end

#extsObject

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



16
17
18
# File 'lib/file_indexer/indexer.rb', line 16

def exts
  @exts
end

#filesObject

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



21
22
23
# File 'lib/file_indexer/indexer.rb', line 21

def files
  @files
end

Instance Method Details

#index(fs) ⇒ Object

Index a list of files



52
53
54
55
56
57
# 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) ⇒ Object

See Also:



60
61
62
63
64
# File 'lib/file_indexer/indexer.rb', line 60

def index!(fs)
  files.merge!(index(fs))
  changed!
  files
end

#index_all(dirs = @dirs, exts = @exts) ⇒ Object

Index multiple directories



40
41
42
# 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) ⇒ Object

See Also:



45
46
47
48
49
# 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!Object

Prune nonexistant files from the index



67
68
69
# File 'lib/file_indexer/indexer.rb', line 67

def prune!
  files.select! { |f,_| File.exist?(f) }.to_h
end

#read_dbObject

Read the database from disk



93
94
95
96
# 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

#stopObject

Stop watching directories for changes



83
84
85
# File 'lib/file_indexer/indexer.rb', line 83

def stop
  @listener&.stop
end

#watch(dirs = @dirs, exts = @exts) ⇒ Object

Watch directories for changes using the listen gem, when called make sure to call #stop when done watching.



73
74
75
76
77
78
79
80
# 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_dbObject

Write the databse to disk



88
89
90
# File 'lib/file_indexer/indexer.rb', line 88

def write_db
  File.open(db_file, 'w') { |f| f.puts(Marshal.dump(files)) }
end