listen 2.7.6 → 2.7.7
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.
- checksums.yaml +4 -4
- data/.gitignore +0 -0
- data/.rspec +0 -0
- data/.rubocop.yml +0 -0
- data/.travis.yml +0 -0
- data/.yardopts +0 -0
- data/CHANGELOG.md +0 -0
- data/CONTRIBUTING.md +0 -0
- data/Gemfile +2 -0
- data/Guardfile +2 -0
- data/LICENSE.txt +0 -0
- data/README.md +0 -0
- data/Rakefile +0 -0
- data/lib/listen.rb +0 -0
- data/lib/listen/adapter.rb +0 -0
- data/lib/listen/adapter/base.rb +47 -21
- data/lib/listen/adapter/bsd.rb +31 -25
- data/lib/listen/adapter/darwin.rb +13 -12
- data/lib/listen/adapter/linux.rb +45 -36
- data/lib/listen/adapter/polling.rb +12 -7
- data/lib/listen/adapter/tcp.rb +9 -4
- data/lib/listen/adapter/windows.rb +46 -58
- data/lib/listen/change.rb +12 -8
- data/lib/listen/cli.rb +0 -0
- data/lib/listen/directory.rb +30 -22
- data/lib/listen/file.rb +9 -8
- data/lib/listen/listener.rb +35 -12
- data/lib/listen/options.rb +23 -0
- data/lib/listen/queue_optimizer.rb +23 -13
- data/lib/listen/record.rb +98 -21
- data/lib/listen/silencer.rb +21 -40
- data/lib/listen/tcp.rb +0 -0
- data/lib/listen/tcp/broadcaster.rb +0 -0
- data/lib/listen/tcp/message.rb +0 -0
- data/lib/listen/version.rb +1 -1
- data/listen.gemspec +0 -0
- data/spec/acceptance/listen_spec.rb +0 -0
- data/spec/acceptance/tcp_spec.rb +0 -0
- data/spec/lib/listen/adapter/base_spec.rb +17 -16
- data/spec/lib/listen/adapter/bsd_spec.rb +0 -0
- data/spec/lib/listen/adapter/darwin_spec.rb +11 -4
- data/spec/lib/listen/adapter/linux_spec.rb +20 -29
- data/spec/lib/listen/adapter/polling_spec.rb +15 -13
- data/spec/lib/listen/adapter/tcp_spec.rb +6 -3
- data/spec/lib/listen/adapter/windows_spec.rb +0 -0
- data/spec/lib/listen/adapter_spec.rb +0 -0
- data/spec/lib/listen/change_spec.rb +21 -27
- data/spec/lib/listen/directory_spec.rb +60 -42
- data/spec/lib/listen/file_spec.rb +16 -20
- data/spec/lib/listen/listener_spec.rb +136 -99
- data/spec/lib/listen/record_spec.rb +205 -62
- data/spec/lib/listen/silencer_spec.rb +44 -114
- data/spec/lib/listen/tcp/broadcaster_spec.rb +0 -0
- data/spec/lib/listen/tcp/listener_spec.rb +8 -5
- data/spec/lib/listen/tcp/message_spec.rb +0 -0
- data/spec/lib/listen_spec.rb +0 -0
- data/spec/spec_helper.rb +0 -0
- data/spec/support/acceptance_helper.rb +15 -4
- data/spec/support/fixtures_helper.rb +0 -0
- data/spec/support/platform_helper.rb +0 -0
- metadata +3 -2
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
include Listen
|
|
4
|
+
|
|
5
|
+
describe Listener do
|
|
4
6
|
subject { described_class.new(options) }
|
|
5
7
|
let(:options) { {} }
|
|
6
|
-
let(:registry) { instance_double(Celluloid::Registry
|
|
8
|
+
let(:registry) { instance_double(Celluloid::Registry) }
|
|
7
9
|
|
|
8
10
|
let(:supervisor) do
|
|
9
11
|
instance_double(Celluloid::SupervisionGroup, add: true, pool: true)
|
|
10
12
|
end
|
|
11
13
|
|
|
12
|
-
let(:record) { instance_double(
|
|
13
|
-
let(:silencer) { instance_double(
|
|
14
|
-
let(:adapter) { instance_double(
|
|
14
|
+
let(:record) { instance_double(Record, terminate: true, build: true) }
|
|
15
|
+
let(:silencer) { instance_double(Silencer, configure: nil) }
|
|
16
|
+
let(:adapter) { instance_double(Adapter::Base, start: nil) }
|
|
17
|
+
|
|
15
18
|
before do
|
|
19
|
+
allow(Listen::Silencer).to receive(:new) { silencer }
|
|
20
|
+
|
|
16
21
|
allow(Celluloid::Registry).to receive(:new) { registry }
|
|
17
22
|
allow(Celluloid::SupervisionGroup).to receive(:run!) { supervisor }
|
|
18
|
-
allow(registry).to receive(:[]).with(:silencer) { silencer }
|
|
19
23
|
allow(registry).to receive(:[]).with(:adapter) { adapter }
|
|
20
24
|
allow(registry).to receive(:[]).with(:record) { record }
|
|
21
25
|
end
|
|
@@ -75,31 +79,25 @@ describe Listen::Listener do
|
|
|
75
79
|
allow(silencer).to receive(:silenced?) { false }
|
|
76
80
|
end
|
|
77
81
|
|
|
78
|
-
it 'registers silencer' do
|
|
79
|
-
expect(supervisor).to receive(:add).
|
|
80
|
-
with(Listen::Silencer, as: :silencer, args: subject)
|
|
81
|
-
|
|
82
|
-
subject.start
|
|
83
|
-
end
|
|
84
|
-
|
|
85
82
|
it 'supervises change_pool' do
|
|
86
83
|
expect(supervisor).to receive(:pool).
|
|
87
|
-
with(
|
|
84
|
+
with(Change, as: :change_pool, args: subject)
|
|
88
85
|
|
|
89
86
|
subject.start
|
|
90
87
|
end
|
|
91
88
|
|
|
92
89
|
it 'supervises adaper' do
|
|
93
|
-
allow(
|
|
90
|
+
allow(Adapter).to receive(:select) { Adapter::Polling }
|
|
91
|
+
options = [mq: subject, directories: []]
|
|
94
92
|
expect(supervisor).to receive(:add).
|
|
95
|
-
with(
|
|
93
|
+
with(Adapter::Polling, as: :adapter, args: options)
|
|
96
94
|
|
|
97
95
|
subject.start
|
|
98
96
|
end
|
|
99
97
|
|
|
100
98
|
it 'supervises record' do
|
|
101
99
|
expect(supervisor).to receive(:add).
|
|
102
|
-
with(
|
|
100
|
+
with(Record, as: :record, args: subject)
|
|
103
101
|
|
|
104
102
|
subject.start
|
|
105
103
|
end
|
|
@@ -122,11 +120,14 @@ describe Listen::Listener do
|
|
|
122
120
|
it 'calls block on changes' do
|
|
123
121
|
foo = instance_double(Pathname, to_s: 'foo', exist?: true)
|
|
124
122
|
|
|
123
|
+
dir = instance_double(Pathname)
|
|
124
|
+
allow(dir).to receive(:+).with('foo') { foo }
|
|
125
|
+
|
|
125
126
|
block_stub = instance_double(Proc)
|
|
126
127
|
subject.block = block_stub
|
|
127
128
|
expect(block_stub).to receive(:call).with(['foo'], [], [])
|
|
128
129
|
subject.start
|
|
129
|
-
subject.queue(:file, :modified, foo)
|
|
130
|
+
subject.queue(:file, :modified, dir, 'foo')
|
|
130
131
|
sleep 0.25
|
|
131
132
|
end
|
|
132
133
|
end
|
|
@@ -199,20 +200,11 @@ describe Listen::Listener do
|
|
|
199
200
|
end
|
|
200
201
|
|
|
201
202
|
describe '#ignore' do
|
|
202
|
-
let(:new_silencer) { instance_double(Listen::Silencer) }
|
|
203
|
-
before { allow(Celluloid::Actor).to receive(:[]=) }
|
|
204
|
-
|
|
205
|
-
it 'resets silencer actor' do
|
|
206
|
-
expect(Listen::Silencer).to receive(:new).with(subject) { new_silencer }
|
|
207
|
-
expect(registry).to receive(:[]=).with(:silencer, new_silencer)
|
|
208
|
-
subject.ignore(/foo/)
|
|
209
|
-
end
|
|
210
|
-
|
|
211
203
|
context 'with existing ignore options' do
|
|
212
204
|
let(:options) { { ignore: /bar/ } }
|
|
213
205
|
|
|
214
206
|
it 'adds up to existing ignore options' do
|
|
215
|
-
expect(
|
|
207
|
+
expect(silencer).to receive(:configure).with(options)
|
|
216
208
|
subject.ignore(/foo/)
|
|
217
209
|
expect(subject.options).to include(ignore: [/bar/, /foo/])
|
|
218
210
|
end
|
|
@@ -222,7 +214,7 @@ describe Listen::Listener do
|
|
|
222
214
|
let(:options) { { ignore: [/bar/] } }
|
|
223
215
|
|
|
224
216
|
it 'adds up to existing ignore options' do
|
|
225
|
-
expect(
|
|
217
|
+
expect(silencer).to receive(:configure).with(options)
|
|
226
218
|
subject.ignore(/foo/)
|
|
227
219
|
expect(subject.options).to include(ignore: [[/bar/], /foo/])
|
|
228
220
|
end
|
|
@@ -230,21 +222,20 @@ describe Listen::Listener do
|
|
|
230
222
|
end
|
|
231
223
|
|
|
232
224
|
describe '#ignore!' do
|
|
233
|
-
|
|
234
|
-
|
|
225
|
+
context 'with no existing options' do
|
|
226
|
+
let(:options) { {} }
|
|
235
227
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
expect(subject.options).to include(ignore!: /foo/)
|
|
228
|
+
it 'sets options' do
|
|
229
|
+
expect(silencer).to receive(:configure).with(options)
|
|
230
|
+
subject
|
|
231
|
+
end
|
|
241
232
|
end
|
|
242
233
|
|
|
243
234
|
context 'with existing ignore! options' do
|
|
244
235
|
let(:options) { { ignore!: /bar/ } }
|
|
245
236
|
|
|
246
237
|
it 'overwrites existing ignore options' do
|
|
247
|
-
expect(
|
|
238
|
+
expect(silencer).to receive(:configure).with(options)
|
|
248
239
|
subject.ignore!([/foo/])
|
|
249
240
|
expect(subject.options).to include(ignore!: [/foo/])
|
|
250
241
|
end
|
|
@@ -254,7 +245,7 @@ describe Listen::Listener do
|
|
|
254
245
|
let(:options) { { ignore: /bar/ } }
|
|
255
246
|
|
|
256
247
|
it 'deletes ignore options' do
|
|
257
|
-
expect(
|
|
248
|
+
expect(silencer).to receive(:configure).with(options)
|
|
258
249
|
subject.ignore!([/foo/])
|
|
259
250
|
expect(subject.options).to_not include(ignore: /bar/)
|
|
260
251
|
end
|
|
@@ -262,20 +253,11 @@ describe Listen::Listener do
|
|
|
262
253
|
end
|
|
263
254
|
|
|
264
255
|
describe '#only' do
|
|
265
|
-
let(:new_silencer) { instance_double(Listen::Silencer) }
|
|
266
|
-
before { allow(Celluloid::Actor).to receive(:[]=) }
|
|
267
|
-
|
|
268
|
-
it 'resets silencer actor' do
|
|
269
|
-
expect(Listen::Silencer).to receive(:new).with(subject) { new_silencer }
|
|
270
|
-
expect(registry).to receive(:[]=).with(:silencer, new_silencer)
|
|
271
|
-
subject.only(/foo/)
|
|
272
|
-
end
|
|
273
|
-
|
|
274
256
|
context 'with existing only options' do
|
|
275
257
|
let(:options) { { only: /bar/ } }
|
|
276
258
|
|
|
277
259
|
it 'overwrites existing ignore options' do
|
|
278
|
-
expect(
|
|
260
|
+
expect(silencer).to receive(:configure).with(options)
|
|
279
261
|
subject.only([/foo/])
|
|
280
262
|
expect(subject.options).to include(only: [/foo/])
|
|
281
263
|
end
|
|
@@ -287,60 +269,69 @@ describe Listen::Listener do
|
|
|
287
269
|
allow(silencer).to receive(:silenced?) { false }
|
|
288
270
|
|
|
289
271
|
subject.block = proc do |modified, added, _|
|
|
290
|
-
expect(modified).to eql(['foo.txt'])
|
|
291
|
-
expect(added).to eql(['
|
|
272
|
+
expect(modified).to eql(['foo/bar.txt'])
|
|
273
|
+
expect(added).to eql(['foo/baz.txt'])
|
|
292
274
|
end
|
|
293
275
|
|
|
294
|
-
|
|
276
|
+
bar = instance_double(
|
|
295
277
|
Pathname,
|
|
296
|
-
to_s: 'foo.txt',
|
|
278
|
+
to_s: 'foo/bar.txt',
|
|
297
279
|
exist?: true,
|
|
298
280
|
directory?: false)
|
|
299
281
|
|
|
300
|
-
|
|
282
|
+
baz = instance_double(
|
|
301
283
|
Pathname,
|
|
302
|
-
to_s: '
|
|
284
|
+
to_s: 'foo/baz.txt',
|
|
303
285
|
exist?: true,
|
|
304
286
|
directory?: false)
|
|
305
287
|
|
|
288
|
+
dir = instance_double(Pathname)
|
|
289
|
+
expect(dir).to receive(:+).with('bar.txt') { bar }
|
|
290
|
+
expect(dir).to receive(:+).with('baz.txt') { baz }
|
|
291
|
+
|
|
306
292
|
subject.start
|
|
307
|
-
subject.queue(:file, :modified,
|
|
308
|
-
subject.queue(:file, :added,
|
|
293
|
+
subject.queue(:file, :modified, dir, 'bar.txt', {})
|
|
294
|
+
subject.queue(:file, :added, dir, 'baz.txt', {})
|
|
309
295
|
sleep 0.25
|
|
310
296
|
end
|
|
311
297
|
end
|
|
312
298
|
|
|
313
299
|
describe '_smoosh_changes' do
|
|
314
300
|
it 'recognizes rename from temp file' do
|
|
315
|
-
|
|
301
|
+
bar = instance_double(
|
|
316
302
|
Pathname,
|
|
317
|
-
to_s: '
|
|
303
|
+
to_s: 'bar',
|
|
318
304
|
exist?: true,
|
|
319
305
|
directory?: false)
|
|
320
306
|
|
|
307
|
+
foo = instance_double(Pathname, to_s: 'foo')
|
|
308
|
+
allow(foo).to receive(:+).with('bar') { bar }
|
|
309
|
+
|
|
321
310
|
changes = [
|
|
322
|
-
[:file, :modified,
|
|
323
|
-
[:file, :removed,
|
|
324
|
-
[:file, :added,
|
|
325
|
-
[:file, :modified,
|
|
311
|
+
[:file, :modified, foo, 'bar'],
|
|
312
|
+
[:file, :removed, foo, 'bar'],
|
|
313
|
+
[:file, :added, foo, 'bar'],
|
|
314
|
+
[:file, :modified, foo, 'bar']
|
|
326
315
|
]
|
|
327
316
|
allow(silencer).to receive(:silenced?) { false }
|
|
328
317
|
smooshed = subject.send :_smoosh_changes, changes
|
|
329
|
-
expect(smooshed).to eq(modified: ['
|
|
318
|
+
expect(smooshed).to eq(modified: ['bar'], added: [], removed: [])
|
|
330
319
|
end
|
|
331
320
|
|
|
332
|
-
it '
|
|
333
|
-
|
|
321
|
+
it 'ignores deleted temp file' do
|
|
322
|
+
bar = instance_double(
|
|
334
323
|
Pathname,
|
|
335
|
-
to_s: '
|
|
336
|
-
exist?: false
|
|
337
|
-
|
|
324
|
+
to_s: 'bar',
|
|
325
|
+
exist?: false)
|
|
326
|
+
|
|
327
|
+
foo = instance_double(Pathname, to_s: 'foo')
|
|
328
|
+
allow(foo).to receive(:+).with('bar') { bar }
|
|
338
329
|
|
|
339
330
|
changes = [
|
|
340
|
-
[:file, :added,
|
|
341
|
-
[:file, :modified,
|
|
342
|
-
[:file, :removed,
|
|
343
|
-
[:file, :modified,
|
|
331
|
+
[:file, :added, foo, 'bar'],
|
|
332
|
+
[:file, :modified, foo, 'bar'],
|
|
333
|
+
[:file, :removed, foo, 'bar'],
|
|
334
|
+
[:file, :modified, foo, 'bar']
|
|
344
335
|
]
|
|
345
336
|
allow(silencer).to receive(:silenced?) { false }
|
|
346
337
|
smooshed = subject.send :_smoosh_changes, changes
|
|
@@ -349,19 +340,21 @@ describe Listen::Listener do
|
|
|
349
340
|
|
|
350
341
|
it 'recognizes double move as modification' do
|
|
351
342
|
# e.g. "mv foo x && mv x foo" is like "touch foo"
|
|
352
|
-
|
|
343
|
+
bar = instance_double(
|
|
353
344
|
Pathname,
|
|
354
|
-
to_s: '
|
|
355
|
-
exist?: true
|
|
356
|
-
|
|
345
|
+
to_s: 'bar',
|
|
346
|
+
exist?: true)
|
|
347
|
+
|
|
348
|
+
dir = instance_double(Pathname, to_s: 'foo')
|
|
349
|
+
allow(dir).to receive(:+).with('bar') { bar }
|
|
357
350
|
|
|
358
351
|
changes = [
|
|
359
|
-
[:file, :removed,
|
|
360
|
-
[:file, :added,
|
|
352
|
+
[:file, :removed, dir, 'bar'],
|
|
353
|
+
[:file, :added, dir, 'bar']
|
|
361
354
|
]
|
|
362
355
|
allow(silencer).to receive(:silenced?) { false }
|
|
363
356
|
smooshed = subject.send :_smoosh_changes, changes
|
|
364
|
-
expect(smooshed).to eq(modified: ['
|
|
357
|
+
expect(smooshed).to eq(modified: ['bar'], added: [], removed: [])
|
|
365
358
|
end
|
|
366
359
|
|
|
367
360
|
context 'with cookie' do
|
|
@@ -370,11 +363,15 @@ describe Listen::Listener do
|
|
|
370
363
|
foo = instance_double(
|
|
371
364
|
Pathname,
|
|
372
365
|
to_s: 'foo',
|
|
373
|
-
exist?: true
|
|
374
|
-
|
|
366
|
+
exist?: true)
|
|
367
|
+
|
|
368
|
+
dir = instance_double(Pathname, to_s: 'foo')
|
|
369
|
+
allow(dir).to receive(:+).with('foo') { foo }
|
|
370
|
+
|
|
371
|
+
changes = [[:file, :moved_to, dir, 'foo', cookie: 4321]]
|
|
372
|
+
expect(silencer).to receive(:silenced?).
|
|
373
|
+
with(Pathname('foo'), :file) { false }
|
|
375
374
|
|
|
376
|
-
changes = [[:file, :moved_to, foo, cookie: 4321]]
|
|
377
|
-
expect(silencer).to receive(:silenced?).with(foo, :file) { false }
|
|
378
375
|
smooshed = subject.send :_smoosh_changes, changes
|
|
379
376
|
expect(smooshed).to eq(modified: [], added: ['foo'], removed: [])
|
|
380
377
|
end
|
|
@@ -392,15 +389,21 @@ describe Listen::Listener do
|
|
|
392
389
|
exist?: true,
|
|
393
390
|
directory?: false)
|
|
394
391
|
|
|
392
|
+
dir = instance_double(Pathname)
|
|
393
|
+
allow(dir).to receive(:+).with('foo') { foo }
|
|
394
|
+
allow(dir).to receive(:+).with('bar') { bar }
|
|
395
|
+
|
|
395
396
|
changes = [
|
|
396
|
-
[:file, :moved_from, foo
|
|
397
|
-
[:file, :moved_to, bar, cookie: 4321]
|
|
397
|
+
[:file, :moved_from, dir, 'foo', cookie: 4321],
|
|
398
|
+
[:file, :moved_to, dir, 'bar', cookie: 4321]
|
|
398
399
|
]
|
|
399
400
|
|
|
400
401
|
expect(silencer).to receive(:silenced?).
|
|
401
|
-
twice.with(foo, :file) { false }
|
|
402
|
+
twice.with(Pathname('foo'), :file) { false }
|
|
403
|
+
|
|
404
|
+
expect(silencer).to receive(:silenced?).
|
|
405
|
+
with(Pathname('bar'), :file) { false }
|
|
402
406
|
|
|
403
|
-
expect(silencer).to receive(:silenced?).with(bar, :file) { false }
|
|
404
407
|
smooshed = subject.send :_smoosh_changes, changes
|
|
405
408
|
expect(smooshed).to eq(modified: [], added: ['bar'], removed: [])
|
|
406
409
|
end
|
|
@@ -410,7 +413,7 @@ describe Listen::Listener do
|
|
|
410
413
|
|
|
411
414
|
ignored = instance_double(
|
|
412
415
|
Pathname,
|
|
413
|
-
to_s: '
|
|
416
|
+
to_s: 'ignored',
|
|
414
417
|
exist?: true,
|
|
415
418
|
directory?: false)
|
|
416
419
|
|
|
@@ -420,26 +423,60 @@ describe Listen::Listener do
|
|
|
420
423
|
exist?: true,
|
|
421
424
|
directory?: false)
|
|
422
425
|
|
|
426
|
+
dir = instance_double(Pathname)
|
|
427
|
+
allow(dir).to receive(:+).with('foo') { foo }
|
|
428
|
+
allow(dir).to receive(:+).with('ignored') { ignored }
|
|
429
|
+
|
|
423
430
|
changes = [
|
|
424
|
-
[:file, :moved_from, ignored, cookie: 4321],
|
|
425
|
-
[:file, :moved_to, foo , cookie: 4321]
|
|
431
|
+
[:file, :moved_from, dir, 'ignored', cookie: 4321],
|
|
432
|
+
[:file, :moved_to, dir, 'foo' , cookie: 4321]
|
|
426
433
|
]
|
|
427
|
-
|
|
428
|
-
expect(silencer).to receive(:silenced?).
|
|
434
|
+
|
|
435
|
+
expect(silencer).to receive(:silenced?).
|
|
436
|
+
with(Pathname('ignored'), :file) { true }
|
|
437
|
+
|
|
438
|
+
expect(silencer).to receive(:silenced?).
|
|
439
|
+
with(Pathname('foo'), :file) { false }
|
|
440
|
+
|
|
429
441
|
smooshed = subject.send :_smoosh_changes, changes
|
|
430
442
|
expect(smooshed).to eq(modified: ['foo'], added: [], removed: [])
|
|
431
443
|
end
|
|
432
444
|
end
|
|
433
445
|
|
|
434
446
|
context 'with no cookie' do
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
447
|
+
context 'with ignored file' do
|
|
448
|
+
let(:dir) { instance_double(Pathname) }
|
|
449
|
+
let(:ignored) { instance_double(Pathname, to_s: 'foo', exist?: true) }
|
|
450
|
+
|
|
451
|
+
before do
|
|
452
|
+
expect(silencer).to receive(:silenced?).
|
|
453
|
+
with(Pathname('ignored'), :file) { true }
|
|
454
|
+
|
|
455
|
+
allow(dir).to receive(:+).with('ignored') { ignored }
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
it 'recognizes properly ignores files' do
|
|
459
|
+
changes = [[:file, :modified, dir, 'ignored']]
|
|
460
|
+
smooshed = subject.send :_smoosh_changes, changes
|
|
461
|
+
expect(smooshed).to eq(modified: [], added: [], removed: [])
|
|
462
|
+
end
|
|
442
463
|
end
|
|
443
464
|
end
|
|
444
465
|
end
|
|
466
|
+
|
|
467
|
+
context 'when listener is stopped' do
|
|
468
|
+
|
|
469
|
+
before do
|
|
470
|
+
allow(registry).to receive(:[]).with(:change_pool) { nil }
|
|
471
|
+
subject.stop
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
let(:dir) { instance_double(Pathname) }
|
|
475
|
+
|
|
476
|
+
it 'queuing does not crash when no worker is available' do
|
|
477
|
+
expect do
|
|
478
|
+
subject.send(:_queue_raw_change, :dir, dir, 'path', recursive: true)
|
|
479
|
+
end.to_not raise_error
|
|
480
|
+
end
|
|
481
|
+
end
|
|
445
482
|
end
|
|
@@ -8,127 +8,270 @@ describe Listen::Record do
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
let(:record) { Listen::Record.new(listener) }
|
|
11
|
-
let(:
|
|
11
|
+
let(:dir) { instance_double(Pathname, to_s: '/dir') }
|
|
12
12
|
|
|
13
|
-
describe '#
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
describe '#update_file' do
|
|
14
|
+
context 'with path in watched dir' do
|
|
15
|
+
it 'sets path by spliting dirname and basename' do
|
|
16
|
+
record.update_file(dir, 'file.rb', mtime: 1.1)
|
|
17
|
+
expect(record.paths['/dir']).to eq('file.rb' => { mtime: 1.1 })
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'sets path and keeps old data not overwritten' do
|
|
21
|
+
record.update_file(dir, 'file.rb', foo: 1, bar: 2)
|
|
22
|
+
record.update_file(dir, 'file.rb', foo: 3)
|
|
23
|
+
watched_dir = record.paths['/dir']
|
|
24
|
+
expect(watched_dir).to eq('file.rb' => { foo: 3, bar: 2 })
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context 'with subdir path' do
|
|
29
|
+
it 'sets path by spliting dirname and basename' do
|
|
30
|
+
record.update_file(dir, 'path/file.rb', mtime: 1.1)
|
|
31
|
+
expect(record.paths['/dir']['path']).to eq('file.rb' => { mtime: 1.1 })
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'sets path and keeps old data not overwritten' do
|
|
35
|
+
record.update_file(dir, 'path/file.rb', foo: 1, bar: 2)
|
|
36
|
+
record.update_file(dir, 'path/file.rb', foo: 3)
|
|
37
|
+
file_data = record.paths['/dir']['path']['file.rb']
|
|
38
|
+
expect(file_data).to eq(foo: 3, bar: 2)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe '#add_dir' do
|
|
44
|
+
it 'sets itself when .' do
|
|
45
|
+
record.add_dir(dir, '.')
|
|
46
|
+
expect(record.paths['/dir']).to eq({})
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'sets itself when nil' do
|
|
50
|
+
record.add_dir(dir, nil)
|
|
51
|
+
expect(record.paths['/dir']).to eq({})
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'sets itself when empty' do
|
|
55
|
+
record.add_dir(dir, '')
|
|
56
|
+
expect(record.paths['/dir']).to eq({})
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'correctly sets new directory data' do
|
|
60
|
+
record.add_dir(dir, 'path/subdir')
|
|
61
|
+
expect(record.paths['/dir']).to eq('path/subdir' => {})
|
|
17
62
|
end
|
|
18
63
|
|
|
19
64
|
it 'sets path and keeps old data not overwritten' do
|
|
20
|
-
record.
|
|
21
|
-
record.
|
|
22
|
-
|
|
23
|
-
|
|
65
|
+
record.add_dir(dir, 'path/subdir')
|
|
66
|
+
record.update_file(dir, 'path/subdir/file.rb', mtime: 1.1)
|
|
67
|
+
record.add_dir(dir, 'path/subdir')
|
|
68
|
+
record.update_file(dir, 'path/subdir/file2.rb', mtime: 1.2)
|
|
69
|
+
record.add_dir(dir, 'path/subdir')
|
|
70
|
+
|
|
71
|
+
watched = record.paths['/dir']
|
|
72
|
+
expect(watched.keys).to eq ['path/subdir']
|
|
73
|
+
expect(watched['path/subdir'].keys).to eq %w(file.rb file2.rb)
|
|
74
|
+
|
|
75
|
+
subdir = watched['path/subdir']
|
|
76
|
+
expect(subdir['file.rb']).to eq(mtime: 1.1)
|
|
77
|
+
expect(subdir['file2.rb']).to eq(mtime: 1.2)
|
|
24
78
|
end
|
|
25
79
|
end
|
|
26
80
|
|
|
27
81
|
describe '#unset_path' do
|
|
28
82
|
context 'path is present' do
|
|
29
|
-
before { record.
|
|
83
|
+
before { record.update_file(dir, 'path/file.rb', mtime: 1.1) }
|
|
30
84
|
|
|
31
85
|
it 'unsets path' do
|
|
32
|
-
record.unset_path(path)
|
|
33
|
-
expect(record.paths).to eq('/dir
|
|
86
|
+
record.unset_path(dir, 'path/file.rb')
|
|
87
|
+
expect(record.paths).to eq('/dir' => { 'path' => {} })
|
|
34
88
|
end
|
|
35
89
|
end
|
|
36
90
|
|
|
37
91
|
context 'path not present' do
|
|
38
92
|
it 'unsets path' do
|
|
39
|
-
record.unset_path(path)
|
|
40
|
-
expect(record.paths).to eq('/dir
|
|
93
|
+
record.unset_path(dir, 'path/file.rb')
|
|
94
|
+
expect(record.paths).to eq('/dir' => { 'path' => {} })
|
|
41
95
|
end
|
|
42
96
|
end
|
|
43
97
|
end
|
|
44
98
|
|
|
45
99
|
describe '#file_data' do
|
|
46
|
-
context 'path
|
|
47
|
-
|
|
100
|
+
context 'with path in watched dir' do
|
|
101
|
+
context 'when path is present' do
|
|
102
|
+
before { record.update_file(dir, 'file.rb', mtime: 1.1) }
|
|
48
103
|
|
|
49
|
-
|
|
50
|
-
|
|
104
|
+
it 'returns file data' do
|
|
105
|
+
expect(record.file_data(dir, 'file.rb')).to eq(mtime: 1.1)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
context 'path not present' do
|
|
110
|
+
it 'return empty hash' do
|
|
111
|
+
expect(record.file_data(dir, 'file.rb')).to be_empty
|
|
112
|
+
end
|
|
51
113
|
end
|
|
52
114
|
end
|
|
53
115
|
|
|
54
|
-
context 'path
|
|
55
|
-
|
|
56
|
-
|
|
116
|
+
context 'with path in subdir' do
|
|
117
|
+
context 'when path is present' do
|
|
118
|
+
before { record.update_file(dir, 'path/file.rb', mtime: 1.1) }
|
|
119
|
+
|
|
120
|
+
it 'returns file data' do
|
|
121
|
+
expected = { mtime: 1.1 }
|
|
122
|
+
expect(record.file_data(dir, 'path/file.rb')).to eq expected
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
context 'path not present' do
|
|
127
|
+
it 'return empty hash' do
|
|
128
|
+
expect(record.file_data(dir, 'path/file.rb')).to be_empty
|
|
129
|
+
end
|
|
57
130
|
end
|
|
58
131
|
end
|
|
59
132
|
end
|
|
60
133
|
|
|
61
134
|
describe '#dir_entries' do
|
|
62
|
-
context '
|
|
63
|
-
|
|
135
|
+
context 'in watched dir' do
|
|
136
|
+
subject { record.dir_entries(dir, '.') }
|
|
137
|
+
|
|
138
|
+
context 'with no entries' do
|
|
139
|
+
it { should be_empty }
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
context 'with file.rb in record' do
|
|
143
|
+
before { record.update_file(dir, 'file.rb', mtime: 1.1) }
|
|
144
|
+
it { should eq('file.rb' => { mtime: 1.1 }) }
|
|
145
|
+
context 'when file is removed' do
|
|
146
|
+
before { record.update_file(dir, 'file.rb', mtime: 1.1) }
|
|
147
|
+
end
|
|
148
|
+
end
|
|
64
149
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
150
|
+
context 'with subdir/file.rb in record' do
|
|
151
|
+
before { record.update_file(dir, 'subdir/file.rb', mtime: 1.1) }
|
|
152
|
+
it { should eq('subdir' => {}) }
|
|
68
153
|
end
|
|
69
154
|
end
|
|
70
155
|
|
|
71
|
-
context '
|
|
72
|
-
|
|
73
|
-
|
|
156
|
+
context 'in subdir /path' do
|
|
157
|
+
subject { record.dir_entries(dir, 'path') }
|
|
158
|
+
|
|
159
|
+
context 'with no entries' do
|
|
160
|
+
it { should be_empty }
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
context 'with path/file.rb already in record' do
|
|
164
|
+
before { record.update_file(dir, 'path/file.rb', mtime: 1.1) }
|
|
165
|
+
it { should eq('file.rb' => { mtime: 1.1 }) }
|
|
74
166
|
end
|
|
75
167
|
end
|
|
76
168
|
end
|
|
77
169
|
|
|
78
170
|
describe '#build' do
|
|
79
|
-
let(:
|
|
171
|
+
let(:dir1) { Pathname('/dir1') }
|
|
172
|
+
let(:dir2) { Pathname('/dir2') }
|
|
80
173
|
|
|
81
|
-
let(:
|
|
82
|
-
instance_double(Listen::Change, change: nil, terminate: true)
|
|
83
|
-
end
|
|
174
|
+
let(:directories) { [dir1, dir2] }
|
|
84
175
|
|
|
85
176
|
before do
|
|
86
177
|
allow(listener).to receive(:directories) { directories }
|
|
87
|
-
|
|
178
|
+
|
|
179
|
+
allow(::File).to receive(:lstat) do |path|
|
|
180
|
+
fail "::File.lstat stub called with: #{path.inspect}"
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
allow(::Dir).to receive(:entries) do |path|
|
|
184
|
+
fail "::Dir.entries stub called with: #{path.inspect}"
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
allow(::Dir).to receive(:exist?) do |path|
|
|
188
|
+
fail "::Dir.exist? stub called with: #{path.inspect}"
|
|
189
|
+
end
|
|
88
190
|
end
|
|
89
191
|
|
|
90
192
|
it 're-inits paths' do
|
|
91
|
-
|
|
92
|
-
record.build
|
|
93
|
-
expect(record.file_data(path)).to be_empty
|
|
94
|
-
end
|
|
193
|
+
allow(::Dir).to receive(:entries) { [] }
|
|
95
194
|
|
|
96
|
-
|
|
97
|
-
expect(actor).to receive(:change).
|
|
98
|
-
with(:dir, 'dir_path', recursive: true, silence: true, build: true)
|
|
195
|
+
record.update_file(dir, 'path/file.rb', mtime: 1.1)
|
|
99
196
|
record.build
|
|
197
|
+
expect(record.paths).to eq('/dir1' => {}, '/dir2' => {})
|
|
198
|
+
expect(record.file_data(dir, 'path/file.rb')).to be_empty
|
|
100
199
|
end
|
|
101
|
-
end
|
|
102
200
|
|
|
103
|
-
|
|
104
|
-
let(:
|
|
201
|
+
let(:foo_stat) { instance_double(::File::Stat, mtime: 1.0, mode: 0644) }
|
|
202
|
+
let(:bar_stat) { instance_double(::File::Stat, mtime: 2.3, mode: 0755) }
|
|
105
203
|
|
|
106
|
-
|
|
107
|
-
instance_double(Listen::Change, change: nil, terminate: true)
|
|
108
|
-
end
|
|
204
|
+
context 'with no subdirs' do
|
|
109
205
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
206
|
+
before do
|
|
207
|
+
expect(::Dir).to receive(:entries).with('/dir1/.') { %w(foo bar) }
|
|
208
|
+
expect(::Dir).to receive(:exist?).with('/dir1/./foo') { false }
|
|
209
|
+
expect(::Dir).to receive(:exist?).with('/dir1/./bar') { false }
|
|
210
|
+
expect(::File).to receive(:lstat).with('/dir1/./foo') { foo_stat }
|
|
211
|
+
expect(::File).to receive(:lstat).with('/dir1/./bar') { bar_stat }
|
|
212
|
+
|
|
213
|
+
expect(::Dir).to receive(:entries).with('/dir2/.') { [] }
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
it 'builds record' do
|
|
217
|
+
record.build
|
|
218
|
+
expect(record.paths.keys).to eq %w( /dir1 /dir2 )
|
|
219
|
+
expect(record.paths['/dir1']).
|
|
220
|
+
to eq(
|
|
221
|
+
'foo' => { mtime: 1.0, mode: 0644 },
|
|
222
|
+
'bar' => { mtime: 2.3, mode: 0755 })
|
|
223
|
+
end
|
|
113
224
|
end
|
|
114
225
|
|
|
115
|
-
|
|
116
|
-
|
|
226
|
+
context 'with subdir containing files' do
|
|
227
|
+
before do
|
|
228
|
+
expect(::Dir).to receive(:entries).with('/dir1/.') { %w(foo) }
|
|
229
|
+
expect(::Dir).to receive(:exist?).with('/dir1/./foo') { true }
|
|
117
230
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
231
|
+
expect(::Dir).to receive(:entries).with('/dir1/foo') { %w(bar) }
|
|
232
|
+
|
|
233
|
+
expect(::Dir).to receive(:exist?).with('/dir1/foo/bar') { false }
|
|
234
|
+
expect(::File).to receive(:lstat).with('/dir1/foo/bar') { bar_stat }
|
|
235
|
+
|
|
236
|
+
expect(::Dir).to receive(:entries).with('/dir2/.') { [] }
|
|
123
237
|
end
|
|
124
238
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
239
|
+
it 'builds record' do
|
|
240
|
+
record.build
|
|
241
|
+
expect(record.paths.keys).to eq %w( /dir1 /dir2 )
|
|
242
|
+
expect(record.paths['/dir1']).
|
|
243
|
+
to eq('foo' => { 'bar' => { mtime: 2.3, mode: 0755 } })
|
|
244
|
+
expect(record.paths['/dir2']).to eq({})
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
context 'with subdir containing dirs' do
|
|
249
|
+
before do
|
|
250
|
+
expect(::Dir).to receive(:entries).with('/dir1/.') { %w(foo) }
|
|
251
|
+
expect(::Dir).to receive(:exist?).with('/dir1/./foo') { true }
|
|
252
|
+
|
|
253
|
+
expect(::Dir).to receive(:entries).with('/dir1/foo') { %w(bar baz) }
|
|
128
254
|
|
|
129
|
-
|
|
255
|
+
expect(::Dir).to receive(:exist?).with('/dir1/foo/bar') { true }
|
|
256
|
+
expect(::Dir).to receive(:entries).with('/dir1/foo/bar') { [] }
|
|
130
257
|
|
|
131
|
-
|
|
258
|
+
expect(::Dir).to receive(:exist?).with('/dir1/foo/baz') { true }
|
|
259
|
+
expect(::Dir).to receive(:entries).with('/dir1/foo/baz') { [] }
|
|
260
|
+
|
|
261
|
+
expect(::Dir).to receive(:entries).with('/dir2/.') { [] }
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
it 'builds record' do
|
|
265
|
+
record.build
|
|
266
|
+
expect(record.paths.keys).to eq %w( /dir1 /dir2 )
|
|
267
|
+
expect(record.paths['/dir1']).
|
|
268
|
+
to eq(
|
|
269
|
+
'foo' => {},
|
|
270
|
+
'foo/bar' => {},
|
|
271
|
+
'foo/baz' => {},
|
|
272
|
+
)
|
|
273
|
+
expect(record.paths['/dir2']).to eq({})
|
|
274
|
+
end
|
|
132
275
|
end
|
|
133
276
|
end
|
|
134
277
|
end
|