guard 0.8.8 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/CHANGELOG.md +16 -1
  2. data/README.md +665 -293
  3. data/bin/fsevent_watch_guard +0 -0
  4. data/lib/guard.rb +66 -31
  5. data/lib/guard/cli.rb +9 -3
  6. data/lib/guard/dsl.rb +32 -5
  7. data/lib/guard/dsl_describer.rb +3 -2
  8. data/lib/guard/guard.rb +2 -2
  9. data/lib/guard/interactor.rb +179 -48
  10. data/lib/guard/listener.rb +32 -17
  11. data/lib/guard/listeners/darwin.rb +5 -9
  12. data/lib/guard/listeners/linux.rb +6 -10
  13. data/lib/guard/listeners/windows.rb +4 -2
  14. data/lib/guard/notifier.rb +171 -258
  15. data/lib/guard/notifiers/gntp.rb +114 -0
  16. data/lib/guard/notifiers/growl.rb +98 -0
  17. data/lib/guard/notifiers/growl_notify.rb +91 -0
  18. data/lib/guard/notifiers/libnotify.rb +96 -0
  19. data/lib/guard/notifiers/rb_notifu.rb +101 -0
  20. data/lib/guard/ui.rb +2 -2
  21. data/lib/guard/version.rb +1 -1
  22. data/lib/guard/watcher.rb +1 -1
  23. data/lib/vendor/darwin/Gemfile +6 -0
  24. data/lib/vendor/darwin/Guardfile +8 -0
  25. data/lib/vendor/darwin/LICENSE +20 -0
  26. data/lib/vendor/darwin/README.rdoc +254 -0
  27. data/lib/vendor/darwin/Rakefile +21 -0
  28. data/lib/vendor/darwin/ext/extconf.rb +61 -0
  29. data/lib/vendor/darwin/ext/fsevent/fsevent_watch.c +226 -0
  30. data/lib/vendor/darwin/lib/rb-fsevent.rb +2 -0
  31. data/lib/vendor/darwin/lib/rb-fsevent/fsevent.rb +105 -0
  32. data/lib/vendor/darwin/lib/rb-fsevent/version.rb +3 -0
  33. data/lib/vendor/darwin/rb-fsevent.gemspec +24 -0
  34. data/lib/vendor/darwin/spec/fixtures/folder1/file1.txt +0 -0
  35. data/lib/vendor/darwin/spec/fixtures/folder1/folder2/file2.txt +0 -0
  36. data/lib/vendor/darwin/spec/rb-fsevent/fsevent_spec.rb +75 -0
  37. data/lib/vendor/darwin/spec/spec_helper.rb +24 -0
  38. data/lib/vendor/linux/MIT-LICENSE +20 -0
  39. data/lib/vendor/linux/README.md +66 -0
  40. data/lib/vendor/linux/Rakefile +54 -0
  41. data/lib/vendor/linux/VERSION +1 -0
  42. data/lib/vendor/linux/lib/rb-inotify.rb +17 -0
  43. data/lib/vendor/linux/lib/rb-inotify/event.rb +139 -0
  44. data/lib/vendor/linux/lib/rb-inotify/native.rb +31 -0
  45. data/lib/vendor/linux/lib/rb-inotify/native/flags.rb +89 -0
  46. data/lib/vendor/linux/lib/rb-inotify/notifier.rb +308 -0
  47. data/lib/vendor/linux/lib/rb-inotify/watcher.rb +83 -0
  48. data/lib/vendor/linux/rb-inotify.gemspec +53 -0
  49. data/lib/vendor/windows/Gemfile +4 -0
  50. data/lib/vendor/windows/README.md +34 -0
  51. data/lib/vendor/windows/Rakefile +18 -0
  52. data/lib/vendor/windows/lib/rb-fchange.rb +14 -0
  53. data/lib/vendor/windows/lib/rb-fchange/event.rb +29 -0
  54. data/lib/vendor/windows/lib/rb-fchange/native.rb +45 -0
  55. data/lib/vendor/windows/lib/rb-fchange/native/flags.rb +78 -0
  56. data/lib/vendor/windows/lib/rb-fchange/notifier.rb +149 -0
  57. data/lib/vendor/windows/lib/rb-fchange/version.rb +3 -0
  58. data/lib/vendor/windows/lib/rb-fchange/watcher.rb +99 -0
  59. data/lib/vendor/windows/rb-fchange.gemspec +34 -0
  60. data/lib/vendor/windows/spec/fixtures/folder1/file1.txt +0 -0
  61. data/lib/vendor/windows/spec/fixtures/folder1/folder2/file2.txt +0 -0
  62. data/lib/vendor/windows/spec/rb-fchange/fchange_spec.rb +119 -0
  63. data/lib/vendor/windows/spec/spec_helper.rb +21 -0
  64. metadata +87 -22
  65. data/lib/guard/version.rbc +0 -180
