joshbuddy-guard 0.10.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 +370 -0
- data/LICENSE +20 -0
- data/README.md +470 -0
- data/bin/fsevent_watch_guard +0 -0
- data/bin/guard +6 -0
- data/images/failed.png +0 -0
- data/images/pending.png +0 -0
- data/images/success.png +0 -0
- data/lib/guard.rb +463 -0
- data/lib/guard/cli.rb +125 -0
- data/lib/guard/dsl.rb +370 -0
- data/lib/guard/dsl_describer.rb +150 -0
- data/lib/guard/group.rb +37 -0
- data/lib/guard/guard.rb +129 -0
- data/lib/guard/hook.rb +118 -0
- data/lib/guard/interactor.rb +116 -0
- data/lib/guard/listener.rb +351 -0
- data/lib/guard/listeners/darwin.rb +60 -0
- data/lib/guard/listeners/linux.rb +91 -0
- data/lib/guard/listeners/polling.rb +55 -0
- data/lib/guard/listeners/windows.rb +61 -0
- data/lib/guard/notifier.rb +290 -0
- data/lib/guard/templates/Guardfile +2 -0
- data/lib/guard/ui.rb +193 -0
- data/lib/guard/version.rb +6 -0
- data/lib/guard/watcher.rb +114 -0
- data/lib/vendor/darwin/Gemfile +6 -0
- data/lib/vendor/darwin/Guardfile +8 -0
- data/lib/vendor/darwin/LICENSE +20 -0
- data/lib/vendor/darwin/README.rdoc +254 -0
- data/lib/vendor/darwin/Rakefile +21 -0
- data/lib/vendor/darwin/ext/extconf.rb +61 -0
- data/lib/vendor/darwin/ext/fsevent/fsevent_watch.c +226 -0
- data/lib/vendor/darwin/lib/rb-fsevent.rb +2 -0
- data/lib/vendor/darwin/lib/rb-fsevent/fsevent.rb +105 -0
- data/lib/vendor/darwin/lib/rb-fsevent/version.rb +3 -0
- data/lib/vendor/darwin/rb-fsevent.gemspec +24 -0
- data/lib/vendor/darwin/spec/fixtures/folder1/file1.txt +0 -0
- data/lib/vendor/darwin/spec/fixtures/folder1/folder2/file2.txt +0 -0
- data/lib/vendor/darwin/spec/rb-fsevent/fsevent_spec.rb +75 -0
- data/lib/vendor/darwin/spec/spec_helper.rb +24 -0
- data/lib/vendor/linux/MIT-LICENSE +20 -0
- data/lib/vendor/linux/README.md +66 -0
- data/lib/vendor/linux/Rakefile +54 -0
- data/lib/vendor/linux/VERSION +1 -0
- data/lib/vendor/linux/lib/rb-inotify.rb +17 -0
- data/lib/vendor/linux/lib/rb-inotify/event.rb +139 -0
- data/lib/vendor/linux/lib/rb-inotify/native.rb +31 -0
- data/lib/vendor/linux/lib/rb-inotify/native/flags.rb +89 -0
- data/lib/vendor/linux/lib/rb-inotify/notifier.rb +308 -0
- data/lib/vendor/linux/lib/rb-inotify/watcher.rb +83 -0
- data/lib/vendor/linux/rb-inotify.gemspec +53 -0
- data/lib/vendor/windows/Gemfile +4 -0
- data/lib/vendor/windows/README.md +34 -0
- data/lib/vendor/windows/Rakefile +18 -0
- data/lib/vendor/windows/lib/rb-fchange.rb +14 -0
- data/lib/vendor/windows/lib/rb-fchange/event.rb +29 -0
- data/lib/vendor/windows/lib/rb-fchange/native.rb +45 -0
- data/lib/vendor/windows/lib/rb-fchange/native/flags.rb +78 -0
- data/lib/vendor/windows/lib/rb-fchange/notifier.rb +149 -0
- data/lib/vendor/windows/lib/rb-fchange/version.rb +3 -0
- data/lib/vendor/windows/lib/rb-fchange/watcher.rb +99 -0
- data/lib/vendor/windows/rb-fchange.gemspec +34 -0
- data/lib/vendor/windows/spec/fixtures/folder1/file1.txt +0 -0
- data/lib/vendor/windows/spec/fixtures/folder1/folder2/file2.txt +0 -0
- data/lib/vendor/windows/spec/rb-fchange/fchange_spec.rb +119 -0
- data/lib/vendor/windows/spec/spec_helper.rb +21 -0
- data/man/guard.1 +96 -0
- data/man/guard.1.html +181 -0
- metadata +193 -0
@@ -0,0 +1,351 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'digest/sha1'
|
3
|
+
|
4
|
+
module Guard
|
5
|
+
|
6
|
+
autoload :Darwin, 'guard/listeners/darwin'
|
7
|
+
autoload :Linux, 'guard/listeners/linux'
|
8
|
+
autoload :Windows, 'guard/listeners/windows'
|
9
|
+
autoload :Polling, 'guard/listeners/polling'
|
10
|
+
|
11
|
+
# The Listener is the base class for all listener
|
12
|
+
# implementations.
|
13
|
+
#
|
14
|
+
# @abstract
|
15
|
+
#
|
16
|
+
class Listener
|
17
|
+
|
18
|
+
# Default paths that gets ignored by the listener
|
19
|
+
DEFAULT_IGNORE_PATHS = %w[. .. .bundle .git log tmp vendor]
|
20
|
+
|
21
|
+
attr_accessor :changed_files
|
22
|
+
attr_reader :directory, :ignore_paths
|
23
|
+
|
24
|
+
def paused?
|
25
|
+
@paused
|
26
|
+
end
|
27
|
+
|
28
|
+
# Select the appropriate listener implementation for the
|
29
|
+
# current OS and initializes it.
|
30
|
+
#
|
31
|
+
# @param [Array] args the arguments for the listener
|
32
|
+
# @return [Guard::Listener] the chosen listener
|
33
|
+
#
|
34
|
+
def self.select_and_init(watchdir = Dir.pwd, options = nil)
|
35
|
+
no_vendor = options && options.key?(:no_vendor) ? options[:no_vendor] : false
|
36
|
+
if mac? && Darwin.usable?(no_vendor)
|
37
|
+
Darwin.new(watchdir, options)
|
38
|
+
elsif linux? && Linux.usable?(no_vendor)
|
39
|
+
Linux.new(watchdir, options)
|
40
|
+
elsif windows? && Windows.usable?(no_vendor)
|
41
|
+
Windows.new(watchdir, options)
|
42
|
+
else
|
43
|
+
UI.info 'Using polling (Please help us to support your system better than that).'
|
44
|
+
Polling.new(watchdir, options)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Initialize the listener.
|
49
|
+
#
|
50
|
+
# @param [String] directory the root directory to listen to
|
51
|
+
# @option options [Boolean] relativize_paths use only relative paths
|
52
|
+
# @option options [Array<String>] ignore_paths the paths to ignore by the listener
|
53
|
+
#
|
54
|
+
def initialize(directory = Dir.pwd, options = {})
|
55
|
+
@directory = directory.to_s
|
56
|
+
@sha1_checksums_hash = {}
|
57
|
+
@file_timestamp_hash = {}
|
58
|
+
@relativize_paths = options.fetch(:relativize_paths, true)
|
59
|
+
@changed_files = []
|
60
|
+
@paused = false
|
61
|
+
@ignore_paths = DEFAULT_IGNORE_PATHS
|
62
|
+
@ignore_paths |= options[:ignore_paths] if options[:ignore_paths]
|
63
|
+
@watch_all_modifications = options.fetch(:watch_all_modifications, false)
|
64
|
+
|
65
|
+
update_last_event
|
66
|
+
start_reactor
|
67
|
+
end
|
68
|
+
|
69
|
+
# Start the listener thread.
|
70
|
+
#
|
71
|
+
def start_reactor
|
72
|
+
return if ENV["GUARD_ENV"] == 'test'
|
73
|
+
|
74
|
+
Thread.new do
|
75
|
+
loop do
|
76
|
+
if @changed_files != [] && !@paused
|
77
|
+
changed_files = @changed_files.dup
|
78
|
+
clear_changed_files
|
79
|
+
::Guard.run_on_change(changed_files)
|
80
|
+
else
|
81
|
+
sleep 0.1
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Start watching the root directory.
|
88
|
+
#
|
89
|
+
def start
|
90
|
+
watch(@directory)
|
91
|
+
timestamp_files
|
92
|
+
end
|
93
|
+
|
94
|
+
# Stop listening for events.
|
95
|
+
#
|
96
|
+
def stop
|
97
|
+
end
|
98
|
+
|
99
|
+
# Pause the listener to ignore change events.
|
100
|
+
#
|
101
|
+
def pause
|
102
|
+
@paused = true
|
103
|
+
end
|
104
|
+
|
105
|
+
# Unpause the listener to listen again to change events.
|
106
|
+
#
|
107
|
+
def run
|
108
|
+
@paused = false
|
109
|
+
end
|
110
|
+
|
111
|
+
# Clear the list of changed files.
|
112
|
+
#
|
113
|
+
def clear_changed_files
|
114
|
+
@changed_files.clear
|
115
|
+
end
|
116
|
+
|
117
|
+
# Store a listener callback.
|
118
|
+
#
|
119
|
+
# @param [Block] callback the callback to store
|
120
|
+
#
|
121
|
+
def on_change(&callback)
|
122
|
+
@callback = callback
|
123
|
+
end
|
124
|
+
|
125
|
+
# Updates the timestamp of the last event.
|
126
|
+
#
|
127
|
+
def update_last_event
|
128
|
+
@last_event = Time.now
|
129
|
+
end
|
130
|
+
|
131
|
+
# Get the modified files.
|
132
|
+
#
|
133
|
+
# If the `:watch_all_modifications` option is true, then moved and
|
134
|
+
# deleted files are also reported, but prefixed by an exclamation point.
|
135
|
+
#
|
136
|
+
# @example Deleted or moved file
|
137
|
+
# !/home/user/dir/file.rb
|
138
|
+
#
|
139
|
+
# @param [Array<String>] dirs the watched directories
|
140
|
+
# @param [Hash] options the listener options
|
141
|
+
# @option options [Symbol] all whether to files in sub directories
|
142
|
+
# @return [Array<String>] paths of files that have been modified
|
143
|
+
#
|
144
|
+
def modified_files(dirs, options = {})
|
145
|
+
last_event = @last_event
|
146
|
+
files = []
|
147
|
+
if @watch_all_modifications
|
148
|
+
deleted_files = @file_timestamp_hash.collect do |path, ts|
|
149
|
+
unless File.exists?(path)
|
150
|
+
@sha1_checksums_hash.delete(path)
|
151
|
+
@file_timestamp_hash.delete(path)
|
152
|
+
"!#{path}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
files.concat(deleted_files.compact)
|
156
|
+
end
|
157
|
+
update_last_event
|
158
|
+
files.concat(potentially_modified_files(dirs, options).select { |path| file_modified?(path, last_event) })
|
159
|
+
|
160
|
+
relativize_paths(files)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Register a directory to watch.
|
164
|
+
# Must be implemented by the subclasses.
|
165
|
+
#
|
166
|
+
# @param [String] directory the directory to watch
|
167
|
+
#
|
168
|
+
def watch(directory)
|
169
|
+
raise NotImplementedError, "do whatever you want here, given the directory as only argument"
|
170
|
+
end
|
171
|
+
|
172
|
+
# Get all files that are in the watched directory.
|
173
|
+
#
|
174
|
+
# @return [Array<String>] the list of files
|
175
|
+
#
|
176
|
+
def all_files
|
177
|
+
potentially_modified_files([@directory], :all => true)
|
178
|
+
end
|
179
|
+
|
180
|
+
# Scopes all given paths to the current directory.
|
181
|
+
#
|
182
|
+
# @param [Array<String>] paths the paths to change
|
183
|
+
# @return [Array<String>] all paths now relative to the current dir
|
184
|
+
#
|
185
|
+
def relativize_paths(paths)
|
186
|
+
return paths unless relativize_paths?
|
187
|
+
paths.map do |path|
|
188
|
+
path.gsub(%r{^(!)?#{ @directory }/},'\1')
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# Use paths relative to the current directory.
|
193
|
+
#
|
194
|
+
# @return [Boolean] whether to use relative or absolute paths
|
195
|
+
#
|
196
|
+
def relativize_paths?
|
197
|
+
!!@relativize_paths
|
198
|
+
end
|
199
|
+
|
200
|
+
# Populate initial timestamp file hash to watch for deleted or moved files.
|
201
|
+
#
|
202
|
+
def timestamp_files
|
203
|
+
all_files.each {|path| set_file_timestamp_hash(path, file_timestamp(path)) } if @watch_all_modifications
|
204
|
+
end
|
205
|
+
|
206
|
+
# Removes the ignored paths from the directory list.
|
207
|
+
#
|
208
|
+
# @param [Array<String>] dirs the directory to listen to
|
209
|
+
# @param [Array<String>] ignore_paths the paths to ignore
|
210
|
+
# @return children of the passed dirs that are not in the ignore_paths list
|
211
|
+
#
|
212
|
+
def exclude_ignored_paths(dirs, ignore_paths = self.ignore_paths)
|
213
|
+
Dir.glob(dirs.map { |d| "#{d.sub(%r{/+$}, '')}/*" }, File::FNM_DOTMATCH).reject do |path|
|
214
|
+
ignore_paths.include?(File.basename(path))
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
private
|
219
|
+
|
220
|
+
# Gets a list of files that are in the modified directories.
|
221
|
+
#
|
222
|
+
# @param [Array<String>] dirs the list of directories
|
223
|
+
# @param [Hash] options the find file option
|
224
|
+
# @option options [Symbol] all whether to files in sub directories
|
225
|
+
#
|
226
|
+
def potentially_modified_files(dirs, options = {})
|
227
|
+
paths = exclude_ignored_paths(dirs)
|
228
|
+
|
229
|
+
if options[:all]
|
230
|
+
paths.inject([]) do |array, path|
|
231
|
+
if File.file?(path)
|
232
|
+
array << path
|
233
|
+
else
|
234
|
+
array += Dir.glob("#{ path }/**/*", File::FNM_DOTMATCH).select { |p| File.file?(p) }
|
235
|
+
end
|
236
|
+
array
|
237
|
+
end
|
238
|
+
else
|
239
|
+
paths.select { |path| File.file?(path) }
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
# Test if the file content has changed.
|
244
|
+
#
|
245
|
+
# Depending on the filesystem, mtime/ctime is probably only precise to the second, so round
|
246
|
+
# both values down to the second for the comparison.
|
247
|
+
#
|
248
|
+
# ctime is used only on == comparison to always catches Rails 3.1 Assets pipelined on Mac OSX
|
249
|
+
#
|
250
|
+
# @param [String] path the file path
|
251
|
+
# @param [Time] last_event the time of the last event
|
252
|
+
# @return [Boolean] Whether the file content has changed or not.
|
253
|
+
#
|
254
|
+
def file_modified?(path, last_event)
|
255
|
+
ctime = File.ctime(path).to_i
|
256
|
+
mtime = File.mtime(path).to_i
|
257
|
+
if [mtime, ctime].max == last_event.to_i
|
258
|
+
file_content_modified?(path, sha1_checksum(path))
|
259
|
+
elsif mtime > last_event.to_i
|
260
|
+
set_sha1_checksums_hash(path, sha1_checksum(path))
|
261
|
+
true
|
262
|
+
elsif @watch_all_modifications
|
263
|
+
ts = file_timestamp(path)
|
264
|
+
if ts != @file_timestamp_hash[path]
|
265
|
+
set_file_timestamp_hash(path, ts)
|
266
|
+
true
|
267
|
+
end
|
268
|
+
else
|
269
|
+
false
|
270
|
+
end
|
271
|
+
rescue
|
272
|
+
false
|
273
|
+
end
|
274
|
+
|
275
|
+
# Tests if the file content has been modified by
|
276
|
+
# comparing the SHA1 checksum.
|
277
|
+
#
|
278
|
+
# @param [String] path the file path
|
279
|
+
# @param [String] sha1_checksum the checksum of the file
|
280
|
+
#
|
281
|
+
def file_content_modified?(path, sha1_checksum)
|
282
|
+
if @sha1_checksums_hash[path] != sha1_checksum
|
283
|
+
set_sha1_checksums_hash(path, sha1_checksum)
|
284
|
+
true
|
285
|
+
else
|
286
|
+
false
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# Set save a files current timestamp
|
291
|
+
#
|
292
|
+
# @param [String] path the file path
|
293
|
+
# @param [Int] file_timestamp the files modified timestamp
|
294
|
+
#
|
295
|
+
def set_file_timestamp_hash(path, file_timestamp)
|
296
|
+
@file_timestamp_hash[path] = file_timestamp
|
297
|
+
end
|
298
|
+
|
299
|
+
# Set the current checksum of a file.
|
300
|
+
#
|
301
|
+
# @param [String] path the file path
|
302
|
+
# @param [String] sha1_checksum the checksum of the file
|
303
|
+
#
|
304
|
+
def set_sha1_checksums_hash(path, sha1_checksum)
|
305
|
+
@sha1_checksums_hash[path] = sha1_checksum
|
306
|
+
end
|
307
|
+
|
308
|
+
# Gets a files modified timestamp
|
309
|
+
#
|
310
|
+
# @path [String] path the file path
|
311
|
+
# @return [Int] file modified timestamp
|
312
|
+
#
|
313
|
+
def file_timestamp(path)
|
314
|
+
File.mtime(path).to_i
|
315
|
+
end
|
316
|
+
|
317
|
+
# Calculates the SHA1 checksum of a file.
|
318
|
+
#
|
319
|
+
# @param [String] path the path to the file
|
320
|
+
# @return [String] the SHA1 checksum
|
321
|
+
#
|
322
|
+
def sha1_checksum(path)
|
323
|
+
Digest::SHA1.file(path).to_s
|
324
|
+
end
|
325
|
+
|
326
|
+
# Test if the OS is Mac OS X.
|
327
|
+
#
|
328
|
+
# @return [Boolean] Whether the OS is Mac OS X
|
329
|
+
#
|
330
|
+
def self.mac?
|
331
|
+
RbConfig::CONFIG['target_os'] =~ /darwin/i
|
332
|
+
end
|
333
|
+
|
334
|
+
# Test if the OS is Linux.
|
335
|
+
#
|
336
|
+
# @return [Boolean] Whether the OS is Linux
|
337
|
+
#
|
338
|
+
def self.linux?
|
339
|
+
RbConfig::CONFIG['target_os'] =~ /linux/i
|
340
|
+
end
|
341
|
+
|
342
|
+
# Test if the OS is Windows.
|
343
|
+
#
|
344
|
+
# @return [Boolean] Whether the OS is Windows
|
345
|
+
#
|
346
|
+
def self.windows?
|
347
|
+
RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
|
348
|
+
end
|
349
|
+
|
350
|
+
end
|
351
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Guard
|
2
|
+
|
3
|
+
# Listener implementation for Mac OS X `FSEvents`.
|
4
|
+
#
|
5
|
+
class Darwin < Listener
|
6
|
+
|
7
|
+
# Initialize the Listener.
|
8
|
+
#
|
9
|
+
def initialize(*)
|
10
|
+
super
|
11
|
+
@fsevent = FSEvent.new
|
12
|
+
end
|
13
|
+
|
14
|
+
# Start the listener.
|
15
|
+
#
|
16
|
+
def start
|
17
|
+
super
|
18
|
+
worker.run
|
19
|
+
end
|
20
|
+
|
21
|
+
# Stop the listener.
|
22
|
+
#
|
23
|
+
def stop
|
24
|
+
super
|
25
|
+
worker.stop
|
26
|
+
end
|
27
|
+
|
28
|
+
# Check if the listener is usable on the current OS.
|
29
|
+
#
|
30
|
+
# @return [Boolean] whether usable or not
|
31
|
+
#
|
32
|
+
def self.usable?(no_vendor = false)
|
33
|
+
$LOAD_PATH << File.expand_path('../../../vendor/darwin/lib', __FILE__) unless no_vendor
|
34
|
+
require 'rb-fsevent'
|
35
|
+
true
|
36
|
+
rescue LoadError
|
37
|
+
false
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# Get the listener worker.
|
43
|
+
#
|
44
|
+
def worker
|
45
|
+
@fsevent
|
46
|
+
end
|
47
|
+
|
48
|
+
# Watch the given directory for file changes.
|
49
|
+
#
|
50
|
+
# @param [String] directory the directory to watch
|
51
|
+
#
|
52
|
+
def watch(directory)
|
53
|
+
worker.watch(directory) do |modified_dirs|
|
54
|
+
files = modified_files(modified_dirs)
|
55
|
+
@callback.call(files) unless files.empty?
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Guard
|
2
|
+
|
3
|
+
# Listener implementation for Linux `inotify`.
|
4
|
+
#
|
5
|
+
class Linux < Listener
|
6
|
+
|
7
|
+
# Initialize the Listener.
|
8
|
+
#
|
9
|
+
def initialize(*)
|
10
|
+
super
|
11
|
+
@inotify = INotify::Notifier.new
|
12
|
+
@files = []
|
13
|
+
@latency = 0.5
|
14
|
+
end
|
15
|
+
|
16
|
+
# Start the listener.
|
17
|
+
#
|
18
|
+
def start
|
19
|
+
@stop = false
|
20
|
+
super
|
21
|
+
watch_change unless watch_change?
|
22
|
+
end
|
23
|
+
|
24
|
+
# Stop the listener.
|
25
|
+
#
|
26
|
+
def stop
|
27
|
+
super
|
28
|
+
@stop = true
|
29
|
+
end
|
30
|
+
|
31
|
+
# Check if the listener is usable on the current OS.
|
32
|
+
#
|
33
|
+
# @return [Boolean] whether usable or not
|
34
|
+
#
|
35
|
+
def self.usable?(no_vendor = false)
|
36
|
+
$LOAD_PATH << File.expand_path('../../../vendor/linux/lib', __FILE__) unless no_vendor
|
37
|
+
require 'rb-inotify'
|
38
|
+
true
|
39
|
+
rescue LoadError
|
40
|
+
false
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# Get the listener worker.
|
46
|
+
#
|
47
|
+
def worker
|
48
|
+
@inotify
|
49
|
+
end
|
50
|
+
|
51
|
+
# Watch the given directory for file changes.
|
52
|
+
#
|
53
|
+
# @param [String] directory the directory to watch
|
54
|
+
#
|
55
|
+
def watch(directory)
|
56
|
+
worker.watch(directory, :recursive, :attrib, :create, :move_self, :close_write) do |event|
|
57
|
+
unless event.name == "" # Event on root directory
|
58
|
+
@files << event.absolute_name
|
59
|
+
end
|
60
|
+
end
|
61
|
+
rescue Interrupt
|
62
|
+
end
|
63
|
+
|
64
|
+
# Test if inotify is watching for changes.
|
65
|
+
#
|
66
|
+
# @return [Boolean] whether inotify is active or not
|
67
|
+
#
|
68
|
+
def watch_change?
|
69
|
+
!!@watch_change
|
70
|
+
end
|
71
|
+
|
72
|
+
# Watch for file system changes.
|
73
|
+
#
|
74
|
+
def watch_change
|
75
|
+
@watch_change = true
|
76
|
+
until @stop
|
77
|
+
if RbConfig::CONFIG['build'] =~ /java/ || IO.select([worker.to_io], [], [], @latency)
|
78
|
+
break if @stop
|
79
|
+
|
80
|
+
sleep(@latency)
|
81
|
+
worker.process
|
82
|
+
|
83
|
+
files = modified_files(@files.shift(@files.size).map { |f| File.dirname(f) }.uniq)
|
84
|
+
@callback.call(files) unless files.empty?
|
85
|
+
end
|
86
|
+
end
|
87
|
+
@watch_change = false
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|