Getting Started
This guide explains how to use build-files-monitor
to efficiently monitor the filesystem for changes.
Installation
Add the gem to your project:
$ bundle add build-files-monitor
Core Concepts
build-files-monitor
provides efficient filesystem monitoring using platform-specific native APIs:
module Build::Files::Monitor
- The main entry point that creates native filesystem monitors.class Build::Files::Monitor::Native
- Uses platform-specific APIs (FSEvent on macOS, INotify on Linux, etc.) via theio-watch
gem for efficient, event-driven monitoring.class Build::Files::Monitor::Polling
- An alternative implementation that works by polling the filesystem. You can use this directly if needed, thoughMonitor
usesNative
by default.class Build::Files::Monitor::Handle
- Represents a tracked directory with a callback that fires when changes are detected.
Usage
Basic File Monitoring
Here's a simple example that monitors a directory for changes:
require "build/files/path"
require "build/files/directory"
require "build/files/monitor"
# Create a path to monitor:
root = Build::Files::Path.current
# Monitor everything within this directory, recursively:
directory = Build::Files::Directory.new(root)
# Create a monitor instance (uses native platform APIs):
monitor = Build::Files::Monitor.new
# Track changes with a callback:
monitor.track_changes(directory) do |state|
puts "Files added: #{state.added.inspect}"
puts "Files changed: #{state.changed.inspect}"
puts "Files removed: #{state.removed.inspect}"
end
# Run the monitor (blocking):
monitor.run
Detecting Specific Changes
The state object passed to your callback provides detailed information about what changed:
monitor.track_changes(directory) do |state|
# Check for specific types of changes:
unless state.added.empty?
puts "New files detected:"
state.added.each do |path|
puts " + #{path}"
end
end
unless state.changed.empty?
puts "Modified files:"
state.changed.each do |path|
puts " ~ #{path}"
end
end
unless state.removed.empty?
puts "Deleted files:"
state.removed.each do |path|
puts " - #{path}"
end
end
end
Running with Custom Latency
You can control how often the monitor checks for changes:
# Check for changes every 2 seconds (default is 0.1 seconds):
monitor.run(latency: 2.0) do
# Optional block that runs after each check:
puts "Checked at #{Time.now}"
end
Stopping the Monitor
Use throw :interrupt
to stop the monitor from within your callback or the run block:
changes_detected = 0
monitor.track_changes(directory) do |state|
changes_detected += 1
# Stop after detecting 5 changes:
if changes_detected >= 5
puts "Detected 5 changes, stopping monitor"
throw :interrupt
end
end
monitor.run
puts "Monitoring stopped"
Monitoring Multiple Directories
You can track changes in multiple directories simultaneously:
monitor = Build::Files::Monitor.new
# Track the first directory:
dir1 = Build::Files::Directory.new(Build::Files::Path.expand("src"))
monitor.track_changes(dir1) do |state|
puts "Changes in src/: #{state.added.size + state.changed.size}"
end
# Track a second directory:
dir2 = Build::Files::Directory.new(Build::Files::Path.expand("config"))
monitor.track_changes(dir2) do |state|
puts "Changes in config/: #{state.added.size + state.changed.size}"
end
# Run the monitor for both:
monitor.run
Removing Tracked Directories
You can stop monitoring a directory by calling remove!
on the handle:
handle = monitor.track_changes(directory) do |state|
puts "Change detected!"
end
# Later, stop monitoring this directory:
handle.remove!
Using Specific Implementations
By default, Build::Files::Monitor.new
creates a Native
monitor. You can also directly instantiate specific implementations:
# Use native monitoring (default):
monitor = Build::Files::Monitor::Native.new
# Or use polling mode (useful for testing or special scenarios):
monitor = Build::Files::Monitor::Polling.new