module INotify # Watchers monitor a single path for changes, # specified by {INotify::Notifier#watch event flags}. # A watcher is usually created via \{Notifier#watch}. # # One {Notifier} may have many {Watcher}s. # The Notifier actually takes care of the checking for events, # via \{Notifier#run #run} or \{Notifier#process #process}. # The main purpose of having Watcher objects # is to be able to disable them using \{#close}. class Watcher # The {Notifier} that this Watcher belongs to. # # @return [Notifier] attr_reader :notifier # The path that this Watcher is watching. # # @return [String] attr_reader :path # The {INotify::Notifier#watch flags} # specifying the events that this Watcher is watching for, # and potentially some options as well. # # @return [Array] attr_reader :flags # The id for this Watcher. # Used to retrieve this Watcher from {Notifier#watchers}. # # @private # @return [Fixnum] attr_reader :id # Calls this Watcher's callback with the given {Event}. # # @private # @param event [Event] def callback!(event) @callback[event] end # Disables this Watcher, so that it doesn't fire any more events. # # @raise [SystemCallError] if the watch fails to be disabled for some reason def close if Native.inotify_rm_watch(@notifier.fd, @id) == 0 @notifier.watchers.delete(@id) return end raise SystemCallError.new("Failed to stop watching #{path.inspect}", FFI.errno) end # Creates a new {Watcher}. # # @private # @see Notifier#watch def initialize(notifier, path, *flags, &callback) @notifier = notifier @callback = callback || proc {} @path = path @flags = flags.freeze @id = Native.inotify_add_watch(@notifier.fd, path.dup, Native::Flags.to_mask(flags)) unless @id < 0 @notifier.watchers[@id] = self return end raise SystemCallError.new( "Failed to watch #{path.inspect}" + case FFI.errno when Errno::EACCES::Errno; ": read access to the given file is not permitted." when Errno::EBADF::Errno; ": the given file descriptor is not valid." when Errno::EFAULT::Errno; ": path points outside of the process's accessible address space." when Errno::EINVAL::Errno; ": the given event mask contains no legal events; or fd is not an inotify file descriptor." when Errno::ENOMEM::Errno; ": insufficient kernel memory was available." when Errno::ENOSPC::Errno; ": The user limit on the total number of inotify watches was reached or the kernel failed to allocate a needed resource." else; "" end, FFI.errno) end end end