2026-01-26 05:12:14 +01:00
{# retoor < retoor @ molodetz . nl > #}
{% extends 'page.html' %}
2026-01-25 13:09:28 +01:00
2026-01-26 05:12:14 +01:00
{% set page_title = "fswatch" %}
{% set breadcrumb = [{"url": "api/index.html", "title": "API Reference"}, {"title": "fswatch"}] %}
{% set prev_page = {"url": "api/faker.html", "title": "faker"} %}
{% set next_page = {"url": "api/html.html", "title": "html"} %}
{% block article %}
2026-01-25 13:09:28 +01:00
< h1 > fswatch</ h1 >
< p > The < code > fswatch</ code > module provides file system watching capabilities, allowing scripts to monitor files and directories for changes in real-time. Built on libuv's filesystem events.</ p >
< pre >< code > import "fswatch" for FileWatcher, FsEvent</ code ></ pre >
< div class = "toc" >
< h4 > On This Page</ h4 >
< ul >
< li >< a href = "#filewatcher-class" > FileWatcher Class</ a ></ li >
< li >< a href = "#fsevent-class" > FsEvent Class</ a ></ li >
< li >< a href = "#examples" > Examples</ a ></ li >
</ ul >
</ div >
< h2 id = "filewatcher-class" > FileWatcher Class</ h2 >
< div class = "class-header" >
< h3 > FileWatcher</ h3 >
< p > Monitors a file or directory for changes</ p >
</ div >
< h3 > Constructor</ h3 >
< div class = "method-signature" >
< span class = "method-name" > FileWatcher.new</ span > (< span class = "param" > path</ span > ) → < span class = "type" > FileWatcher</ span >
</ div >
< p > Creates a new FileWatcher for the specified path. The path can be a file or directory.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > path</ span > < span class = "param-type" > (String)</ span > - Path to the file or directory to watch</ li >
</ ul >
< pre >< code > var watcher = FileWatcher.new("./config.json")
var dirWatcher = FileWatcher.new("./src")</ code ></ pre >
< h3 > Methods</ h3 >
< div class = "method-signature" >
< span class = "method-name" > start</ span > (< span class = "param" > callback</ span > )
</ div >
< p > Starts watching for changes. The callback function is invoked with an FsEvent whenever a change is detected.</ p >
< ul class = "param-list" >
< li >< span class = "param-name" > callback</ span > < span class = "param-type" > (Fn)</ span > - Function that receives an FsEvent parameter</ li >
</ ul >
< pre >< code > watcher.start { |event|
System.print("Changed: %(event.filename)")
}</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > stop</ span > ()
</ div >
< p > Stops watching for changes.</ p >
< pre >< code > watcher.stop()</ code ></ pre >
< h3 > Properties</ h3 >
< div class = "method-signature" >
< span class = "method-name" > isActive</ span > → < span class = "type" > Bool</ span >
</ div >
< p > Returns true if the watcher is currently active.</ p >
< pre >< code > if (watcher.isActive) {
System.print("Watcher is running")
}</ code ></ pre >
< h2 id = "fsevent-class" > FsEvent Class</ h2 >
< div class = "class-header" >
< h3 > FsEvent</ h3 >
< p > Represents a file system change event</ p >
</ div >
< h3 > Properties</ h3 >
< div class = "method-signature" >
< span class = "method-name" > filename</ span > → < span class = "type" > String</ span >
</ div >
< p > The name of the file that changed. For directory watchers, this is the relative filename within the directory.</ p >
< pre >< code > System.print("File changed: %(event.filename)")</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > isRename</ span > → < span class = "type" > Bool</ span >
</ div >
< p > True if the event is a rename/move operation. This includes file creation and deletion.</ p >
< pre >< code > if (event.isRename) {
System.print("File renamed/created/deleted")
}</ code ></ pre >
< div class = "method-signature" >
< span class = "method-name" > isChange</ span > → < span class = "type" > Bool</ span >
</ div >
< p > True if the event is a content change.</ p >
< pre >< code > if (event.isChange) {
System.print("File content modified")
}</ code ></ pre >
< h2 id = "examples" > Examples</ h2 >
< h3 > Watch a Single File</ h3 >
< pre >< code > import "fswatch" for FileWatcher
var watcher = FileWatcher.new("./config.json")
watcher.start { |event|
System.print("Config changed!")
System.print(" Rename: %(event.isRename)")
System.print(" Change: %(event.isChange)")
}
System.print("Watching config.json for changes...")
System.print("Press Ctrl+C to stop")</ code ></ pre >
< h3 > Watch a Directory</ h3 >
< pre >< code > import "fswatch" for FileWatcher
var watcher = FileWatcher.new("./src")
watcher.start { |event|
System.print("[%(event.filename)]")
if (event.isRename) {
System.print(" Created/Deleted/Renamed")
}
if (event.isChange) {
System.print(" Modified")
}
}
System.print("Watching ./src directory...")
System.print("Press Ctrl+C to stop")</ code ></ pre >
< h3 > Auto-Reload Configuration</ h3 >
< pre >< code > import "fswatch" for FileWatcher
import "io" for File
import "json" for Json
var config = {}
var loadConfig = Fn.new {
var content = File.read("config.json")
config = Json.parse(content)
System.print("Config loaded: %(config)")
}
loadConfig.call()
var watcher = FileWatcher.new("./config.json")
watcher.start { |event|
System.print("Config file changed, reloading...")
loadConfig.call()
}
System.print("Running with auto-reload...")</ code ></ pre >
< h3 > Build on Change</ h3 >
< pre >< code > import "fswatch" for FileWatcher
import "subprocess" for Subprocess
var watcher = FileWatcher.new("./src")
var build = Fn.new {
System.print("Building...")
var result = Subprocess.run("make", ["build"])
if (result.exitCode == 0) {
System.print("Build successful!")
} else {
System.print("Build failed!")
System.print(result.stderr)
}
}
watcher.start { |event|
if (event.filename.endsWith(".c") || event.filename.endsWith(".h")) {
System.print("%(event.filename) changed")
build.call()
}
}
System.print("Watching for source changes...")</ code ></ pre >
< h3 > Multiple Watchers</ h3 >
< pre >< code > import "fswatch" for FileWatcher
var srcWatcher = FileWatcher.new("./src")
var testWatcher = FileWatcher.new("./test")
srcWatcher.start { |event|
System.print("[SRC] %(event.filename)")
}
testWatcher.start { |event|
System.print("[TEST] %(event.filename)")
}
System.print("Watching src/ and test/ directories...")</ code ></ pre >
< h3 > Debounced Watcher</ h3 >
< pre >< code > import "fswatch" for FileWatcher
import "timer" for Timer
import "datetime" for DateTime
var lastChange = null
var debounceMs = 500
var watcher = FileWatcher.new("./src")
watcher.start { |event|
var now = DateTime.now()
if (lastChange == null || (now - lastChange).milliseconds > debounceMs) {
lastChange = now
System.print("Change detected: %(event.filename)")
}
}
System.print("Watching with %(debounceMs)ms debounce...")</ code ></ pre >
< h3 > Graceful Shutdown</ h3 >
< pre >< code > import "fswatch" for FileWatcher
import "signal" for Signal
var watcher = FileWatcher.new("./data")
watcher.start { |event|
System.print("%(event.filename) changed")
}
Signal.trap(Signal.SIGINT) {
System.print("\nStopping watcher...")
watcher.stop()
System.print("Watcher stopped: %(watcher.isActive)")
}
System.print("Watching ./data (Ctrl+C to stop)")</ code ></ pre >
< div class = "admonition note" >
< div class = "admonition-title" > Note</ div >
< p > File system event behavior varies by operating system. On some platforms, multiple events may be delivered for a single change, or event types may overlap (both < code > isRename</ code > and < code > isChange</ code > true).</ p >
</ div >
< div class = "admonition tip" >
< div class = "admonition-title" > Tip</ div >
< p > When watching directories, the < code > filename</ code > property contains the relative path of the changed file within the watched directory, not the full path.</ p >
</ div >
< div class = "admonition warning" >
< div class = "admonition-title" > Warning</ div >
< p > Watching a large directory tree may consume significant system resources. Consider watching specific subdirectories when possible.</ p >
</ div >
2026-01-26 05:12:14 +01:00
{% endblock %}