listen 2.7.5 → 2.7.6

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -0
  3. data/.rspec +0 -0
  4. data/.rubocop.yml +0 -0
  5. data/.travis.yml +0 -1
  6. data/.yardopts +0 -0
  7. data/CHANGELOG.md +0 -0
  8. data/CONTRIBUTING.md +0 -0
  9. data/Gemfile +25 -4
  10. data/Guardfile +0 -0
  11. data/LICENSE.txt +0 -0
  12. data/README.md +18 -10
  13. data/Rakefile +0 -0
  14. data/lib/listen.rb +2 -4
  15. data/lib/listen/adapter.rb +13 -4
  16. data/lib/listen/adapter/base.rb +33 -16
  17. data/lib/listen/adapter/bsd.rb +21 -38
  18. data/lib/listen/adapter/darwin.rb +17 -25
  19. data/lib/listen/adapter/linux.rb +34 -52
  20. data/lib/listen/adapter/polling.rb +9 -25
  21. data/lib/listen/adapter/tcp.rb +27 -14
  22. data/lib/listen/adapter/windows.rb +67 -23
  23. data/lib/listen/change.rb +26 -23
  24. data/lib/listen/cli.rb +0 -0
  25. data/lib/listen/directory.rb +47 -58
  26. data/lib/listen/file.rb +66 -101
  27. data/lib/listen/listener.rb +214 -155
  28. data/lib/listen/queue_optimizer.rb +104 -0
  29. data/lib/listen/record.rb +15 -5
  30. data/lib/listen/silencer.rb +14 -10
  31. data/lib/listen/tcp.rb +0 -1
  32. data/lib/listen/tcp/broadcaster.rb +31 -26
  33. data/lib/listen/tcp/message.rb +2 -2
  34. data/lib/listen/version.rb +1 -1
  35. data/listen.gemspec +1 -1
  36. data/spec/acceptance/listen_spec.rb +151 -239
  37. data/spec/acceptance/tcp_spec.rb +125 -134
  38. data/spec/lib/listen/adapter/base_spec.rb +13 -30
  39. data/spec/lib/listen/adapter/bsd_spec.rb +7 -35
  40. data/spec/lib/listen/adapter/darwin_spec.rb +18 -30
  41. data/spec/lib/listen/adapter/linux_spec.rb +49 -55
  42. data/spec/lib/listen/adapter/polling_spec.rb +20 -35
  43. data/spec/lib/listen/adapter/tcp_spec.rb +25 -27
  44. data/spec/lib/listen/adapter/windows_spec.rb +7 -33
  45. data/spec/lib/listen/adapter_spec.rb +10 -10
  46. data/spec/lib/listen/change_spec.rb +55 -57
  47. data/spec/lib/listen/directory_spec.rb +105 -155
  48. data/spec/lib/listen/file_spec.rb +186 -73
  49. data/spec/lib/listen/listener_spec.rb +233 -216
  50. data/spec/lib/listen/record_spec.rb +60 -22
  51. data/spec/lib/listen/silencer_spec.rb +48 -75
  52. data/spec/lib/listen/tcp/broadcaster_spec.rb +78 -69
  53. data/spec/lib/listen/tcp/listener_spec.rb +28 -71
  54. data/spec/lib/listen/tcp/message_spec.rb +48 -14
  55. data/spec/lib/listen_spec.rb +3 -3
  56. data/spec/spec_helper.rb +6 -3
  57. data/spec/support/acceptance_helper.rb +250 -31
  58. data/spec/support/fixtures_helper.rb +6 -4
  59. data/spec/support/platform_helper.rb +2 -2
  60. metadata +5 -5
  61. data/lib/listen/tcp/listener.rb +0 -108
@@ -1,145 +1,136 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Listen::TCP do
3
+ describe Listen::Listener do
4
4
 
5
5
  let(:port) { 4000 }
6
-
7
- let(:broadcaster) { Listen.to(Dir.pwd, forward_to: port) }
8
- let(:recipient) { Listen.on(port) }
9
- let(:callback) do
10
- lambda do |modified, added, removed|
11
- add_changes(:modified, modified)
12
- add_changes(:added, added)
13
- add_changes(:removed, removed)
14
- end
15
- end
6
+ let(:broadcast_options) { { forward_to: port } }
16
7
  let(:paths) { Pathname.new(Dir.pwd) }
17
8
 
18
9
  around { |example| fixtures { example.run } }
19
10
 
