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
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Diffing two point-in-time snapshots turns state into a stream of change events.
- 2Modification timestamps are a cheap proxy for detecting that a file's contents changed.
- 3A shared boolean flag lets an external caller cleanly break out of a blocking loop.
Related explainers
ruby
class ApplicationController < ActionController::Base ALLOWED_REDIRECT_HOSTS = [nil, ENV.fetch("APP_HOST", "app.example.com")].freeze def store_return_to(location = request.fullpath)
Safe post-login redirects in Rails
open-redirect
session
authentication
Intermediate
9 steps
ruby
class HashDiff Change = Struct.new(:from, :to) def self.call(before, after)
Diffing two hashes in Ruby
set-operations
struct
enumerable
Intermediate
7 steps
ruby
module CreditCard module_function def valid?(number)
Validating credit card numbers with Luhn
checksum
luhn-algorithm
validation
Intermediate
6 steps
ruby
class UserColor GOLDEN_RATIO_CONJUGATE = 0.618033988749895 def initialize(username)
Deriving a stable color from a username
hashing
color-theory
deterministic-mapping
Intermediate
7 steps
ruby
namespace :counter_cache do desc "Recalculate comments_count for posts after a backfill" task warm_post_comments: :environment do scope = Post.where(comments_count: nil).or(Post.where("comments_count < 0"))
Backfilling counter caches in a Rake task in Rails
counter-cache
batching
rake-tasks
Intermediate
6 steps
ruby
class ToastBroadcaster include ActionView::RecordIdentifier def self.broadcast_to(user, message:, type: :notice)
How Turbo Stream toasts broadcast in Rails
turbo-streams
service-object
real-time
Intermediate
6 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/polling-for-file-changes-in-ruby-explained-ruby-6abd/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.