listen 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 [](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
|