20
- before do
21
- broadcaster.start
22
- end
23
-
24
- context 'when broadcaster' do
25
- before do
26
- broadcaster.block = callback
27
- end
28
-
29
- it 'still handles local changes' do
30
- expect(listen do
31
- touch 'file.rb'
32
- end).to eq(
33
- modified: [],
34
- added: ['file.rb'],
35
- removed: []
36
- )
37
- end
38
-
39
- it 'may be paused and unpaused' do
40
- broadcaster.pause
41
-
42
- expect(listen do
43
- touch 'file.rb'
44
- end).to eq(
45
- modified: [],
46
- added: [],
47
- removed: []
48
- )
49
-
50
- broadcaster.unpause
51
-
52
- expect(listen do
53
- touch 'file.rb'
54
- end).to eq(
55
- modified: ['file.rb'],
56
- added: [],
57
- removed: []
58
- )
59
- end
60
-
61
- it 'may be stopped and restarted' do
62
- broadcaster.stop
63
-
64
- expect(listen do
65
- touch 'file.rb'
66
- end).to eq(
67
- modified: [],
68
- added: [],
69
- removed: []
70
- )
71
-
72
- broadcaster.start
73
-
74
- expect(listen do
75
- touch 'file.rb'
76
- end).to eq(
77
- modified: ['file.rb'],
78
- added: [],
79
- removed: []
80
- )
11
+ modes = if !windows? || Celluloid::VERSION > '0.15.2'
12
+ [:recipient, :broadcaster]
13
+ else
14
+ [:broadcaster]
15
+ end
16
+
17
+ modes.each do |mode|
18
+ context "when #{mode}" do
19
+ if mode == :broadcaster
20
+ subject { setup_listener(broadcast_options, :track_changes) }
21
+ before { subject.listener.start }
22
+ after { subject.listener.stop }
23
+ else
24
+ subject { setup_recipient(port, :track_changes) }
25
+ let(:broadcaster) { setup_listener(broadcast_options) }
26
+
27
+ before do
28
+ broadcaster.listener.start
29
+ # Travis on OSX is too slow
30
+ subject.lag = 1.2
31
+ subject.listener.start
32
+ end
33
+ after do
34
+ broadcaster.listener.stop
35
+ subject.listener.stop
36
+ end
37
+ end
38
+
39
+ it { should process_addition_of('file.rb') }
40
+
41
+ context 'when paused' do
42
+ before { subject.listener.pause }
43
+
44
+ context 'with no queued changes' do
45
+ it { should_not process_addition_of('file.rb') }
46
+
47
+ context 'when unpaused' do
48
+ before { subject.listener.unpause }
49
+ it { should process_addition_of('file.rb') }
50
+ end
51
+ end
52
+
53
+ context 'with queued addition' do
54
+ before { change_fs(:added, 'file.rb') }
55
+ it { should_not process_modification_of('file.rb') }
56
+
57
+ context 'when unpaused' do
58
+ before { subject.listener.unpause }
59
+ it { should process_queued_addition_of('file.rb') }
60
+ it { should process_modification_of('file.rb') }
61
+ end
62
+ end
63
+
64
+ context 'with queued modification' do
65
+ before do
66
+ change_fs(:added, 'file.rb')
67
+ change_fs(:modified, 'file.rb')
68
+ end
69
+
70
+ it { should_not process_queued_addition_of('file.rb') }
71
+ it { should_not process_queued_modification_of('file.rb') }
72
+
73
+ context 'when unpaused' do
74
+ before { subject.listener.unpause }
75
+ it { should process_queued_addition_of('file.rb') }
76
+
77
+ # NOTE: when adapter is 'local_fs?', the change optimizer
78
+ # (_squash_changes) reduces the "add+mod" into a single "add"
79
+ if mode == :broadcaster
80
+ # "optimizing" on local fs (broadcaster) will remove
81
+ # :modified from queue
82
+ it { should_not process_queued_modification_of('file.rb') }
83
+ else
84
+ # optimization skipped, because it's TCP, so we'll have both
85
+ # :modified and :added events for same file
86
+ it { should process_queued_modification_of('file.rb') }
87
+ end
88
+
89
+ it { should process_modification_of('file.rb') }
90
+ end
91
+ end
92
+ end
93
+
94
+ context 'when stopped' do
95
+ before { subject.listener.stop }
96
+
97
+ context 'with no queued changes' do
98
+ it { should_not process_addition_of('file.rb') }
99
+
100
+ context 'when started' do
101
+ before { subject.listener.start }
102
+ it { should process_addition_of('file.rb') }
103
+ end
104
+ end
105
+
106
+ context 'with queued addition' do
107
+ before { change_fs(:added, 'file.rb') }
108
+ it { should_not process_modification_of('file.rb') }
109
+
110
+ context 'when started' do
111
+ before { subject.listener.start }
112
+ it { should_not process_queued_addition_of('file.rb') }
113
+ it { should process_modification_of('file.rb') }
114
+ end
115
+ end
116
+
117
+ context 'with queued modification' do
118
+ before do
119
+ change_fs(:added, 'file.rb')
120
+ change_fs(:modified, 'file.rb')
121
+ end
122
+
123
+ it { should_not process_queued_addition_of('file.rb') }
124
+ it { should_not process_queued_modification_of('file.rb') }
125
+
126
+ context 'when started' do
127
+ before { subject.listener.start }
128
+ it { should_not process_queued_addition_of('file.rb') }
129
+ it { should_not process_queued_modification_of('file.rb') }
130
+ it { should process_modification_of('file.rb') }
131
+ end
132
+ end
133
+ end
81
134
  end
