ruby 48 lines · 7 steps

Polling for file changes in Ruby

A DirectoryWatcher that detects added, removed, and changed files by comparing periodic snapshots of a directory tree.

Explained by highlit
1require 'set'
2 
3class DirectoryWatcher
4 def initialize(path, pattern: '**/*', interval: 1.0)
5 @path = File.expand_path(path)
6 @pattern = pattern
7 @interval = interval
8 @snapshot = {}
9 @running = false
10 end
11 
12 def watch(&block)
13 @snapshot = scan
14 @running = true
15 
16 while @running
17 sleep @interval
18 current = scan
19 
20 added = current.keys - @snapshot.keys
21 removed = @snapshot.keys - current.keys
22 changed = (current.keys & @snapshot.keys).select do |file|
23 current[file] != @snapshot[file]
24 end
25 
26 unless added.empty? && removed.empty? && changed.empty?
27 block.call(added: added, removed: removed, changed: changed)
28 end
29 
30 @snapshot = current
31 end
32 end
33 
34 def stop
35 @running = false
36 end
37 
38 private
39 
40 def scan
41 Dir.glob(File.join(@path, @pattern)).each_with_object({}) do |file, acc|
42 next unless File.file?(file)
43 acc[file] = File.mtime(file).to_f
44 rescue Errno::ENOENT
45 next
46 end
47 end
48end
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Diffing two point-in-time snapshots turns state into a stream of change events.
  2. 2Modification timestamps are a cheap proxy for detecting that a file's contents changed.
  3. 3A shared boolean flag lets an external caller cleanly break out of a blocking loop.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Polling for file changes in Ruby — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code