Build::Files::MonitorSourceBuildFilesMonitorPolling

class Polling

A cross-platform filesystem monitor that uses polling to detect changes.

This implementation works on all platforms by periodically checking file modification times. While less efficient than platform-specific native implementations, it provides a reliable fallback for platforms without native filesystem event support.

Definitions

def initialize(logger: nil)

Initialize a new polling monitor.

Signature

parameter logger Logger

Optional logger for debugging monitor activity.

Implementation

def initialize(logger: nil)
	@directories = Hash.new do |hash, key|
		hash[key] = Set.new
	end
	
	@updated = false
	
	@deletions = nil
	
	@logger = logger || Logger.new(nil)
end

attr :updated

Signature

attribute Boolean

Whether the set of monitored directories has been updated.

def update(directories, *args)

Notify the monitor that files in these directories have changed.

Implementation

def update(directories, *args)
	@logger.debug{"Update: #{directories} #{args.inspect}"}
	
	delay_deletions do
		directories.each do |directory|
			@logger.debug{"Directory: #{directory}"}
			
			@directories[directory].each do |handle|
				@logger.debug{"Handle changed: #{handle.inspect}"}
				
				# Changes here may not actually require an update to the handle:
				handle.changed!(*args)
			end
		end
	end
end

def roots

Signature

returns Array(String)

The root directories currently being monitored.

Implementation

def roots
	@directories.keys
end

def delete(handle)

Delete a handle from the monitor.

Signature

parameter handle Handle

The handle to remove.

Implementation

def delete(handle)
	if @deletions
		@logger.debug{"Delayed delete handle: #{handle}"}
		@deletions << handle
	else
		purge(handle)
	end
end

def track_changes(files, &block)

Track changes to a set of files.

Signature

parameter files List

The list of files to monitor.

yields {|state| ...}

When changes are detected.

parameter state State

The current state with information about added, changed, and removed files.

returns Handle

A handle that can be used to stop tracking these files.

Implementation

def track_changes(files, &block)
	handle = Handle.new(self, files, &block)
	
	add(handle)
end

def add(handle)

Add a handle to the monitor.

Signature

parameter handle Handle

The handle to add.

returns Handle

The added handle.

Implementation

def add(handle)
	@logger.debug{"Adding handle: #{handle}"}
	
	handle.directories.each do |directory|
		# We want the full path as a plain string:
		directory = directory.to_s
		
		@directories[directory] << handle
		
		# We just added the first handle:
		if @directories[directory].size == 1
			# If the handle already existed, this might trigger unnecessarily.
			@updated = true
		end
	end
	
	handle
end

def run(latency: 0.1, **options, &block)

Run the monitor loop, checking for changes at regular intervals.

This method blocks until interrupted via throw :interrupt. It continuously polls the filesystem for changes and invokes registered callbacks.

Signature

parameter latency Numeric

The time in seconds to wait between checks (default: 0.1).

Implementation

def run(latency: 0.1, **options, &block)
	catch(:interrupt) do
		while true
			self.update(self.roots)
			
			yield if block_given?
			
			sleep(latency)
		end
	end
end