82
135
  end
83
-
84
- context 'when recipient' do
85
- before do
86
- recipient.start
87
- recipient.block = callback
88
- end
89
-
90
- it 'receives changes over TCP' do
91
- expect(listen(1) do
92
- touch 'file.rb'
93
- end).to eq(
94
- modified: [],
95
- added: ['file.rb'],
96
- removed: []
97
- )
98
- end
99
-
100
- it 'may be paused and unpaused' do
101
- recipient.pause
102
-
103
- expect(listen(1) do
104
- touch 'file.rb'
105
- end).to eq(
106
- modified: [],
107
- added: [],
108
- removed: []
109
- )
110
-
111
- recipient.unpause
112
-
113
- expect(listen(1) do
114
- touch 'file.rb'
115
- end).to eq(
116
- modified: ['file.rb'],
117
- added: [],
118
- removed: []
119
- )
120
- end
121
-
122
- it 'may be stopped and restarted' do
123
- recipient.stop
124
-
125
- expect(listen(1) do
126
- touch 'file.rb'
127
- end).to eq(
128
- modified: [],
129
- added: [],
130
- removed: []
131
- )
132
-
133
- recipient.start
134
-
135
- expect(listen(1) do
136
- touch 'file.rb'
137
- end).to eq(
138
- modified: ['file.rb'],
139
- added: [],
140
- removed: []
141
- )
142
- end
143
- end
144
-
145
136
  end
@@ -1,46 +1,29 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Listen::Adapter::Base do
4
- let(:adapter) { described_class.new(listener) }
5
- let(:registry) { double(Celluloid::Registry) }
6
- let(:listener) { double(Listen::Listener, registry: registry, options: {}) }
4
+ subject { described_class.new(listener) }
7
5
 
8
- describe '#_latency' do
9
- it 'returns default_latency with listener actor latency not present' do
10
- latency = Listen::Adapter::Base::DEFAULT_LATENCY
11
- expect(adapter.send(:_latency)).to eq latency
12
- end
6
+ let(:listener) { instance_double(Listen::Listener) }
13
7
 
14
- it 'returns latency from listener actor if present' do
15
- listener.stub(:options) { { latency: 1234 } }
16
- expect(adapter.send(:_latency)).to eq 1234
17
- end
18
- end
8
+ before { allow(listener).to receive(:async).with(:change_pool) { worker } }
19
9
 
20
10
  describe '#_notify_change' do
21
- let(:change_pool) { double(Listen::Change) }
22
- let(:change_pool_async) { double('ChangePoolAsync') }
23
- before do
24
- change_pool.stub(:async) { change_pool_async }
25
- registry.stub(:[]).with(:change_pool) { change_pool }
26
- end
27
-
28
- context 'listener listen' do
29
- before { listener.stub(:listen?) { true } }
11
+ context 'listener is listening or paused' do
12
+ let(:worker) { instance_double(Listen::Change) }
30
13
 
31
14
  it 'calls change on change_pool asynchronously' do
32
- expect(change_pool_async).to receive(:change).
33
- with('path', type: 'Dir', recurcise: true)
34
- adapter.send(:_notify_change, 'path', type: 'Dir', recurcise: true)
15
+ expect(worker).to receive(:change).
16
+ with(:dir, 'path', recursive: true)
17
+ subject.send(:_notify_change, :dir, 'path', recursive: true)
35
18
  end
36
19
  end
37
20
 
