listen 0.2.0 → 0.3.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 +6 -1
- data/LICENSE +1 -1
- data/README.md +91 -24
- data/lib/listen.rb +2 -0
- data/lib/listen/adapter.rb +90 -10
- data/lib/listen/adapters/darwin.rb +4 -5
- data/lib/listen/adapters/linux.rb +9 -13
- data/lib/listen/adapters/polling.rb +8 -6
- data/lib/listen/adapters/windows.rb +6 -8
- data/lib/listen/listener.rb +67 -12
- data/lib/listen/version.rb +1 -1
- metadata +11 -13
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,9 @@
|
|
1
|
-
##
|
1
|
+
## 0.3.0 - February 21, 2012
|
2
|
+
|
3
|
+
- Add automatic fallback to polling if system adapter doesn't work (like a DropBox folder). ([@thibaudgg][])
|
4
|
+
- Add latency and force_polling options. ([@Maher4Ever][])
|
5
|
+
|
6
|
+
## 0.2.0 - February 13, 2012
|
2
7
|
|
3
8
|
- Add checksum comparaison support for detecting consecutive file modifications made during the same second. ([@thibaudgg][])
|
4
9
|
- Add rb-fchange support. ([@thibaudgg][])
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,20 +1,16 @@
|
|
1
1
|
# Listen [](http://travis-ci.org/guard/listen)
|
2
2
|
|
3
|
-
**Work in progress...**
|
4
|
-
|
5
3
|
The Listen gem listens to file modifications and notifies you about the changes.
|
6
4
|
|
7
|
-
##
|
5
|
+
## Features
|
8
6
|
|
9
|
-
|
10
|
-
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
- Dropbox detection with polling fallback (if needed)
|
17
|
-
- Improve API (if needed)
|
7
|
+
* Works everywhere!
|
8
|
+
* OS-specific adapters for Mac OS X 10.6+, Linux and Windows.
|
9
|
+
* Automatic fallback to polling if OS-specific adapter doesn't work.
|
10
|
+
* Detects files modification, addidation and removal.
|
11
|
+
* Checksum comparaison for modifications made under the same second.
|
12
|
+
* Tested on all Ruby environments via [travis-ci](http://travis-ci.org/guard/listen).
|
13
|
+
* Threadable.
|
18
14
|
|
19
15
|
## Install
|
20
16
|
|
@@ -27,14 +23,12 @@ gem install listen
|
|
27
23
|
There are two ways you can use Listen.
|
28
24
|
|
29
25
|
1. call `Listen.to` with a path params, and define callbacks in a block.
|
30
|
-
|
26
|
+
2. create a `listener` object usable in an (ARel style) chainable way.
|
31
27
|
|
32
28
|
Feel free to give your feeback via [Listen issues](https://github.com/guard/listener/issues)
|
33
29
|
|
34
30
|
### Block API
|
35
31
|
|
36
|
-
#### One dir
|
37
|
-
|
38
32
|
``` ruby
|
39
33
|
Listen.to('dir/path/to/listen', filter: /.*\.rb/, ignore: '/ignored/path') do |modified, added, removed|
|
40
34
|
# ...
|
@@ -47,6 +41,9 @@ end
|
|
47
41
|
listener = Listen.to('dir/path/to/listen')
|
48
42
|
listener = listener.ignore('/ignored/path')
|
49
43
|
listener = listener.filter(/.*\.rb/)
|
44
|
+
listener = listener.latency(0.5)
|
45
|
+
listener = listener.force_polling(true)
|
46
|
+
listener = listener.polling_fallback_message(false)
|
50
47
|
listener = listener.change(&callback)
|
51
48
|
listener.start # enter the run loop
|
52
49
|
listener.stop
|
@@ -55,7 +52,14 @@ listener.stop
|
|
55
52
|
#### Chainable
|
56
53
|
|
57
54
|
``` ruby
|
58
|
-
Listen.to('dir/path/to/listen')
|
55
|
+
Listen.to('dir/path/to/listen')
|
56
|
+
.ignore('/ignored/path')
|
57
|
+
.filter(/.*\.rb/)
|
58
|
+
.latency(0.5)
|
59
|
+
.force_polling(true)
|
60
|
+
.polling_fallback_message('custom message')
|
61
|
+
.change(&callback)
|
62
|
+
.start # enter the run loop
|
59
63
|
```
|
60
64
|
|
61
65
|
#### Multiple listeners support available via Thread
|
@@ -74,20 +78,83 @@ Thread.new { scripts.start } # enter the run loop
|
|
74
78
|
These options can be set through `Listen.to` params or via methods (see the "Object" API)
|
75
79
|
|
76
80
|
```ruby
|
77
|
-
:filter => /.*\.rb/, /.*\.coffee/
|
78
|
-
|
81
|
+
:filter => /.*\.rb/, /.*\.coffee/ # Filter files to listen to via a regexps list.
|
82
|
+
# default: none
|
83
|
+
|
84
|
+
:ignore => 'path1', 'path2' # Ignore a list of paths (root directory or sub-dir)
|
85
|
+
# default: '.bundle', '.git', '.DS_Store', 'log', 'tmp', 'vendor'
|
79
86
|
|
80
|
-
:
|
81
|
-
|
87
|
+
:latency => 0.5 # Set the delay (**in seconds**) between checking for changes
|
88
|
+
# default: 0.1 sec (1.0 sec for polling)
|
89
|
+
|
90
|
+
:force_polling => true # Force the use of the polling adapter
|
91
|
+
# default: none
|
92
|
+
|
93
|
+
:polling_fallback_message => 'custom message' # Set a custom polling fallback message (or disable it with `false`)
|
94
|
+
# default: "WARNING: Listen fallen back to polling, learn more at https://github.com/guard/listen#fallback."
|
82
95
|
```
|
83
96
|
|
97
|
+
## Listen adapters
|
98
|
+
|
99
|
+
The Listen gem has a set of adapters to notify it when there are changes.
|
100
|
+
There are 3 OS-specific adapters to support Mac, Linux and Windows. These adapters are fast
|
101
|
+
as they use some system-calls to implement the notifying function.
|
102
|
+
|
103
|
+
There is also a polling adapter which is a cross-platform adapter and it will
|
104
|
+
work on any system. This adapter is unfortunately slower than the rest of the adapters.
|
105
|
+
|
106
|
+
The Listen gem will choose the best and working adapter for your machine automatically. If you
|
107
|
+
want to force the use of the polling adapter, either use the `:force_polling` option
|
108
|
+
while initializing the listener or call the `force_polling` method on your listener
|
109
|
+
before starting it.
|
110
|
+
|
111
|
+
<a name="fallback"/>
|
112
|
+
### Polling fallback
|
113
|
+
|
114
|
+
When the OS-specific adapter doesn't work the Listen gem automatically falls back to the polling adapter.
|
115
|
+
Here some things to try to avoiding this fallback:
|
116
|
+
|
117
|
+
* [Update your Dropbox client](http://www.dropbox.com/downloading) (if used).
|
118
|
+
* Move or rename the listened folder.
|
119
|
+
* Update/reboot your OS.
|
120
|
+
|
121
|
+
If it still falling back, feel free to [open an issue](https://github.com/guard/listen/issues/new) (and be sure to give all details).
|
122
|
+
|
123
|
+
## Development [](https://gemnasium.com/guard/listen)
|
124
|
+
|
125
|
+
* Documentation hosted at [RubyDoc](http://rubydoc.info/github/guard/listen/master/frames).
|
126
|
+
* Source hosted at [GitHub](https://github.com/guard/listen).
|
127
|
+
|
128
|
+
Pull requests are very welcome! Please try to follow these simple rules if applicable:
|
129
|
+
|
130
|
+
* Please create a topic branch for every separate change you make.
|
131
|
+
* Make sure your patches are well tested. All specs run with `rake spec:portability` must pass.
|
132
|
+
* Update the [Yard](http://yardoc.org/) documentation.
|
133
|
+
* Update the README.
|
134
|
+
* Update the CHANGELOG for noteworthy changes.
|
135
|
+
* Please **do not change** the version number.
|
136
|
+
|
137
|
+
For questions please join us in our [Google group](http://groups.google.com/group/guard-dev) or on
|
138
|
+
`#guard` (irc.freenode.net).
|
139
|
+
|
84
140
|
## Acknowledgment
|
85
141
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
142
|
+
* [Michael Kessler (netzpirat)][] for having written the [initial specs](https://github.com/guard/listen/commit/1e457b13b1bb8a25d2240428ce5ed488bafbed1f).
|
143
|
+
* [Travis Tilley (ttilley)][] for this awesome work on [fssm][] & [rb-fsevent][].
|
144
|
+
* [Nathan Weizenbaum (nex3)][] for [rb-inotify][], a thorough inotify wrapper.
|
145
|
+
* [stereobooster][] for [rb-fchange][], windows support wouldn't exist without him.
|
146
|
+
* [Yehuda Katz (wycats)][] for [vigilo][], that has been a great source of inspiration.
|
147
|
+
|
148
|
+
## Author
|
149
|
+
|
150
|
+
[Thibaud Guillaume-Gentil][] ([@thibaudgg](http://twitter.com/thibaudgg))
|
151
|
+
|
152
|
+
## Contributors
|
153
|
+
|
154
|
+
[https://github.com/guard/listen/contributors](https://github.com/guard/listen/contributors)
|
90
155
|
|
156
|
+
[Thibaud Guillaume-Gentil]: https://github.com/thibaudgg
|
157
|
+
[Michael Kessler (netzpirat)]: https://github.com/netzpirat
|
91
158
|
[Travis Tilley (ttilley)]: https://github.com/ttilley
|
92
159
|
[fssm]: https://github.com/ttilley/fssm
|
93
160
|
[rb-fsevent]: https://github.com/thibaudgg/rb-fsevent
|
data/lib/listen.rb
CHANGED
@@ -8,6 +8,8 @@ module Listen
|
|
8
8
|
# @param [Hash] options the listen options
|
9
9
|
# @option options [String] ignore a list of paths to ignore
|
10
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
|
11
13
|
#
|
12
14
|
# @yield [modified, added, removed] the changed files
|
13
15
|
# @yieldparam [Array<String>] modified the list of modified files
|
data/lib/listen/adapter.rb
CHANGED
@@ -4,35 +4,115 @@ module Listen
|
|
4
4
|
class Adapter
|
5
5
|
attr_accessor :latency
|
6
6
|
|
7
|
+
# The default delay between checking for changes.
|
8
|
+
DEFAULT_LATENCY = 0.1
|
9
|
+
# 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."
|
11
|
+
|
7
12
|
# Select the appropriate adapter implementation for the
|
8
13
|
# current OS and initializes it.
|
9
14
|
#
|
15
|
+
# @param [String, Pathname] directory the directory to watch
|
16
|
+
# @param [Hash] options the adapter options
|
17
|
+
# @option options [Boolean] force_polling to force polling or not
|
18
|
+
# @option options [String, Boolean] polling_fallback_message to change polling fallback message or remove it
|
19
|
+
# @option options [Float] latency the delay between checking for changes in seconds
|
20
|
+
#
|
21
|
+
# @yield [changed_dirs, options] callback Callback called when a change happens
|
22
|
+
# @yieldparam [Array<String>] changed_dirs the changed directories
|
23
|
+
# @yieldparam [Hash] options callback options (like :recursive => true)
|
24
|
+
#
|
10
25
|
# @return [Listen::Adapter] the chosen adapter
|
11
26
|
#
|
12
|
-
def self.select_and_initialize(
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
Adapters::
|
17
|
-
elsif Adapters::
|
18
|
-
Adapters::
|
27
|
+
def self.select_and_initialize(directory, options = {}, &callback)
|
28
|
+
return Adapters::Polling.new(directory, options, &callback) if options.delete(:force_polling)
|
29
|
+
|
30
|
+
if Adapters::Darwin.usable_and_work?(directory, options)
|
31
|
+
Adapters::Darwin.new(directory, options, &callback)
|
32
|
+
elsif Adapters::Linux.usable_and_work?(directory, options)
|
33
|
+
Adapters::Linux.new(directory, options, &callback)
|
34
|
+
elsif Adapters::Windows.usable_and_work?(directory, options)
|
35
|
+
Adapters::Windows.new(directory, options, &callback)
|
19
36
|
else
|
20
|
-
|
37
|
+
unless options[:polling_fallback_message] == false
|
38
|
+
Kernel.warn(options[:polling_fallback_message] || POLLING_FALLBACK_MESSAGE)
|
39
|
+
end
|
40
|
+
Adapters::Polling.new(directory, options, &callback)
|
21
41
|
end
|
22
42
|
end
|
23
43
|
|
24
|
-
|
25
|
-
|
44
|
+
# Initialize the adapter.
|
45
|
+
#
|
46
|
+
# @param [String, Pathname] directory the directory to watch
|
47
|
+
# @param [Hash] options the adapter options
|
48
|
+
# @option options [Float] latency the delay between checking for changes in seconds
|
49
|
+
#
|
50
|
+
# @yield [changed_dirs, options] callback Callback called when a change happens
|
51
|
+
# @yieldparam [Array<String>] changed_dirs the changed directories
|
52
|
+
# @yieldparam [Hash] options callback options (like :recursive => true)
|
53
|
+
#
|
54
|
+
# @return [Listen::Adapter] the adapter
|
55
|
+
#
|
56
|
+
def initialize(directory, options = {}, &callback)
|
57
|
+
@directory = directory
|
58
|
+
@callback = callback
|
59
|
+
@latency ||= DEFAULT_LATENCY
|
60
|
+
@latency = options[:latency] if options[:latency]
|
26
61
|
end
|
27
62
|
|
28
63
|
# Start the adapter.
|
29
64
|
#
|
30
65
|
def start
|
66
|
+
@stop = false
|
31
67
|
end
|
32
68
|
|
33
69
|
# Stop the adapter.
|
34
70
|
#
|
35
71
|
def stop
|
72
|
+
@stop = true
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
# Check if the adapter is usable and works on the current OS.
|
78
|
+
#
|
79
|
+
# @param [String, Pathname] directory the directory to watch
|
80
|
+
# @param [Hash] options the adapter options
|
81
|
+
# @option options [Float] latency the delay between checking for changes in seconds
|
82
|
+
#
|
83
|
+
# @return [Boolean] whether usable and work or not
|
84
|
+
#
|
85
|
+
def self.usable_and_work?(directory, options = {})
|
86
|
+
usable? && work?(directory, options)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Check if the adapter is really working on the current OS by actually testing it.
|
90
|
+
# This test take some time depending the adapter latency (max latency + 0.2 seconds).
|
91
|
+
#
|
92
|
+
# @param [String, Pathname] directory the directory to watch
|
93
|
+
# @param [Hash] options the adapter options
|
94
|
+
# @option options [Float] latency the delay between checking for changes in seconds
|
95
|
+
#
|
96
|
+
# @return [Boolean] whether work or not
|
97
|
+
#
|
98
|
+
def self.work?(directory, options = {})
|
99
|
+
@work = nil
|
100
|
+
Thread.new do
|
101
|
+
begin
|
102
|
+
callback = lambda { |changed_dirs, options| @work = true }
|
103
|
+
adapter = self.new(directory, options, &callback)
|
104
|
+
thread = Thread.new { adapter.start }
|
105
|
+
sleep 0.1 # wait for the adapter starts
|
106
|
+
FileUtils.touch "#{directory}/.listen_test"
|
107
|
+
sleep adapter.latency + 0.1 # wait for callback
|
108
|
+
@work ||= false
|
109
|
+
Thread.kill(thread)
|
110
|
+
ensure
|
111
|
+
FileUtils.rm "#{directory}/.listen_test"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
sleep 0.01 while @work.nil?
|
115
|
+
@work
|
36
116
|
end
|
37
117
|
|
38
118
|
end
|
@@ -5,11 +5,10 @@ module Listen
|
|
5
5
|
#
|
6
6
|
class Darwin < Adapter
|
7
7
|
|
8
|
-
# Initialize the Adapter.
|
8
|
+
# Initialize the Adapter. See {Listen::Adapter#initialize} for more info.
|
9
9
|
#
|
10
|
-
def initialize(
|
10
|
+
def initialize(directory, options = {}, &callback)
|
11
11
|
super
|
12
|
-
@latency ||= 0.1
|
13
12
|
init_worker
|
14
13
|
end
|
15
14
|
|
@@ -46,9 +45,9 @@ module Listen
|
|
46
45
|
#
|
47
46
|
def init_worker
|
48
47
|
@worker = FSEvent.new
|
49
|
-
@worker.watch(@
|
48
|
+
@worker.watch(@directory, :latency => @latency) do |changed_dirs|
|
50
49
|
changed_dirs.map! { |path| path.sub /\/$/, '' }
|
51
|
-
@
|
50
|
+
@callback.call(changed_dirs, {})
|
52
51
|
end
|
53
52
|
end
|
54
53
|
|
@@ -9,16 +9,15 @@ module Listen
|
|
9
9
|
# @see https://github.com/nex3/rb-inotify/blob/master/lib/rb-inotify/notifier.rb#L99-L177
|
10
10
|
#
|
11
11
|
EVENTS = %w[recursive attrib close modify move create delete delete_self move_self]
|
12
|
-
|
12
|
+
|
13
13
|
# Listener implementation for Linux `inotify`.
|
14
14
|
#
|
15
15
|
class Linux < Adapter
|
16
16
|
|
17
|
-
# Initialize the Adapter.
|
17
|
+
# Initialize the Adapter. See {Listen::Adapter#initialize} for more info.
|
18
18
|
#
|
19
|
-
def initialize(
|
19
|
+
def initialize(directory, options = {}, &callback)
|
20
20
|
super
|
21
|
-
@latency ||= 0.1
|
22
21
|
@changed_dirs = Set.new
|
23
22
|
init_worker
|
24
23
|
end
|
@@ -28,7 +27,6 @@ module Listen
|
|
28
27
|
def start
|
29
28
|
super
|
30
29
|
Thread.new { @worker.run }
|
31
|
-
@stop = false
|
32
30
|
poll_changed_dirs
|
33
31
|
end
|
34
32
|
|
@@ -36,7 +34,6 @@ module Listen
|
|
36
34
|
#
|
37
35
|
def stop
|
38
36
|
super
|
39
|
-
@stop = true
|
40
37
|
@worker.stop
|
41
38
|
end
|
42
39
|
|
@@ -54,28 +51,27 @@ module Listen
|
|
54
51
|
end
|
55
52
|
|
56
53
|
private
|
57
|
-
|
58
|
-
#
|
54
|
+
|
55
|
+
# Initialize INotify worker and set watch callback block.
|
59
56
|
#
|
60
57
|
def init_worker
|
61
58
|
@worker = INotify::Notifier.new
|
62
|
-
@worker.watch(@
|
59
|
+
@worker.watch(@directory, *EVENTS.map(&:to_sym)) do |event|
|
63
60
|
unless event.name == "" # Event on root directory
|
64
61
|
@changed_dirs << File.dirname(event.absolute_name)
|
65
62
|
end
|
66
63
|
end
|
67
64
|
end
|
68
|
-
|
65
|
+
|
69
66
|
# Polling around @changed_dirs presence.
|
70
67
|
#
|
71
68
|
def poll_changed_dirs
|
72
69
|
until @stop
|
73
70
|
sleep(@latency)
|
74
|
-
|
75
71
|
next if @changed_dirs.empty?
|
76
72
|
changed_dirs = @changed_dirs.to_a
|
77
|
-
@changed_dirs.clear
|
78
|
-
@
|
73
|
+
@changed_dirs.clear
|
74
|
+
@callback.call(changed_dirs, {})
|
79
75
|
end
|
80
76
|
end
|
81
77
|
|
@@ -1,6 +1,9 @@
|
|
1
1
|
module Listen
|
2
2
|
module Adapters
|
3
3
|
|
4
|
+
# The default delay between checking for changes.
|
5
|
+
DEFAULT_POLLING_LATENCY = 1.0
|
6
|
+
|
4
7
|
# Polling Adapter that works cross-platform and
|
5
8
|
# has no dependencies. This is the adapter that
|
6
9
|
# uses the most CPU processing power and has higher
|
@@ -8,18 +11,17 @@ module Listen
|
|
8
11
|
#
|
9
12
|
class Polling < Adapter
|
10
13
|
|
11
|
-
# Initialize the Adapter.
|
14
|
+
# Initialize the Adapter. See {Listen::Adapter#initialize} for more info.
|
12
15
|
#
|
13
|
-
def initialize(
|
16
|
+
def initialize(directory, options = {}, &callback)
|
17
|
+
@latency ||= DEFAULT_POLLING_LATENCY
|
14
18
|
super
|
15
|
-
@latency ||= 1.0
|
16
19
|
end
|
17
20
|
|
18
21
|
# Start the adapter.
|
19
22
|
#
|
20
23
|
def start
|
21
24
|
super
|
22
|
-
@stop = false
|
23
25
|
poll
|
24
26
|
end
|
25
27
|
|
@@ -27,7 +29,6 @@ module Listen
|
|
27
29
|
#
|
28
30
|
def stop
|
29
31
|
super
|
30
|
-
@stop = true
|
31
32
|
end
|
32
33
|
|
33
34
|
private
|
@@ -37,10 +38,11 @@ module Listen
|
|
37
38
|
def poll
|
38
39
|
until @stop
|
39
40
|
start = Time.now.to_f
|
40
|
-
@
|
41
|
+
@callback.call([@directory], :recursive => true)
|
41
42
|
nap_time = @latency - (Time.now.to_f - start)
|
42
43
|
sleep(nap_time) if nap_time > 0
|
43
44
|
end
|
45
|
+
rescue Interrupt
|
44
46
|
end
|
45
47
|
|
46
48
|
end
|
@@ -7,11 +7,10 @@ module Listen
|
|
7
7
|
#
|
8
8
|
class Windows < Adapter
|
9
9
|
|
10
|
-
# Initialize the Adapter.
|
10
|
+
# Initialize the Adapter. See {Listen::Adapter#initialize} for more info.
|
11
11
|
#
|
12
|
-
def initialize(
|
12
|
+
def initialize(directory, options = {}, &callback)
|
13
13
|
super
|
14
|
-
@latency ||= 0.1
|
15
14
|
@changed_dirs = Set.new
|
16
15
|
init_worker
|
17
16
|
end
|
@@ -21,7 +20,6 @@ module Listen
|
|
21
20
|
def start
|
22
21
|
super
|
23
22
|
Thread.new { @worker.run }
|
24
|
-
@stop = false
|
25
23
|
poll_changed_dirs
|
26
24
|
end
|
27
25
|
|
@@ -51,21 +49,21 @@ module Listen
|
|
51
49
|
#
|
52
50
|
def init_worker
|
53
51
|
@worker = FChange::Notifier.new
|
54
|
-
@worker.watch(@
|
52
|
+
@worker.watch(@directory, :all_events, :recursive) do |event|
|
55
53
|
@changed_dirs << File.expand_path(event.watcher.path)
|
56
54
|
end
|
57
55
|
end
|
58
|
-
|
56
|
+
|
59
57
|
# Polling around @changed_dirs presence.
|
60
58
|
#
|
61
59
|
def poll_changed_dirs
|
62
60
|
until @stop
|
63
61
|
sleep(@latency)
|
64
|
-
|
62
|
+
|
65
63
|
next if @changed_dirs.empty?
|
66
64
|
changed_dirs = @changed_dirs.to_a
|
67
65
|
@changed_dirs.clear
|
68
|
-
@
|
66
|
+
@callback.call(changed_dirs, :recursive => true)
|
69
67
|
end
|
70
68
|
end
|
71
69
|
|
data/lib/listen/listener.rb
CHANGED
@@ -9,17 +9,20 @@ require 'listen/adapters/windows'
|
|
9
9
|
|
10
10
|
module Listen
|
11
11
|
class Listener
|
12
|
-
attr_accessor :directory, :ignored_paths, :file_filters, :sha1_checksums, :paths
|
12
|
+
attr_accessor :directory, :ignored_paths, :file_filters, :sha1_checksums, :paths
|
13
13
|
|
14
14
|
# Default paths that gets ignored by the listener
|
15
15
|
DEFAULT_IGNORED_PATHS = %w[.bundle .git .DS_Store log tmp vendor]
|
16
16
|
|
17
17
|
# Initialize the file listener.
|
18
18
|
#
|
19
|
-
# @param [String, Pathname]
|
19
|
+
# @param [String, Pathname] directory the directory to watch
|
20
20
|
# @param [Hash] options the listen options
|
21
21
|
# @option options [String] ignore a list of paths to ignore
|
22
22
|
# @option options [Regexp] filter a list of regexps file filters
|
23
|
+
# @option options [Float] latency the delay between checking for changes in seconds
|
24
|
+
# @option options [Boolean] force_polling whether to force the polling adapter or not
|
25
|
+
# @option options [String, Boolean] polling_fallback_message to change polling fallback message or remove it
|
23
26
|
#
|
24
27
|
# @yield [modified, added, removed] the changed files
|
25
28
|
# @yieldparam [Array<String>] modified the list of modified files
|
@@ -28,23 +31,24 @@ module Listen
|
|
28
31
|
#
|
29
32
|
# @return [Listen::Listener] the file listener
|
30
33
|
#
|
31
|
-
def initialize(
|
32
|
-
@directory =
|
34
|
+
def initialize(directory, options = {}, &block)
|
35
|
+
@directory = directory
|
33
36
|
@ignored_paths = DEFAULT_IGNORED_PATHS
|
34
37
|
@file_filters = []
|
35
38
|
@sha1_checksums = {}
|
36
39
|
@block = block
|
37
|
-
if
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
@adapter = Adapter.select_and_initialize(self)
|
40
|
+
@ignored_paths += Array(options.delete(:ignore)) if options[:ignore]
|
41
|
+
@file_filters += Array(options.delete(:filter)) if options[:filter]
|
42
|
+
|
43
|
+
@adapter_options = options
|
42
44
|
end
|
43
45
|
|
44
|
-
# Initialize the @paths and start the adapter.
|
46
|
+
# Initialize the adapter and the @paths concurrently and start the adapter.
|
45
47
|
#
|
46
48
|
def start
|
49
|
+
Thread.new { @adapter = initialize_adapter }
|
47
50
|
init_paths
|
51
|
+
sleep 0.01 while @adapter.nil?
|
48
52
|
@adapter.start
|
49
53
|
end
|
50
54
|
|
@@ -82,9 +86,53 @@ module Listen
|
|
82
86
|
self
|
83
87
|
end
|
84
88
|
|
89
|
+
# Sets the latency for the adapter. This is a helper method
|
90
|
+
# to simplify changing the latency directly from the listener.
|
91
|
+
#
|
92
|
+
# @example Wait 0.5 seconds each time before checking changes
|
93
|
+
# latency 0.5
|
94
|
+
#
|
95
|
+
# @param [Float] seconds the amount of delay, in seconds
|
96
|
+
#
|
97
|
+
# @return [Listen::Listener] the listener itself
|
98
|
+
#
|
99
|
+
def latency(seconds)
|
100
|
+
@adapter_options[:latency] = seconds
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
104
|
+
# Defines whether the use of the polling adapter
|
105
|
+
# should be forced or not.
|
106
|
+
#
|
107
|
+
# @example Forcing the use of the polling adapter
|
108
|
+
# force_polling true
|
109
|
+
#
|
110
|
+
# @param [Boolean] value wheather to force the polling adapter or not
|
111
|
+
#
|
112
|
+
# @return [Listen::Listener] the listener itself
|
113
|
+
#
|
114
|
+
def force_polling(value)
|
115
|
+
@adapter_options[:force_polling] = value
|
116
|
+
self
|
117
|
+
end
|
118
|
+
|
119
|
+
# Defines a custom polling fallback message of disable it.
|
120
|
+
#
|
121
|
+
# @example Disabling the polling fallback message
|
122
|
+
# polling_fallback_message false
|
123
|
+
#
|
124
|
+
# @param [String, Boolean] value to change polling fallback message or remove it
|
125
|
+
#
|
126
|
+
# @return [Listen::Listener] the listener itself
|
127
|
+
#
|
128
|
+
def polling_fallback_message(value)
|
129
|
+
@adapter_options[:polling_fallback_message] = value
|
130
|
+
self
|
131
|
+
end
|
132
|
+
|
85
133
|
# Set change callback block to the listener.
|
86
134
|
#
|
87
|
-
# @example
|
135
|
+
# @example Assign a callback to be called on changes
|
88
136
|
# callback = lambda { |modified, added, removed| ... }
|
89
137
|
# change &callback
|
90
138
|
#
|
@@ -136,6 +184,13 @@ module Listen
|
|
136
184
|
|
137
185
|
private
|
138
186
|
|
187
|
+
# Initialize adapter with the listener callback and the @adapter_options
|
188
|
+
#
|
189
|
+
def initialize_adapter
|
190
|
+
callback = lambda { |changed_dirs, options| self.on_change(changed_dirs, options) }
|
191
|
+
Adapter.select_and_initialize(@directory, @adapter_options, &callback)
|
192
|
+
end
|
193
|
+
|
139
194
|
# Research all existing paths (directories & files) filtered and without ignored directories paths.
|
140
195
|
#
|
141
196
|
# @yield [path] the existing path
|
@@ -183,7 +238,7 @@ module Listen
|
|
183
238
|
def detect_modifications_and_removals(directory, options = {})
|
184
239
|
@paths[directory].each do |basename, type|
|
185
240
|
path = File.join(directory, basename)
|
186
|
-
|
241
|
+
|
187
242
|
case type
|
188
243
|
when 'Dir'
|
189
244
|
if File.directory?(path)
|
data/lib/listen/version.rb
CHANGED
metadata
CHANGED
@@ -1,20 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: listen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Thibaud Guillaume-Gentil
|
9
|
-
- Michael Kessler
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-21 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: rb-fsevent
|
17
|
-
requirement: &
|
16
|
+
requirement: &70190939404480 !ruby/object:Gem::Requirement
|
18
17
|
none: false
|
19
18
|
requirements:
|
20
19
|
- - ~>
|
@@ -22,10 +21,10 @@ dependencies:
|
|
22
21
|
version: 0.9.0
|
23
22
|
type: :runtime
|
24
23
|
prerelease: false
|
25
|
-
version_requirements: *
|
24
|
+
version_requirements: *70190939404480
|
26
25
|
- !ruby/object:Gem::Dependency
|
27
26
|
name: rb-inotify
|
28
|
-
requirement: &
|
27
|
+
requirement: &70190939403840 !ruby/object:Gem::Requirement
|
29
28
|
none: false
|
30
29
|
requirements:
|
31
30
|
- - ~>
|
@@ -33,10 +32,10 @@ dependencies:
|
|
33
32
|
version: 0.8.8
|
34
33
|
type: :runtime
|
35
34
|
prerelease: false
|
36
|
-
version_requirements: *
|
35
|
+
version_requirements: *70190939403840
|
37
36
|
- !ruby/object:Gem::Dependency
|
38
37
|
name: rb-fchange
|
39
|
-
requirement: &
|
38
|
+
requirement: &70190939403220 !ruby/object:Gem::Requirement
|
40
39
|
none: false
|
41
40
|
requirements:
|
42
41
|
- - ~>
|
@@ -44,10 +43,10 @@ dependencies:
|
|
44
43
|
version: 0.0.5
|
45
44
|
type: :runtime
|
46
45
|
prerelease: false
|
47
|
-
version_requirements: *
|
46
|
+
version_requirements: *70190939403220
|
48
47
|
- !ruby/object:Gem::Dependency
|
49
48
|
name: bundler
|
50
|
-
requirement: &
|
49
|
+
requirement: &70190939402680 !ruby/object:Gem::Requirement
|
51
50
|
none: false
|
52
51
|
requirements:
|
53
52
|
- - ! '>='
|
@@ -55,12 +54,11 @@ dependencies:
|
|
55
54
|
version: '0'
|
56
55
|
type: :development
|
57
56
|
prerelease: false
|
58
|
-
version_requirements: *
|
57
|
+
version_requirements: *70190939402680
|
59
58
|
description: The Listen gem listens to file modifications and notifies you about the
|
60
59
|
changes. Works everywhere!
|
61
60
|
email:
|
62
61
|
- thibaud@thibaud.me
|
63
|
-
- michi@netzpiraten.ch
|
64
62
|
executables: []
|
65
63
|
extensions: []
|
66
64
|
extra_rdoc_files: []
|
@@ -96,7 +94,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
94
|
version: 1.3.6
|
97
95
|
requirements: []
|
98
96
|
rubyforge_project: listen
|
99
|
-
rubygems_version: 1.8.
|
97
|
+
rubygems_version: 1.8.16
|
100
98
|
signing_key:
|
101
99
|
specification_version: 3
|
102
100
|
summary: Listen to file modifications
|