| module INotify |
| # An event caused by a change on the filesystem. |
| # Each {Watcher} can fire many events, |
| # which are passed to that watcher's callback. |
| class Event |
| # A list of other events that are related to this one. |
| # Currently, this is only used for files that are moved within the same directory: |
| # the `:moved_from` and the `:moved_to` events will be related. |
| # |
| # @return [Array<Event>] |
| attr_reader :related |
| |
| # The name of the file that the event occurred on. |
| # This is only set for events that occur on files in directories; |
| # otherwise, it's `""`. |
| # Similarly, if the event is being fired for the directory itself |
| # the name will be `""` |
| # |
| # This pathname is relative to the enclosing directory. |
| # For the absolute pathname, use \{#absolute\_name}. |
| # Note that when the `:recursive` flag is passed to {Notifier#watch}, |
| # events in nested subdirectories will still have a `#name` field |
| # relative to their immediately enclosing directory. |
| # For example, an event on the file `"foo/bar/baz"` |
| # will have name `"baz"`. |
| # |
| # @return [String] |
| attr_reader :name |
| |
| # The {Notifier} that fired this event. |
| # |
| # @return [Notifier] |
| attr_reader :notifier |
| |
| # An integer specifying that this event is related to some other event, |
| # which will have the same cookie. |
| # |
| # Currently, this is only used for files that are moved within the same directory. |
| # Both the `:moved_from` and the `:moved_to` events will have the same cookie. |
| # |
| # @private |
| # @return [Fixnum] |
| attr_reader :cookie |
| |
| # The {Watcher#id id} of the {Watcher} that fired this event. |
| # |
| # @private |
| # @return [Fixnum] |
| attr_reader :watcher_id |
| |
| # Returns the {Watcher} that fired this event. |
| # |
| # @return [Watcher] |
| def watcher |
| @watcher ||= @notifier.watchers[@watcher_id] |
| end |
| |
| # The absolute path of the file that the event occurred on. |
| # |
| # This is actually only as absolute as the path passed to the {Watcher} |
| # that created this event. |
| # However, it is relative to the working directory, |
| # assuming that hasn't changed since the watcher started. |
| # |
| # @return [String] |
| def absolute_name |
| return watcher.path if name.empty? |
| return File.join(watcher.path, name) |
| end |
| |
| # Returns the flags that describe this event. |
| # This is generally similar to the input to {Notifier#watch}, |
| # except that it won't contain options flags nor `:all_events`, |
| # and it may contain one or more of the following flags: |
| # |
| # `:unmount` |
| # : The filesystem containing the watched file or directory was unmounted. |
| # |
| # `:ignored` |
| # : The \{#watcher watcher} was closed, or the watched file or directory was deleted. |
| # |
| # `:isdir` |
| # : The subject of this event is a directory. |
| # |
| # @return [Array<Symbol>] |
| def flags |
| @flags ||= Native::Flags.from_mask(@native[:mask]) |
| end |
| |
| # Constructs an {Event} object from a string of binary data, |
| # and destructively modifies the string to get rid of the initial segment |
| # used to construct the Event. |
| # |
| # @private |
| # @param data [String] The string to be modified |
| # @param notifier [Notifier] The {Notifier} that fired the event |
| # @return [Event, nil] The event, or `nil` if the string is empty |
| def self.consume(data, notifier) |
| return nil if data.empty? |
| ev = new(data, notifier) |
| data.replace data[ev.size..-1] |
| ev |
| end |
| |
| # Creates an event from a string of binary data. |
| # Differs from {Event.consume} in that it doesn't modify the string. |
| # |
| # @private |
| # @param data [String] The data string |
| # @param notifier [Notifier] The {Notifier} that fired the event |
| def initialize(data, notifier) |
| ptr = FFI::MemoryPointer.from_string(data) |
| @native = Native::Event.new(ptr) |
| @related = [] |
| @cookie = @native[:cookie] |
| @name = fix_encoding(data[@native.size, @native[:len]].gsub(/\0+$/, '')) |
| @notifier = notifier |
| @watcher_id = @native[:wd] |
| |
| raise QueueOverflowError.new("inotify event queue has overflowed.") if @native[:mask] & Native::Flags::IN_Q_OVERFLOW != 0 |
| end |
| |
| # Calls the callback of the watcher that fired this event, |
| # passing in the event itself. |
| # |
| # @private |
| def callback! |
| watcher && watcher.callback!(self) |
| end |
| |
| # Returns the size of this event object in bytes, |
| # including the \{#name} string. |
| # |
| # @return [Fixnum] |
| def size |
| @native.size + @native[:len] |
| end |
| |
| private |
| |
| def fix_encoding(name) |
| name.force_encoding('filesystem') if name.respond_to?(:force_encoding) |
| name |
| end |
| end |
| end |