@@ -0,0 +1,53 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rb-inotify}
8
+ s.version = "0.8.8"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Nathan Weizenbaum"]
12
+ s.date = %q{2011-09-27}
13
+ s.description = %q{A Ruby wrapper for Linux's inotify, using FFI}
14
+ s.email = %q{nex342@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".yardopts",
20
+ "MIT-LICENSE",
21
+ "README.md",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "lib/rb-inotify.rb",
25
+ "lib/rb-inotify/event.rb",
26
+ "lib/rb-inotify/native.rb",
27
+ "lib/rb-inotify/native/flags.rb",
28
+ "lib/rb-inotify/notifier.rb",
29
+ "lib/rb-inotify/watcher.rb",
30
+ "rb-inotify.gemspec"
31
+ ]
32
+ s.homepage = %q{http://github.com/nex3/rb-inotify}
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = %q{1.3.7}
35
+ s.summary = %q{A Ruby wrapper for Linux's inotify, using FFI}
36
+
37
+ if s.respond_to? :specification_version then
38
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
39
+ s.specification_version = 3
40
+
41
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
42
+ s.add_runtime_dependency(%q<ffi>, [">= 0.5.0"])
43
+ s.add_development_dependency(%q<yard>, [">= 0.4.0"])
44
+ else
45
+ s.add_dependency(%q<ffi>, [">= 0.5.0"])
46
+ s.add_dependency(%q<yard>, [">= 0.4.0"])
47
+ end
48
+ else
49
+ s.add_dependency(%q<ffi>, [">= 0.5.0"])
50
+ s.add_dependency(%q<yard>, [">= 0.4.0"])
51
+ end
52
+ end
53
+
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rb-fchange.gemspec
4
+ gemspec
@@ -0,0 +1,34 @@
1
+ # rb-fchange
2
+
3
+ Code is working. But there is still a lot of work.
4
+ This is a simple wrapper over the Windows Kernel functions for monitoring the specified directory or subtree.
5
+ Tested on:
6
+
7
+ - jruby 1.6.1 (ruby-1.8.7-p330) (2011-04-12 85838f6)
8
+ - ruby 1.8.7 (2011-02-18 patchlevel 334) [i386-ingw32]
9
+ - ruby 1.9.2p180 (2011-02-18) [i386-mingw32]
10
+
11
+ Example
12
+
13
+ ```ruby
14
+ require 'rb-fchange'
15
+
16
+ notifier = FChange::Notifier.new
17
+ notifier.watch("test", :all_events, :recursive) do |event|
18
+ p Time.now.utc
19
+ end
20
+
21
+ Signal.trap('INT') do
22
+ p "Bye bye...",
23
+ notifier.stop
24
+ abort("\n")
25
+ end
26
+
27
+ notifier.run
28
+ ```
29
+
30
+ ## TODO
31
+
32
+ - add latency setting with 0.5 default
33
+ - rework interface (should more look like rb-fsevent)
34
+ - add none-ANSI path support
@@ -0,0 +1,18 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task :default => :spec
7
+
8
+ namespace(:spec) do
9
+ desc "Run all specs on multiple ruby versions (requires pik)"
10
+ task(:portability) do
11
+ %w[187 192 161].each do |version|
12
+ system("echo -----------#{version}------------")
13
+ system("pik use #{version}")
14
+ system("bundle install")
15
+ system("rake spec")
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ require "rb-fchange/native"
2
+ require "rb-fchange/native/flags"
3
+ require "rb-fchange/notifier"
4
+ require "rb-fchange/watcher"
5
+ require "rb-fchange/event"
6
+
7
+ # The root module of the library, which is laid out as so:
8
+ #
9
+ # * {Notifier} -- The main class, where the notifications are set up
10
+ # * {Watcher} -- A watcher for a single file or directory
11
+ # * {Event} -- An filesystem event notification
12
+ module FChange
13
+
14
+ end
@@ -0,0 +1,29 @@
1
+ module FChange
2
+ # An event caused by a change on the filesystem.
3
+ # Each {Watcher} can fire many events,
4
+ # which are passed to that watcher's callback.
5
+ class Event
6
+ # The {Watcher} that fired this event.
7
+ #
8
+ # @return [Watcher]
9
+ attr_reader :watcher
10
+
11
+ # Creates an event from a string of binary data.
12
+ # Differs from {Event.consume} in that it doesn't modify the string.
13
+ #
14
+ # @private
15
+ # @param watcher [Watcher] The {Watcher} that fired the event
16
+ def initialize(watcher)
17
+ @watcher = watcher
18
+ end
19
+
20
+ # Calls the callback of the watcher that fired this event,
21
+ # passing in the event itself.
22
+ #
23
+ # @private
24
+ def callback!
25
+ @watcher.callback!(self)
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,45 @@
1
+ require 'ffi'
2
+
3
+ module FChange
4
+ # This module contains the low-level foreign-function.
5
+ # It's an implementation detail, and not meant for users to deal with.
6
+ #
7
+ # @private
8
+ module Native
9
+ extend FFI::Library
10
+ ffi_lib 'kernel32'
11
+ ffi_convention :stdcall
12
+
13
+ # HANDLE FindFirstChangeNotification(
14
+ # LPCTSTR lpPathName, // directory name
15
+ # BOOL bWatchSubtree, // monitoring option
16
+ # DWORD dwNotifyFilter // filter conditions
17
+ #);
18
+ attach_function :FindFirstChangeNotificationW, [:pointer, :int, :long], :long
19
+
20
+ # HANDLE FindFirstChangeNotification(
21
+ # LPCTSTR lpPathName, // directory name
22
+ # BOOL bWatchSubtree, // monitoring option
23
+ # DWORD dwNotifyFilter // filter conditions
24
+ #);
25
+ attach_function :FindFirstChangeNotificationA, [:pointer, :int, :long], :long
26
+
27
+ # BOOL FindNextChangeNotification(
28
+ # HANDLE hChangeHandle // handle to change notification
29
+ # );
30
+ attach_function :FindNextChangeNotification, [:long], :int
31
+
32
+ # DAORD WaitForMultipleObjects(
33
+ # DWORD nCount, // number of handles in array
34
+ # CONST HANDLE *lpHandles, // object-handle array
35
+ # BOOL bWaitAll, // wait option
36
+ # DWORD dwMilliseconds // time-out interval
37
+ # );
38
+ attach_function :WaitForMultipleObjects, [:long, :pointer, :int, :long], :long
39
+
40
+ # BOOL FindCloseChangeNotification(
41
+ # HANDLE hChangeHandle
42
+ # );
43
+ attach_function :FindCloseChangeNotification, [:long], :int
44
+ end
45
+ end
@@ -0,0 +1,78 @@
1
+ module FChange
2
+ module Native
3
+ # A module containing all the flags to be passed to {Notifier#watch}.
4
+ # @see http://msdn.microsoft.com/en-us/library/aa364417(v=VS.85).aspx
5
+ #
6
+ # @private
7
+ module Flags
8
+
9
+ # Any file name change in the watched directory or subtree causes a change
10
+ # notification wait operation to return. Changes include renaming,
11
+ # creating, or deleting a file name.
12
+ FILE_NOTIFY_CHANGE_FILE_NAME = 0x00000001
13
+
14
+ # Any directory-name change in the watched directory or subtree causes a
15
+ # change notification wait operation to return. Changes include creating
16
+ # or deleting a directory.
17
+ FILE_NOTIFY_CHANGE_DIR_NAME = 0x00000002
18
+
19
+ # Any attribute change in the watched directory or subtree causes a change
20
+ # notification wait operation to return.
21
+ FILE_NOTIFY_CHANGE_ATTRIBUTES = 0x00000004
22
+
23
+ # Any file-size change in the watched directory or subtree causes a change
24
+ # notification wait operation to return. The operating system detects a
25
+ # change in file size only when the file is written to the disk.
26
+ # For operating systems that use extensive caching, detection occurs only
27
+ # when the cache is sufficiently flushed.
28
+ FILE_NOTIFY_CHANGE_SIZE = 0x00000008
29
+
30
+ # Any change to the last write-time of files in the watched directory or
31
+ # subtree causes a change notification wait operation to return.
32
+ # The operating system detects a change to the last write-time only when
33
+ # the file is written to the disk. For operating systems that use
34
+ # extensive caching, detection occurs only when the cache is sufficiently
35
+ # flushed
36
+ FILE_NOTIFY_CHANGE_LAST_WRITE = 0x00000010
37
+
38
+ # Any change to the last access time of files in the watched directory or
39
+ # subtree causes a change notification wait operation to return.
40
+ FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x00000020
41
+
42
+ # Any change to the creation time of files in the watched directory or
43
+ # subtree causes a change notification wait operation to return.
44
+ FILE_NOTIFY_CHANGE_CREATION = 0x00000040
45
+
46
+ # Any security-descriptor change in the watched directory or subtree
47
+ # causes a change notification wait operation to return.
48
+ FILE_NOTIFY_CHANGE_SECURITY = 0x00000100
49
+
50
+ FILE_NOTIFY_CHANGE_ALL_EVENTS = (
51
+ FILE_NOTIFY_CHANGE_DIR_NAME |
52
+ FILE_NOTIFY_CHANGE_FILE_NAME |
53
+ FILE_NOTIFY_CHANGE_LAST_WRITE
54
+ )
55
+
56
+ # Converts a list of flags to the bitmask that the C API expects.
57
+ #
58
+ # @param flags [Array<Symbol>]
59
+ # @return [Fixnum]
60
+ def self.to_mask(flags)
61
+ flags.map {|flag| const_get("FILE_NOTIFY_CHANGE_#{flag.to_s.upcase}")}.
62
+ inject(0) {|mask, flag| mask | flag}
63
+ end
64
+
65
+ # Converts a bitmask from the C API into a list of flags.
66
+ #
67
+ # @param mask [Fixnum]
68
+ # @return [Array<Symbol>]
69
+ def self.from_mask(mask)
70
+ constants.map {|c| c.to_s}.select do |c|
71
+ next false unless c =~ /^FILE_NOTIFY_CHANGE_/
72
+ const_get(c) & mask != 0
73
+ end.map {|c| c.sub("FILE_NOTIFY_CHANGE_", "").downcase.to_sym} - [:all_events]
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,149 @@
1
+ module FChange
2
+ # Notifier wraps a single instance of FChange.
3
+ # It's possible to have more than one instance,
4
+ # but usually unnecessary.
5
+ #
6
+ # @example
7
+ # # Create the notifier
8
+ # notifier = FChange::Notifier.new
9
+ #
10
+ # # Run this callback whenever the file path/to/foo.txt is read
11
+ # notifier.watch("path/to/foo/", :all_events) do
12
+ # puts "foo was accessed!"
13
+ # end
14
+ #
15
+ # # Nothing happens until you run the notifier!
16
+ # notifier.run
17
+ class Notifier
18
+
19
+ #
20
+ INFINITE = 0xFFFFFFFF
21
+
22
+ #
23
+ WAIT_OBJECT_0 = 0x00000000
24
+
25
+ # A hash from {Watcher} ids to the instances themselves.
26
+ #
27
+ # @private
28
+ # @return [{Fixnum => Watcher}]
29
+ attr_reader :watchers
30
+
31
+ attr_reader :dwChangeHandles
32
+ attr_reader :lp_dwChangeHandles
33
+
34
+ # Creates a new {Notifier}.
35
+ #
36
+ # @return [Notifier]
37
+ def initialize
38
+ @watchers = {}
39
+ @dwChangeHandles = []
40
+ @lp_dwChangeHandles = 0
41
+ end
42
+
43
+ # Adds a new {Watcher} to the queue.
44
+ def add_watcher(watcher)
45
+
46
+ @watchers[watcher.id] = watcher
47
+
48
+ @dwChangeHandles.push watcher.id
49
+
50
+ # Pack event handles into newly created storage area
51
+ # to be used for Win32 call
52
+ @lp_dwChangeHandles = dwChangeHandles.pack("L" * dwChangeHandles.count)
53
+
54
+ end
55
+
56
+ # Watches a file or directory for changes,
57
+ # calling the callback when there are.
58
+ # This is only activated once \{#process} or \{#run} is called.
59
+ #
60
+ # **Note that by default, this does not recursively watch subdirectories
61
+ # of the watched directory**.
62
+ # To do so, use the `:recursive` flag.
63
+ #
64
+ # `:recursive`
65
+ # : Recursively watch any subdirectories that are created.
66
+ #
67
+ # @param path [String] The path to the file or directory
68
+ # @param flags [Array<Symbol>] Which events to watch for
69
+ # @yield [event] A block that will be called
70
+ # whenever one of the specified events occur
71
+ # @yieldparam event [Event] The Event object containing information
72
+ # about the event that occured
73
+ # @return [Watcher] A Watcher set up to watch this path for these events
74
+ # @raise [SystemCallError] if the file or directory can't be watched,
75
+ # e.g. if the file isn't found, read access is denied,
76
+ # or the flags don't contain any events
77
+ def watch(path, *flags, &callback)
78
+ recursive = flags.include?(:recursive)
79
+ #:latency = 0.5
80
+ flags = flags - [:recursive]
81
+ if flags.empty?
82
+ @flags = [:all_events]
83
+ else
84
+ @flags = flags.freeze
85
+ end
86
+ Watcher.new(self, path, recursive, *@flags, &callback)
87
+ end
88
+
89
+ # Starts the notifier watching for filesystem events.
90
+ # Blocks until \{#stop} is called.
91
+ #
92
+ # @see #process
93
+ def run
94
+ @stop = false
95
+ process until @stop
96
+ end
97
+
98
+ # Stop watching for filesystem events.
99
+ # That is, if we're in a \{#run} loop,
100
+ # exit out as soon as we finish handling the events.
101
+ def stop
102
+ @stop = true
103
+ end
104
+
105
+ # Blocks until there are one or more filesystem events
106
+ # that this notifier has watchers registered for.
107
+ # Once there are events, the appropriate callbacks are called
108
+ # and this function returns.
109
+ #
110
+ # @see #run
111
+ def process
112
+ read_events.each {|event| event.callback!}
113
+ end
114
+
115
+ # Blocks until there are one or more filesystem events
116
+ # that this notifier has watchers registered for.
117
+ # Once there are events, returns their {Event} objects.
118
+ #
119
+ # @private
120
+ def read_events
121
+
122
+ # can return WAIT_TIMEOUT = 0x00000102
123
+ dwWaitStatus = Native.WaitForMultipleObjects(@dwChangeHandles.count,
124
+ @lp_dwChangeHandles, 0, 500)
125
+
126
+ events = []
127
+
128
+ # this call blocks all threads completely.
129
+ @dwChangeHandles.each_index do |index|
130
+ if dwWaitStatus == WAIT_OBJECT_0 + index
131
+
132
+ ev = Event.new(@watchers[@dwChangeHandles[index]])
133
+ events << ev
134
+
135
+ r = Native.FindNextChangeNotification(@dwChangeHandles[index])
136
+ if r == 0
137
+ raise SystemCallError.new("Failed to watch", r)
138
+ end
139
+ end
140
+ end
141
+ events
142
+ end
143
+
144
+ def close
145
+
146
+ end
147
+
148
+ end
149
+ end
@@ -0,0 +1,3 @@
1
+ module FChange
2
+ VERSION = "0.0.5"
3
+ end
@@ -0,0 +1,99 @@
1
+ require 'pathname'
2
+
3
+ module FChange
4
+ # Watchers monitor a single path for changes,
5
+ # specified by {FChange::Notifier#watch event flags}.
6
+ # A watcher is usually created via \{Notifier#watch}.
7
+ #
8
+ # One {Notifier} may have many {Watcher}s.
9
+ # The Notifier actually takes care of the checking for events,
10
+ # via \{Notifier#run #run} or \{Notifier#process #process}.
11
+ # The main purpose of having Watcher objects
12
+ # is to be able to disable them using \{#close}.
13
+ class Watcher
14
+ # The {Notifier} that this Watcher belongs to.
15
+ #
16
+ # @return [Notifier]
17
+ attr_reader :notifier
18
+
19
+ # The path that this Watcher is watching.
20
+ #
21
+ # @return [String]
22
+ attr_reader :path
23
+
24
+ # The {FChange::Notifier#watch flags}
25
+ # specifying the events that this Watcher is watching for,
26
+ # and potentially some options as well.
27
+ #
28
+ # @return [Array<Symbol>]
29
+ attr_reader :flags
30
+
31
+ # The id for this Watcher.
32
+ # Used to retrieve this Watcher from {Notifier#watchers}.
33
+ #
34
+ # @private
35
+ # @return [Fixnum]
36
+ attr_reader :id
37
+
38
+ #
39
+ # @private
40
+ # @return [Boolean]
41
+ attr_reader :recursive
42
+
43
+ # Calls this Watcher's callback with the given {Event}.
44
+ #
45
+ # @private
46
+ # @param event [Event]
47
+ def callback!(event)
48
+ @callback[event]
49
+ end
50
+
51
+ # Disables this Watcher, so that it doesn't fire any more events.
52
+ #
53
+ # @raise [SystemCallError] if the watch fails to be disabled for some reason
54
+ def close
55
+ r = Native.FindCloseChangeNotification(@id)
56
+ #@notifier.remove_watcher(self)
57
+ return if r == 0
58
+ raise SystemCallError.new("Failed to stop watching #{@path.inspect}", r)
59
+ end
60
+
61
+ # see http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85).aspx
62
+ def normalize_path(path)
63
+ if(path.size > 256)
64
+ path = "\\\\?\\" + Pathname.new(path).realpath.to_s
65
+ end
66
+ # require 'rchardet'
67
+ # require 'iconv'
68
+ # cd = CharDet.detect(path)
69
+ # encoding = cd['encoding']
70
+ # converter = Iconv.new("UTF-16LE", encoding)
71
+ # converter.iconv(path)
72
+ # path.encode!("UTF-16LE")
73
+ end
74
+
75
+ # Creates a new {Watcher}.
76
+ #
77
+ # @private
78
+ # @see Notifier#watch
79
+ def initialize(notifier, path, recursive, *flags, &callback)
80
+ @notifier = notifier
81
+ @callback = callback || proc {}
82
+ @path = path
83
+ @flags = flags
84
+ @recursive = recursive ? 1 : 0
85
+
86
+ @id = Native.FindFirstChangeNotificationA(path, @recursive,
87
+ Native::Flags.to_mask(flags));
88
+ # @id = Native.FindFirstChangeNotificationW(normalize_path(path), @recursive,
89
+ # Native::Flags.to_mask(flags));
90
+
91
+ unless @id < 0
92
+ @notifier.add_watcher(self)
93
+ return
94
+ end
95
+
96
+ raise SystemCallError.new("Failed to watch #{path.inspect}", @id)
97
+ end
98
+ end
99
+ end