listen 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +22 -0
- data/README.md +146 -29
- data/lib/listen.rb +22 -10
- data/lib/listen/adapter.rb +89 -50
- data/lib/listen/adapters/darwin.rb +43 -18
- data/lib/listen/adapters/linux.rb +48 -33
- data/lib/listen/adapters/polling.rb +20 -7
- data/lib/listen/adapters/windows.rb +38 -31
- data/lib/listen/directory_record.rb +254 -0
- data/lib/listen/listener.rb +59 -228
- data/lib/listen/multi_listener.rb +121 -0
- data/lib/listen/turnstile.rb +28 -0
- data/lib/listen/version.rb +1 -1
- metadata +16 -11
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
## 0.4.0 - April 9, 2012
|
2
|
+
|
3
|
+
### New features
|
4
|
+
|
5
|
+
- Add `wait_for_callback` method to all adapters. ([@Maher4Ever][])
|
6
|
+
- Add `Listen::MultiListener` class to listen to multiple directories at once. ([@Maher4Ever][])
|
7
|
+
- Allow passing multiple directories to the `Listen.to` method. ([@Maher4Ever][])
|
8
|
+
- Add `blocking` option to `Listen#start` which can be used to disable blocking the current thread upon starting. ([@Maher4Ever][])
|
9
|
+
- Use absolute-paths in callbacks by default instead of relative-paths. ([@Maher4Ever][])
|
10
|
+
- Add `relative_paths` option to `Listen::Listener` to retain the old functionality. ([@Maher4Ever][])
|
11
|
+
|
12
|
+
### Improvements
|
13
|
+
|
14
|
+
- Encapsulate thread spawning in the linux-adapter. ([@Maher4Ever][])
|
15
|
+
- Encapsulate thread spawning in the darwin-adapter. ([@Maher4Ever][] with [@scottdavis][] help)
|
16
|
+
- Encapsulate thread spawning in the windows-adapter. ([@Maher4Ever][])
|
17
|
+
- Fix linux-adapter bug where Listen would report file-modification events on the parent-directory. ([@Maher4Ever][])
|
18
|
+
|
19
|
+
### Removals
|
20
|
+
|
21
|
+
- Remove `wait_until_listening` as adapters doesn't need to run inside threads anymore ([@Maher4Ever][])
|
22
|
+
|
1
23
|
## 0.3.3 - March 6, 2012
|
2
24
|
|
3
25
|
### Improvements
|
data/README.md
CHANGED
@@ -5,12 +5,13 @@ The Listen gem listens to file modifications and notifies you about the changes.
|
|
5
5
|
## Features
|
6
6
|
|
7
7
|
* Works everywhere!
|
8
|
+
* Supports watching multiple directories from a single listener.
|
8
9
|
* OS-specific adapters for Mac OS X 10.6+, Linux and Windows.
|
9
10
|
* Automatic fallback to polling if OS-specific adapter doesn't work.
|
10
11
|
* Detects files modification, addidation and removal.
|
11
12
|
* Checksum comparaison for modifications made under the same second.
|
13
|
+
* Allows ignoring paths and supplying filters for better results.
|
12
14
|
* Tested on all Ruby environments via [travis-ci](http://travis-ci.org/guard/listen).
|
13
|
-
* Threadable.
|
14
15
|
|
15
16
|
## Install
|
16
17
|
|
@@ -20,19 +21,25 @@ gem install listen
|
|
20
21
|
|
21
22
|
## Usage
|
22
23
|
|
23
|
-
There are two ways
|
24
|
+
There are **two ways** to use Listen:
|
24
25
|
|
25
|
-
1.
|
26
|
-
2.
|
26
|
+
1. Call `Listen.to` with either a single directory or multiple directories, then define the `change` callback in a block.
|
27
|
+
2. Create a `listener` object and use it in an (ARel style) chainable way.
|
27
28
|
|
28
29
|
Feel free to give your feeback via [Listen issues](https://github.com/guard/listener/issues)
|
29
30
|
|
30
31
|
### Block API
|
31
32
|
|
32
33
|
``` ruby
|
34
|
+
# Listen to a single directory.
|
33
35
|
Listen.to('dir/path/to/listen', filter: /.*\.rb/, ignore: '/ignored/path') do |modified, added, removed|
|
34
36
|
# ...
|
35
37
|
end
|
38
|
+
|
39
|
+
# Listen to multiple directories.
|
40
|
+
Listen.to('dir/to/awesome_app', 'dir/to/other_app', filter: /.*\.rb/, latency: 0.1) do |modified, added, removed|
|
41
|
+
# ...
|
42
|
+
end
|
36
43
|
```
|
37
44
|
|
38
45
|
### "Object" API
|
@@ -45,11 +52,10 @@ listener = listener.latency(0.5)
|
|
45
52
|
listener = listener.force_polling(true)
|
46
53
|
listener = listener.polling_fallback_message(false)
|
47
54
|
listener = listener.change(&callback)
|
48
|
-
listener.start #
|
49
|
-
listener.stop
|
55
|
+
listener.start # blocks execution!
|
50
56
|
```
|
51
57
|
|
52
|
-
|
58
|
+
### Chainable
|
53
59
|
|
54
60
|
``` ruby
|
55
61
|
Listen.to('dir/path/to/listen')
|
@@ -59,21 +65,121 @@ Listen.to('dir/path/to/listen')
|
|
59
65
|
.force_polling(true)
|
60
66
|
.polling_fallback_message('custom message')
|
61
67
|
.change(&callback)
|
62
|
-
.start #
|
68
|
+
.start # blocks execution!
|
63
69
|
```
|
64
70
|
|
65
|
-
|
71
|
+
### Pause/Unpause
|
72
|
+
|
73
|
+
Listener can also easily be paused/unpaused:
|
66
74
|
|
67
75
|
``` ruby
|
68
|
-
listener = Listen.to(
|
69
|
-
|
70
|
-
|
76
|
+
listener = Listen.to('dir/path/to/listen')
|
77
|
+
listener.start(false) # non-blocking mode
|
78
|
+
listener.pause # stop listening to changes
|
79
|
+
listener.paused? # => true
|
80
|
+
listener.unpause
|
81
|
+
listener.stop
|
82
|
+
```
|
83
|
+
|
84
|
+
## Listening to changes on multiple directories
|
85
|
+
|
86
|
+
The Listen gem provides the `MultiListener` class to watch multiple directories and
|
87
|
+
handle their changes from a single listener:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
listener = Listen::MultiListener.new('app/css', 'app/js')
|
91
|
+
listener.latency(0.5)
|
92
|
+
|
93
|
+
# Configure the listener to your needs...
|
94
|
+
|
95
|
+
listener.start # blocks execution!
|
96
|
+
````
|
97
|
+
|
98
|
+
For an easier access, the `Listen.to` method can also be used to create a multi-listener:
|
99
|
+
|
100
|
+
``` ruby
|
101
|
+
listener = Listen.to('app/css', 'app/js')
|
102
|
+
.ignore('vendor') # both js/vendor and css/vendor will be ignored
|
103
|
+
.change(&assets_callback)
|
104
|
+
|
105
|
+
listener.start # blocks execution!
|
106
|
+
```
|
107
|
+
|
108
|
+
## Changes callback
|
109
|
+
|
110
|
+
Changes to the listened-to directories gets reported back to the user in a callback.
|
111
|
+
The registered callback gets invoked, when there are changes, with **three** parameters:
|
112
|
+
`modified_paths`, `added_paths` and `removed_paths` in that particular order.
|
113
|
+
|
114
|
+
You can register a callback in two ways. The first way is by passing a block when calling
|
115
|
+
the `Listen.to` method or when initializing a listener object:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
Listen.to('path/to/app') do |modified, added, removed|
|
119
|
+
# This block will be called when there are changes.
|
120
|
+
end
|
121
|
+
|
122
|
+
# or ...
|
123
|
+
|
124
|
+
listener = Listen::Listener.new('path/to/app') do |modified, added, removed|
|
125
|
+
# This block will be called when there are changes.
|
126
|
+
end
|
127
|
+
|
128
|
+
```
|
71
129
|
|
72
|
-
|
73
|
-
|
130
|
+
The second way to register a callback is be calling the `change` method on any
|
131
|
+
listener passing it a block:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
# Create a callback
|
135
|
+
callback = Proc.new do |modified, added, removed|
|
136
|
+
# This proc will be called when there are changes.
|
137
|
+
end
|
138
|
+
|
139
|
+
listener = Listen.to('dir')
|
140
|
+
listener.change(&callback) # convert the callback to a block and register it
|
141
|
+
|
142
|
+
listener.start # blocks execution
|
143
|
+
```
|
144
|
+
|
145
|
+
### Paths in callbacks
|
146
|
+
|
147
|
+
Listeners invoke callbacks passing them absolute paths by default:
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
# Assume someone changes the 'style.css' file in '/home/user/app/css' after creating
|
151
|
+
# the listener.
|
152
|
+
Listen.to('/home/user/app/css') do |modified, added, removed|
|
153
|
+
modified.inspect # => ['/home/user/app/css/style.css']
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
#### Relative paths in callbacks
|
158
|
+
|
159
|
+
When creating a listener for a **single** path (more specifically a `Listen::Listener` instance),
|
160
|
+
you can pass `:relative_paths => true` as an option to get relative paths in
|
161
|
+
your callback:
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
# Assume someone changes the 'style.css' file in '/home/user/app/css' after creating
|
165
|
+
# the listener.
|
166
|
+
Listen.to('/home/user/app/css', :relative_paths => true) do |modified, added, removed|
|
167
|
+
modified.inspect # => ['style.css']
|
168
|
+
end
|
74
169
|
```
|
75
170
|
|
76
|
-
|
171
|
+
Passing the `:relative_paths => true` option won't work when listeneing to multiple
|
172
|
+
directories:
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
# Assume someone changes the 'style.css' file in '/home/user/app/css' after creating
|
176
|
+
# the listener.
|
177
|
+
Listen.to('/home/user/app/css', '/home/user/app/js', :relative_paths => true) do |modified, added, removed|
|
178
|
+
modified.inspect # => ['/home/user/app/css/style.css']
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
182
|
+
## Options
|
77
183
|
|
78
184
|
These options can be set through `Listen.to` params or via methods (see the "Object" API)
|
79
185
|
|
@@ -94,19 +200,28 @@ These options can be set through `Listen.to` params or via methods (see the "Obj
|
|
94
200
|
# default: "WARNING: Listen fallen back to polling, learn more at https://github.com/guard/listen#fallback."
|
95
201
|
```
|
96
202
|
|
97
|
-
###
|
203
|
+
### Non-blocking listening to changes
|
98
204
|
|
99
|
-
|
205
|
+
Starting a listener blocks the current thread by default. That means any code after the
|
206
|
+
`start` call won't be run until the listener is stopped (which needs to be done from another thread).
|
100
207
|
|
101
|
-
|
208
|
+
For advanced usage there is an option to disable this behavior and have the listener start working
|
209
|
+
in the background without blocking. To enable non-blocking listening the `start` method of
|
210
|
+
the listener (be it `Listener` or `MultiListener`) needs to be called with `false` as a parameter.
|
211
|
+
|
212
|
+
Here is an example of using a listener in the non-blocking mode:
|
213
|
+
|
214
|
+
```ruby
|
102
215
|
listener = Listen.to('dir/path/to/listen')
|
103
|
-
listener.start
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
listener.stop
|
216
|
+
listener.start(false) # doesn't block execution
|
217
|
+
|
218
|
+
# Code here will run immediately after starting the listener
|
219
|
+
|
108
220
|
```
|
109
221
|
|
222
|
+
**note**: Using the `Listen.to` helper-method with a callback-block will always
|
223
|
+
block execution. See the "Block API" section for an example.
|
224
|
+
|
110
225
|
## Listen adapters
|
111
226
|
|
112
227
|
The Listen gem has a set of adapters to notify it when there are changes.
|
@@ -122,17 +237,17 @@ while initializing the listener or call the `force_polling` method on your liste
|
|
122
237
|
before starting it.
|
123
238
|
|
124
239
|
<a name="fallback"/>
|
125
|
-
|
240
|
+
## Polling fallback
|
126
241
|
|
127
|
-
When
|
128
|
-
Here some things
|
242
|
+
When a OS-specific adapter doesn't work the Listen gem automatically falls back to the polling adapter.
|
243
|
+
Here are some things you could try to avoid the polling fallback:
|
129
244
|
|
130
245
|
* [Update your Dropbox client](http://www.dropbox.com/downloading) (if used).
|
131
246
|
* Increase latency. (Please [open an issue](https://github.com/guard/listen/issues/new) if you think that default is too low.)
|
132
247
|
* Move or rename the listened folder.
|
133
248
|
* Update/reboot your OS.
|
134
249
|
|
135
|
-
If
|
250
|
+
If your application keeps using the polling-adapter and you can't figure out why, feel free to [open an issue](https://github.com/guard/listen/issues/new) (and be sure to give all the details).
|
136
251
|
|
137
252
|
## Development [![Dependency Status](https://gemnasium.com/guard/listen.png?branch=master)](https://gemnasium.com/guard/listen)
|
138
253
|
|
@@ -159,15 +274,17 @@ For questions please join us in our [Google group](http://groups.google.com/grou
|
|
159
274
|
* [stereobooster][] for [rb-fchange][], windows support wouldn't exist without him.
|
160
275
|
* [Yehuda Katz (wycats)][] for [vigilo][], that has been a great source of inspiration.
|
161
276
|
|
162
|
-
##
|
277
|
+
## Authors
|
163
278
|
|
164
|
-
[Thibaud Guillaume-Gentil][] ([@thibaudgg](http://twitter.com/thibaudgg))
|
279
|
+
* [Thibaud Guillaume-Gentil][] ([@thibaudgg](http://twitter.com/thibaudgg))
|
280
|
+
* [Maher Sallam][] ([@mahersalam](http://twitter.com/mahersalam))
|
165
281
|
|
166
282
|
## Contributors
|
167
283
|
|
168
284
|
[https://github.com/guard/listen/contributors](https://github.com/guard/listen/contributors)
|
169
285
|
|
170
286
|
[Thibaud Guillaume-Gentil]: https://github.com/thibaudgg
|
287
|
+
[Maher Sallam]: https://github.com/Maher4Ever
|
171
288
|
[Michael Kessler (netzpirat)]: https://github.com/netzpirat
|
172
289
|
[Travis Tilley (ttilley)]: https://github.com/ttilley
|
173
290
|
[fssm]: https://github.com/ttilley/fssm
|
data/lib/listen.rb
CHANGED
@@ -1,15 +1,22 @@
|
|
1
|
-
require 'listen/listener'
|
2
|
-
|
3
1
|
module Listen
|
4
2
|
|
5
|
-
|
3
|
+
autoload :Turnstile, 'listen/turnstile'
|
4
|
+
autoload :Listener, 'listen/listener'
|
5
|
+
autoload :MultiListener, 'listen/multi_listener'
|
6
|
+
autoload :DirectoryRecord, 'listen/directory_record'
|
7
|
+
autoload :Adapter, 'listen/adapter'
|
8
|
+
|
9
|
+
module Adapters
|
10
|
+
autoload :Darwin, 'listen/adapters/darwin'
|
11
|
+
autoload :Linux, 'listen/adapters/linux'
|
12
|
+
autoload :Windows, 'listen/adapters/windows'
|
13
|
+
autoload :Polling, 'listen/adapters/polling'
|
14
|
+
end
|
15
|
+
|
16
|
+
# Listens to filesystem modifications on a either single directory or multiple directories.
|
6
17
|
#
|
7
|
-
# @param
|
8
|
-
# @param
|
9
|
-
# @option options [String] ignore a list of paths to ignore
|
10
|
-
# @option options [Regexp] filter a list of regexps file filters
|
11
|
-
# @option options [Float] latency the delay between checking for changes in seconds
|
12
|
-
# @option options [Boolean] polling whether to force or disable the polling adapter
|
18
|
+
# @param (see Listen::Listener#new)
|
19
|
+
# @param (see Listen::MultiListener#new)
|
13
20
|
#
|
14
21
|
# @yield [modified, added, removed] the changed files
|
15
22
|
# @yieldparam [Array<String>] modified the list of modified files
|
@@ -19,7 +26,12 @@ module Listen
|
|
19
26
|
# @return [Listen::Listener] the file listener if no block given
|
20
27
|
#
|
21
28
|
def self.to(*args, &block)
|
22
|
-
listener =
|
29
|
+
listener = if args.length == 1 || ! args[1].is_a?(String)
|
30
|
+
Listener.new(*args, &block)
|
31
|
+
else
|
32
|
+
MultiListener.new(*args, &block)
|
33
|
+
end
|
34
|
+
|
23
35
|
block ? listener.start : listener
|
24
36
|
end
|
25
37
|
|
data/lib/listen/adapter.rb
CHANGED
@@ -1,18 +1,22 @@
|
|
1
1
|
require 'rbconfig'
|
2
|
+
require 'thread'
|
3
|
+
require 'set'
|
4
|
+
require 'fileutils'
|
2
5
|
|
3
6
|
module Listen
|
4
7
|
class Adapter
|
5
|
-
attr_accessor :latency, :paused
|
8
|
+
attr_accessor :directories, :latency, :paused
|
6
9
|
|
7
10
|
# The default delay between checking for changes.
|
8
11
|
DEFAULT_LATENCY = 0.1
|
12
|
+
|
9
13
|
# The default warning message when falling back to polling adapter.
|
10
|
-
POLLING_FALLBACK_MESSAGE = "WARNING: Listen fallen back to polling, learn more at https://github.com/guard/listen#fallback."
|
14
|
+
POLLING_FALLBACK_MESSAGE = "WARNING: Listen has fallen back to polling, learn more at https://github.com/guard/listen#fallback."
|
11
15
|
|
12
|
-
#
|
16
|
+
# Selects the appropriate adapter implementation for the
|
13
17
|
# current OS and initializes it.
|
14
18
|
#
|
15
|
-
# @param [String,
|
19
|
+
# @param [String, Array<String>] directories the directories to watch
|
16
20
|
# @param [Hash] options the adapter options
|
17
21
|
# @option options [Boolean] force_polling to force polling or not
|
18
22
|
# @option options [String, Boolean] polling_fallback_message to change polling fallback message or remove it
|
@@ -24,26 +28,26 @@ module Listen
|
|
24
28
|
#
|
25
29
|
# @return [Listen::Adapter] the chosen adapter
|
26
30
|
#
|
27
|
-
def self.select_and_initialize(
|
28
|
-
return Adapters::Polling.new(
|
31
|
+
def self.select_and_initialize(directories, options = {}, &callback)
|
32
|
+
return Adapters::Polling.new(directories, options, &callback) if options.delete(:force_polling)
|
29
33
|
|
30
|
-
if Adapters::Darwin.
|
31
|
-
Adapters::Darwin.new(
|
32
|
-
elsif Adapters::Linux.
|
33
|
-
Adapters::Linux.new(
|
34
|
-
elsif Adapters::Windows.
|
35
|
-
Adapters::Windows.new(
|
34
|
+
if Adapters::Darwin.usable_and_works?(directories, options)
|
35
|
+
Adapters::Darwin.new(directories, options, &callback)
|
36
|
+
elsif Adapters::Linux.usable_and_works?(directories, options)
|
37
|
+
Adapters::Linux.new(directories, options, &callback)
|
38
|
+
elsif Adapters::Windows.usable_and_works?(directories, options)
|
39
|
+
Adapters::Windows.new(directories, options, &callback)
|
36
40
|
else
|
37
41
|
unless options[:polling_fallback_message] == false
|
38
42
|
Kernel.warn(options[:polling_fallback_message] || POLLING_FALLBACK_MESSAGE)
|
39
43
|
end
|
40
|
-
Adapters::Polling.new(
|
44
|
+
Adapters::Polling.new(directories, options, &callback)
|
41
45
|
end
|
42
46
|
end
|
43
47
|
|
44
|
-
#
|
48
|
+
# Initializes the adapter.
|
45
49
|
#
|
46
|
-
# @param [String,
|
50
|
+
# @param [String, Array<String>] directories the directories to watch
|
47
51
|
# @param [Hash] options the adapter options
|
48
52
|
# @option options [Float] latency the delay between checking for changes in seconds
|
49
53
|
#
|
@@ -53,68 +57,103 @@ module Listen
|
|
53
57
|
#
|
54
58
|
# @return [Listen::Adapter] the adapter
|
55
59
|
#
|
56
|
-
def initialize(
|
57
|
-
@
|
58
|
-
@callback
|
59
|
-
@latency
|
60
|
-
@latency
|
61
|
-
@paused
|
60
|
+
def initialize(directories, options = {}, &callback)
|
61
|
+
@directories = Array(directories)
|
62
|
+
@callback = callback
|
63
|
+
@latency ||= DEFAULT_LATENCY
|
64
|
+
@latency = options[:latency] if options[:latency]
|
65
|
+
@paused = false
|
66
|
+
@mutex = Mutex.new
|
67
|
+
@changed_dirs = Set.new
|
68
|
+
@turnstile = Turnstile.new
|
62
69
|
end
|
63
70
|
|
64
|
-
#
|
71
|
+
# Starts the adapter.
|
65
72
|
#
|
66
|
-
|
73
|
+
# @param [Boolean] blocking whether or not to block the current thread after starting
|
74
|
+
#
|
75
|
+
def start(blocking = true)
|
67
76
|
@stop = false
|
68
77
|
end
|
69
78
|
|
70
|
-
#
|
79
|
+
# Stops the adapter.
|
71
80
|
#
|
72
81
|
def stop
|
73
82
|
@stop = true
|
83
|
+
@turnstile.signal # ensure no thread is blocked
|
74
84
|
end
|
75
85
|
|
76
|
-
|
86
|
+
# Blocks the main thread until the poll thread
|
87
|
+
# calls the callback.
|
88
|
+
#
|
89
|
+
def wait_for_callback
|
90
|
+
@turnstile.wait unless @paused
|
91
|
+
end
|
77
92
|
|
78
|
-
#
|
93
|
+
# Checks if the adapter is usable and works on the current OS.
|
79
94
|
#
|
80
|
-
# @param [String,
|
95
|
+
# @param [String, Array<String>] directories the directories to watch
|
81
96
|
# @param [Hash] options the adapter options
|
82
97
|
# @option options [Float] latency the delay between checking for changes in seconds
|
83
98
|
#
|
84
99
|
# @return [Boolean] whether usable and work or not
|
85
100
|
#
|
86
|
-
def self.
|
87
|
-
usable? &&
|
101
|
+
def self.usable_and_works?(directories, options = {})
|
102
|
+
usable? && Array(directories).all? { |d| works?(d, options) }
|
88
103
|
end
|
89
104
|
|
90
|
-
#
|
91
|
-
#
|
105
|
+
# Runs a tests to determine if the adapter can actually pick up
|
106
|
+
# changes in a given directory and returns the result.
|
107
|
+
#
|
108
|
+
# @note This test takes some time depending the adapter latency.
|
92
109
|
#
|
93
110
|
# @param [String, Pathname] directory the directory to watch
|
94
111
|
# @param [Hash] options the adapter options
|
95
112
|
# @option options [Float] latency the delay between checking for changes in seconds
|
96
113
|
#
|
97
|
-
# @return [Boolean] whether
|
98
|
-
#
|
99
|
-
def self.
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
114
|
+
# @return [Boolean] whether the adapter works or not
|
115
|
+
#
|
116
|
+
def self.works?(directory, options = {})
|
117
|
+
work = false
|
118
|
+
test_file = "#{directory}/.listen_test"
|
119
|
+
callback = lambda { |changed_dirs, options| work = true }
|
120
|
+
adapter = self.new(directory, options, &callback)
|
121
|
+
adapter.start(false)
|
122
|
+
|
123
|
+
FileUtils.touch(test_file)
|
124
|
+
|
125
|
+
t = Thread.new { sleep(adapter.latency * 5); adapter.stop }
|
126
|
+
|
127
|
+
adapter.wait_for_callback
|
128
|
+
work
|
129
|
+
ensure
|
130
|
+
Thread.kill(t) if t
|
131
|
+
FileUtils.rm(test_file) if File.exists?(test_file)
|
132
|
+
adapter.stop
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
# Polls changed directories and reports them back
|
138
|
+
# when there are changes.
|
139
|
+
#
|
140
|
+
# @option [Boolean] recursive whether or not to pass the recursive option to the callback
|
141
|
+
#
|
142
|
+
def poll_changed_dirs(recursive = false)
|
143
|
+
until @stop
|
144
|
+
sleep(@latency)
|
145
|
+
next if @changed_dirs.empty?
|
146
|
+
|
147
|
+
changed_dirs = []
|
148
|
+
|
149
|
+
@mutex.synchronize do
|
150
|
+
changed_dirs = @changed_dirs.to_a
|
151
|
+
@changed_dirs.clear
|
113
152
|
end
|
153
|
+
|
154
|
+
@callback.call(changed_dirs, recursive ? {:recursive => recursive} : {})
|
155
|
+
@turnstile.signal
|
114
156
|
end
|
115
|
-
sleep 0.01 while @work.nil?
|
116
|
-
@work
|
117
157
|
end
|
118
|
-
|
119
158
|
end
|
120
159
|
end
|