38
- context "listener doesn't listen" do
39
- before { listener.stub(:listen?) { false } }
21
+ context 'listener is stopped' do
22
+ let(:worker) { nil }
40
23
 
41
- it 'calls change on change_pool asynchronously' do
42
- expect(change_pool_async).to_not receive(:change)
43
- adapter.send(:_notify_change, 'path', type: 'Dir', recurcise: true)
24
+ it 'does not fail when no worker is available' do
25
+ expect(worker).to_not receive(:change)
26
+ subject.send(:_notify_change, :dir, 'path', recursive: true)
44
27
  end
45
28
  end
46
29
  end
@@ -1,42 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Listen::Adapter::BSD do
4
+ describe 'class' do
5
+ subject { described_class }
6
+ it { should be_local_fs }
4
7
 
5
- if bsd?
6
- let(:listener) { double(Listen::Listener) }
7
- let(:adapter) { described_class.new(listener) }
8
-
9
- describe '.usable?' do
10
- it 'returns always true' do
11
- expect(described_class).to be_usable
12
- end
13
-
14
- it 'requires rb-kqueue and find gem' do
15
- described_class.usable?
16
- expect(defined?(KQueue)).to be_true
17
- expect(defined?(Find)).to be_true
18
- end
8
+ if bsd?
9
+ it { should be_usable }
10
+ else
11
+ it { should_not be_usable }
19
12
  end
20
13
  end
21
-
22
- if darwin?
23
- it "isn't usable on Darwin" do
24
- expect(described_class).to_not be_usable
25
- end
26
- end
27
-
28
- if linux?
29
- it "isn't usable on Linux" do
30
- expect(described_class).to_not be_usable
31
- end
32
- end
33
-
34
- if windows?
35
- it "isn't usable on Windows" do
36
- expect(described_class).to_not be_usable
37
- end
38
- end
39
-
40
- specify { expect(described_class).to be_local_fs }
41
-
42
14
  end
@@ -1,42 +1,30 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Listen::Adapter::Darwin do
4
- if darwin?
5
- let(:listener) { double(Listen::Listener) }
6
- let(:adapter) { described_class.new(listener) }
7
-
8
- describe '.usable?' do
9
- it 'returns always true' do
10
- expect(described_class).to be_usable
11
- end
12
- end
13
-
14
- describe '#initialize' do
15
- it 'requires rb-fsevent gem' do
16
- described_class.new(listener)
17
- expect(defined?(FSEvent)).to be_true
18
- end
4
+ describe 'class' do
5
+ subject { described_class }
6
+ it { should be_local_fs }
7
+
8
+ if darwin?
9
+ it { should be_usable }
10
+ else
11
+ it { should_not be_usable }
19
12
  end
20
13
  end
21
14
 
22
- if windows?
23
- it "isn't usable on Windows" do
24
- expect(described_class).to_not be_usable
25
- end
26
- end
15
+ let(:options) { {} }
16
+ let(:listener) { instance_double(Listen::Listener, options: options) }
27
17
 
28
- if linux?
29
- it "isn't usable on Linux" do
30
- expect(described_class).to_not be_usable
18
+ describe '#_latency' do
19
+ subject { described_class.new(listener).send(:_latency) }
20
+
21
+ context 'with no overriding option' do
22
+ it { should eq described_class.const_get('DEFAULT_LATENCY') }
31
23
  end
32
- end
33
24
 
34
- if bsd?
35
- it "isn't usable on BSD" do
36
- expect(described_class).to_not be_usable
25
+ context 'with custom latency overriding' do
26
+ let(:options) { { latency: 1234 } }
27
+ it { should eq 1234 }
37
28
  end
38
29
  end
39
-
40
- specify { expect(described_class).to be_local_fs }
41
-
42
30
  end
@@ -1,19 +1,27 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Listen::Adapter::Linux do
4
+ describe 'class' do
5
+ subject { described_class }
6
+ it { should be_local_fs }
7
+
8
+ if linux?
9
+ it { should be_usable }
10
+ else
11
+ it { should_not be_usable }
12
+ end
13
+ end
14
+
4
15
  if linux?
5
- let(:listener) { double(Listen::Listener) }
16
+ let(:listener) { instance_double(Listen::Listener) }
6
17
  let(:adapter) { described_class.new(listener) }
7
18
 
8
- describe '.usable?' do
9
- it 'returns always true' do
10
- expect(described_class).to be_usable
11
- end
12
- end
13
-
14
19
  describe '#initialize' do
