Project

watchly

0.0
No release in over 3 years
A small, dependency-free, polling-based library that watches one or more glob patterns and reports on change
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

Watchly

Watchly is a lightweight, dependency-free, polling-based file watcher for Ruby. It watches one or more glob patterns and reports file changes in a simple, predictable way.

Watchly is designed around batch semantics: when files change, a single callback is triggered with a complete description of what changed.

An official command-line interface is available via the watchly-cli gem.


Installation

gem install watchly

Or in your Gemfile:

gem 'watchly'

Usage

Initialize a watcher

require 'watchly'

# with the default interval (1 second)
watcher = Watchly::Watcher.new '**/*'

# with a different interval
watcher = Watchly::Watcher.new '**/*', interval: 2.0

# with multiple glob patterns
watcher = Watchly::Watcher.new 'spec/**/*.rb', 'lib/*.*'

Watch for changes

When changes are detected, Watchly yields a Changeset object describing all filesystem changes since the last poll.

watcher.on_change do |changes|
  changes.each do |type, path|
    puts "#{type}: #{path}"
  end
end

This will output events such as:

added: spec/new_spec.rb
modified: lib/watchly.rb
removed: tmp/debug.log

Accessing specific change types

The changes object exposes separate collections for each type of change:

  • changes.added
  • changes.removed
  • changes.modified

Example:

watcher.on_change do |changes|
  puts "Added files:"
  changes.added.each { |path| puts "  + #{path}" }

  puts "Modified files:"
  changes.modified.each { |path| puts "  * #{path}" }

  puts "Removed files:"
  changes.removed.each { |path| puts "  - #{path}" }
end

Working with actionable files

In many cases, you only want to work with files that currently exist.

For this purpose, changes.files provides a convenient, pre-filtered list of actionable files:

  • Includes: added and modified files
  • Excludes: removed files
watcher.on_change do |changes|
  next if changes.empty?

  puts "Processing files:"
  changes.files.each do |path|
    puts "  - #{path}"
  end
end

A changeset that only contains removed files is considered empty. This prevents unnecessary processing when files are deleted.


Checking for changes

You can test whether a changeset contains any actionable files:

watcher.on_change do |changes|
  if changes.any?
    puts "Files changed:"
    changes.files.each { |path| puts "  - #{path}" }
  else
    puts "Files were removed:"
    changes.removed.each { |path| puts "  - #{path}" }
  end
end

Or explicitly:

changes.empty? # => true if no added or modified files
changes.any?   # => true if at least one actionable file exists

The on_change callback is triggered for any filesystem change, including deletions. The any? and empty? helpers reflect whether there are actionable files (added or modified).


Stopping the watcher

# Mainly useful for tests, but can be called from another thread
watcher.stop

Contributing / Support

If you experience any issue, have a question, or wish to contribute, feel free to open an issue.