20
+ before do
21
+ allow(listener).to receive(:directories) { [] }
22
+ end
15
23
  it 'requires rb-inotify gem' do
16
- described_class.new(listener)
24
+ adapter.send(:_configure)
17
25
  expect(defined?(INotify)).to be
18
26
  end
19
27
  end
@@ -23,13 +31,16 @@ describe Listen::Adapter::Linux do
23
31
  let!(:adapter) { described_class.new(listener) }
24
32
 
25
33
  before do
26
- allow_any_instance_of(INotify::Notifier).to receive(:watch).
27
- and_raise(Errno::ENOSPC)
28
-
34
+ require 'rb-inotify'
29
35
  allow(listener).to receive(:directories) { ['foo/dir'] }
36
+ fake_worker = double(:fake_worker)
37
+ allow(fake_worker).to receive(:watch).and_raise(Errno::ENOSPC)
38
+
39
+ fake_notifier = double(:fake_notifier, new: fake_worker)
40
+ stub_const('INotify::Notifier', fake_notifier)
30
41
  end
31
42
 
32
- it 'should be show before calling abort' do
43
+ it 'should be shown before calling abort' do
33
44
  expected_message = described_class.const_get('INOTIFY_LIMIT_MESSAGE')
34
45
  expect(STDERR).to receive(:puts).with(expected_message)
35
46
 
@@ -40,15 +51,18 @@ describe Listen::Adapter::Linux do
40
51
  end
41
52
  end
42
53
 
43
- describe '_worker_callback' do
54
+ describe '_callback' do
55
+ before do
56
+ allow(listener).to receive(:directories) { [] }
57
+ end
44
58
 
45
59
  let(:expect_change) do
46
60
  lambda do |change|
47
61
  allow_any_instance_of(Listen::Adapter::Base).
48
62
  to receive(:_notify_change).
49
63
  with(
64
+ :file,
50
65
  Pathname.new('path/foo.txt'),
51
- type: 'File',
52
66
  change: change,
53
67
  cookie: 123)
54
68
  end
@@ -56,53 +70,33 @@ describe Listen::Adapter::Linux do
56
70
 
57
71
  let(:event_callback) do
58
72
  lambda do |flags|
59
- callback = adapter.send(:_worker_callback)
60
- callback.call double(:event,
61
- name: 'foo.txt',
62
- flags: flags,
63
- absolute_name: 'path/foo.txt',
64
- cookie: 123)
73
+ callback = adapter.send(:_callback)
74
+ callback.call double(
75
+ :inotify_event,
76
+ name: 'foo.txt',
77
+ watcher: double(:watcher, path: 'path'),
78
+ flags: flags,
79
+ cookie: 123)
65
80
  end
66
81
  end
67
82
 
68
- # use case: close_write is the only way to detect changes
69
- # on ecryptfs
70
- it 'recognizes close_write as modify' do
71
- expect_change.call(:modified)
72
- event_callback.call([:close_write])
73
- end
83
+ # TODO: get fsevent adapter working like INotify
84
+ unless /1|true/ =~ ENV['LISTEN_GEM_SIMULATE_FSEVENT']
85
+ it 'recognizes close_write as modify' do
86
+ expect_change.call(:modified)
87
+ event_callback.call([:close_write])
88
+ end
74
89
 
75
- it 'recognizes moved_to as moved_to' do
76
- expect_change.call(:moved_to)
77
- event_callback.call([:moved_to])
78
- end
90
+ it 'recognizes moved_to as moved_to' do
91
+ expect_change.call(:moved_to)
92
+ event_callback.call([:moved_to])
93
+ end
79
94
 
80
- it 'recognizes moved_from as moved_from' do
81
- expect_change.call(:moved_from)
82
- event_callback.call([:moved_from])
95
+ it 'recognizes moved_from as moved_from' do
96
+ expect_change.call(:moved_from)
97
+ event_callback.call([:moved_from])
98
+ end
83
99
  end
84
100
  end
85
-
86
- end
87
-
88
- if darwin?
89
- it "isn't usable on Darwin" do
90
- expect(described_class).to_not be_usable
91
- end
92
- end
93
-
94
- if windows?
95
- it "isn't usable on Windows" do
96
- expect(described_class).to_not be_usable
97
- end
98
101
  end
99
-
100
- if bsd?
101
- it "isn't usable on BSD" do
102
- expect(described_class).to_not be_usable
103
- end
104
- end
105
-
106
- specify { expect(described_class).to be_local_fs }
107
-
108
102
  end