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.
- checksums.yaml +4 -4
- data/.gitignore +0 -0
- data/.rspec +0 -0
- data/.rubocop.yml +0 -0
- data/.travis.yml +0 -1
- data/.yardopts +0 -0
- data/CHANGELOG.md +0 -0
- data/CONTRIBUTING.md +0 -0
- data/Gemfile +25 -4
- data/Guardfile +0 -0
- data/LICENSE.txt +0 -0
- data/README.md +18 -10
- data/Rakefile +0 -0
- data/lib/listen.rb +2 -4
- data/lib/listen/adapter.rb +13 -4
- data/lib/listen/adapter/base.rb +33 -16
- data/lib/listen/adapter/bsd.rb +21 -38
- data/lib/listen/adapter/darwin.rb +17 -25
- data/lib/listen/adapter/linux.rb +34 -52
- data/lib/listen/adapter/polling.rb +9 -25
- data/lib/listen/adapter/tcp.rb +27 -14
- data/lib/listen/adapter/windows.rb +67 -23
- data/lib/listen/change.rb +26 -23
- data/lib/listen/cli.rb +0 -0
- data/lib/listen/directory.rb +47 -58
- data/lib/listen/file.rb +66 -101
- data/lib/listen/listener.rb +214 -155
- data/lib/listen/queue_optimizer.rb +104 -0
- data/lib/listen/record.rb +15 -5
- data/lib/listen/silencer.rb +14 -10
- data/lib/listen/tcp.rb +0 -1
- data/lib/listen/tcp/broadcaster.rb +31 -26
- data/lib/listen/tcp/message.rb +2 -2
- data/lib/listen/version.rb +1 -1
- data/listen.gemspec +1 -1
- data/spec/acceptance/listen_spec.rb +151 -239
- data/spec/acceptance/tcp_spec.rb +125 -134
- data/spec/lib/listen/adapter/base_spec.rb +13 -30
- data/spec/lib/listen/adapter/bsd_spec.rb +7 -35
- data/spec/lib/listen/adapter/darwin_spec.rb +18 -30
- data/spec/lib/listen/adapter/linux_spec.rb +49 -55
- data/spec/lib/listen/adapter/polling_spec.rb +20 -35
- data/spec/lib/listen/adapter/tcp_spec.rb +25 -27
- data/spec/lib/listen/adapter/windows_spec.rb +7 -33
- data/spec/lib/listen/adapter_spec.rb +10 -10
- data/spec/lib/listen/change_spec.rb +55 -57
- data/spec/lib/listen/directory_spec.rb +105 -155
- data/spec/lib/listen/file_spec.rb +186 -73
- data/spec/lib/listen/listener_spec.rb +233 -216
- data/spec/lib/listen/record_spec.rb +60 -22
- data/spec/lib/listen/silencer_spec.rb +48 -75
- data/spec/lib/listen/tcp/broadcaster_spec.rb +78 -69
- data/spec/lib/listen/tcp/listener_spec.rb +28 -71
- data/spec/lib/listen/tcp/message_spec.rb +48 -14
- data/spec/lib/listen_spec.rb +3 -3
- data/spec/spec_helper.rb +6 -3
- data/spec/support/acceptance_helper.rb +250 -31
- data/spec/support/fixtures_helper.rb +6 -4
- data/spec/support/platform_helper.rb +2 -2
- metadata +5 -5
- data/lib/listen/tcp/listener.rb +0 -108
@@ -0,0 +1,104 @@
|
|
1
|
+
module Listen
|
2
|
+
module QueueOptimizer
|
3
|
+
private
|
4
|
+
|
5
|
+
def _smoosh_changes(changes)
|
6
|
+
# TODO: adapter could be nil at this point (shutdown)
|
7
|
+
if _adapter_class.local_fs?
|
8
|
+
cookies = changes.group_by do |_, _, _, options|
|
9
|
+
(options || {})[:cookie]
|
10
|
+
end
|
11
|
+
_squash_changes(_reinterpret_related_changes(cookies))
|
12
|
+
else
|
13
|
+
smooshed = { modified: [], added: [], removed: [] }
|
14
|
+
changes.each { |_, change, path, _| smooshed[change] << path.to_s }
|
15
|
+
smooshed.tap { |s| s.each { |_, v| v.uniq! } }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def _squash_changes(changes)
|
20
|
+
actions = changes.group_by(&:last).map do |path, action_list|
|
21
|
+
[_logical_action_for(path, action_list.map(&:first)), path.to_s]
|
22
|
+
end
|
23
|
+
_log :info, "listen: raw changes: #{actions.inspect}"
|
24
|
+
|
25
|
+
{ modified: [], added: [], removed: [] }.tap do |squashed|
|
26
|
+
actions.each do |type, path|
|
27
|
+
squashed[type] << path unless type.nil?
|
28
|
+
end
|
29
|
+
_log :info, "listen: final changes: #{squashed.inspect}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def _logical_action_for(path, actions)
|
34
|
+
actions << :added if actions.delete(:moved_to)
|
35
|
+
actions << :removed if actions.delete(:moved_from)
|
36
|
+
|
37
|
+
modified = actions.detect { |x| x == :modified }
|
38
|
+
_calculate_add_remove_difference(actions, path, modified)
|
39
|
+
end
|
40
|
+
|
41
|
+
def _calculate_add_remove_difference(actions, path, default_if_exists)
|
42
|
+
added = actions.count { |x| x == :added }
|
43
|
+
removed = actions.count { |x| x == :removed }
|
44
|
+
diff = added - removed
|
45
|
+
|
46
|
+
# TODO: avoid checking if path exists and instead assume the events are
|
47
|
+
# in order (if last is :removed, it doesn't exist, etc.)
|
48
|
+
if path.exist?
|
49
|
+
if diff > 0
|
50
|
+
:added
|
51
|
+
elsif diff.zero? && added > 0
|
52
|
+
:modified
|
53
|
+
else
|
54
|
+
default_if_exists
|
55
|
+
end
|
56
|
+
else
|
57
|
+
diff < 0 ? :removed : nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# remove extraneous rb-inotify events, keeping them only if it's a possible
|
62
|
+
# editor rename() call (e.g. Kate and Sublime)
|
63
|
+
def _reinterpret_related_changes(cookies)
|
64
|
+
table = { moved_to: :added, moved_from: :removed }
|
65
|
+
cookies.map do |_, changes|
|
66
|
+
file = _detect_possible_editor_save(changes)
|
67
|
+
if file
|
68
|
+
[[:modified, file]]
|
69
|
+
else
|
70
|
+
not_silenced = changes.reject do |type, _, path, _|
|
71
|
+
_silenced?(path, type)
|
72
|
+
end
|
73
|
+
not_silenced.map do |_, change, path, _|
|
74
|
+
[table.fetch(change, change), path]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end.flatten(1)
|
78
|
+
end
|
79
|
+
|
80
|
+
def _detect_possible_editor_save(changes)
|
81
|
+
return unless changes.size == 2
|
82
|
+
|
83
|
+
from_type = from_change = from = nil
|
84
|
+
to_type = to_change = to = nil
|
85
|
+
|
86
|
+
changes.each do |data|
|
87
|
+
case data[1]
|
88
|
+
when :moved_from
|
89
|
+
from_type, from_change, from, _ = data
|
90
|
+
when :moved_to
|
91
|
+
to_type, to_change, to, _ = data
|
92
|
+
else
|
93
|
+
return nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
return unless from && to
|
98
|
+
|
99
|
+
# Expect an ignored moved_from and non-ignored moved_to
|
100
|
+
# to qualify as an "editor modify"
|
101
|
+
_silenced?(from, from_type) && !_silenced?(to, to_type) ? to : nil
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/listen/record.rb
CHANGED
@@ -2,6 +2,7 @@ module Listen
|
|
2
2
|
class Record
|
3
3
|
include Celluloid
|
4
4
|
|
5
|
+
# TODO: deprecate
|
5
6
|
attr_accessor :paths, :listener
|
6
7
|
|
7
8
|
def initialize(listener)
|
@@ -9,8 +10,8 @@ module Listen
|
|
9
10
|
@paths = _init_paths
|
10
11
|
end
|
11
12
|
|
12
|
-
def set_path(path, data)
|
13
|
-
new_data = file_data(path).merge(data)
|
13
|
+
def set_path(type, path, data = {})
|
14
|
+
new_data = file_data(path).merge(data).merge(type: type)
|
14
15
|
@paths[::File.dirname(path)][::File.basename(path)] = new_data
|
15
16
|
end
|
16
17
|
|
@@ -23,15 +24,24 @@ module Listen
|
|
23
24
|
end
|
24
25
|
|
25
26
|
def dir_entries(path)
|
26
|
-
@paths[path.to_s]
|
27
|
+
@paths[path.to_s].dup
|
27
28
|
end
|
28
29
|
|
29
30
|
def build
|
31
|
+
@last_build_at = Time.now
|
30
32
|
@paths = _init_paths
|
31
33
|
listener.directories.each do |path|
|
32
|
-
options = {
|
33
|
-
listener.
|
34
|
+
options = { recursive: true, silence: true, build: true }
|
35
|
+
listener.sync(:change_pool).change(:dir, path, options)
|
34
36
|
end
|
37
|
+
sleep 0.01 until @last_build_at + 0.1 < Time.now
|
38
|
+
rescue
|
39
|
+
Celluloid.logger.warn "build crashed: #{$!.inspect}"
|
40
|
+
raise
|
41
|
+
end
|
42
|
+
|
43
|
+
def still_building!
|
44
|
+
@last_build_at = Time.now
|
35
45
|
end
|
36
46
|
|
37
47
|
private
|
data/lib/listen/silencer.rb
CHANGED
@@ -25,6 +25,15 @@ module Listen
|
|
25
25
|
# Gedit tmp files
|
26
26
|
| \.goutputstream-.{6}
|
27
27
|
|
28
|
+
# Intellij files
|
29
|
+
| ___jb_bak___
|
30
|
+
| ___jb_old___
|
31
|
+
|
32
|
+
# Vim swap files and write test
|
33
|
+
| \.sw[px]
|
34
|
+
| \.swpx
|
35
|
+
| ^4913
|
36
|
+
|
28
37
|
# other files
|
29
38
|
| \.DS_Store
|
30
39
|
| \.tmp
|
@@ -39,29 +48,24 @@ module Listen
|
|
39
48
|
_init_ignore_patterns
|
40
49
|
end
|
41
50
|
|
42
|
-
def silenced?(path, type
|
51
|
+
def silenced?(path, type)
|
43
52
|
silenced = false
|
44
53
|
|
45
54
|
relative_path = _relative_path(path)
|
46
55
|
|
47
|
-
if only_patterns && type ==
|
56
|
+
if only_patterns && type == :file
|
48
57
|
silenced = !only_patterns.any? { |pattern| relative_path =~ pattern }
|
49
58
|
end
|
50
59
|
|
51
60
|
silenced || ignore_patterns.any? { |pattern| relative_path =~ pattern }
|
52
61
|
end
|
53
62
|
|
54
|
-
def match(args)
|
55
|
-
path, type = args.first
|
56
|
-
silenced?(path, type)
|
57
|
-
end
|
58
|
-
|
59
63
|
private
|
60
64
|
|
61
65
|
def _init_only_patterns
|
62
|
-
|
63
|
-
|
64
|
-
|
66
|
+
return unless listener.options[:only]
|
67
|
+
|
68
|
+
@only_patterns = Array(listener.options[:only])
|
65
69
|
end
|
66
70
|
|
67
71
|
def _init_ignore_patterns
|
data/lib/listen/tcp.rb
CHANGED
@@ -7,8 +7,6 @@ module Listen
|
|
7
7
|
|
8
8
|
finalizer :finalize
|
9
9
|
|
10
|
-
attr_reader :server, :sockets
|
11
|
-
|
12
10
|
# Initializes a Celluloid::IO-powered TCP-broadcaster
|
13
11
|
#
|
14
12
|
# @param [String] host to broadcast on
|
@@ -17,8 +15,11 @@ module Listen
|
|
17
15
|
# Note: Listens on all addresses when host is nil
|
18
16
|
#
|
19
17
|
def initialize(host, port)
|
20
|
-
@server = TCPServer.new(host, port)
|
21
18
|
@sockets = []
|
19
|
+
@server = TCPServer.new(host, port)
|
20
|
+
rescue
|
21
|
+
_log :error, "Broadcaster.initialize: #{$!.inspect}:#{$@.join("\n")}"
|
22
|
+
raise
|
22
23
|
end
|
23
24
|
|
24
25
|
# Asynchronously start accepting connections
|
@@ -28,42 +29,46 @@ module Listen
|
|
28
29
|
|
29
30
|
# Cleans up sockets and server
|
30
31
|
def finalize
|
31
|
-
if @
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
@sockets.map(&:close) if @sockets
|
33
|
+
@sockets = nil
|
34
|
+
|
35
|
+
return unless @server
|
36
|
+
@server.close
|
37
|
+
@server = nil
|
36
38
|
end
|
37
39
|
|
38
40
|
# Broadcasts given payload to all connected sockets
|
39
41
|
def broadcast(payload)
|
40
|
-
@sockets.
|
41
|
-
|
42
|
+
active_sockets = @sockets.select do |socket|
|
43
|
+
_unicast(socket, payload)
|
42
44
|
end
|
43
|
-
|
44
|
-
|
45
|
-
# Unicasts payload to given socket
|
46
|
-
#
|
47
|
-
# @return [Boolean] whether writing to socket was succesful
|
48
|
-
#
|
49
|
-
def unicast(socket, payload)
|
50
|
-
socket.write(payload)
|
51
|
-
true
|
52
|
-
rescue IOError, Errno::ECONNRESET, Errno::EPIPE
|
53
|
-
@sockets.delete(socket)
|
54
|
-
false
|
45
|
+
@sockets.replace(active_sockets)
|
55
46
|
end
|
56
47
|
|
57
48
|
# Continuously accept and handle incoming connections
|
58
49
|
def run
|
59
50
|
while socket = @server.accept
|
60
|
-
|
51
|
+
@sockets << socket
|
61
52
|
end
|
53
|
+
rescue Celluloid::Task::TerminatedError
|
54
|
+
_log :debug, "TCP adapter was terminated: #{$!.inspect}"
|
55
|
+
rescue
|
56
|
+
_log :error, "Broadcaster.run: #{$!.inspect}:#{$@.join("\n")}"
|
57
|
+
raise
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def _log(type, message)
|
63
|
+
Celluloid.logger.send(type, message)
|
62
64
|
end
|
63
65
|
|
64
|
-
|
65
|
-
|
66
|
-
|
66
|
+
def _unicast(socket, payload)
|
67
|
+
socket.write(payload)
|
68
|
+
true
|
69
|
+
rescue IOError, Errno::ECONNRESET, Errno::EPIPE
|
70
|
+
_log :debug, "Broadcaster failed: #{socket.inspect}"
|
71
|
+
false
|
67
72
|
end
|
68
73
|
end
|
69
74
|
end
|
data/lib/listen/tcp/message.rb
CHANGED
@@ -13,8 +13,8 @@ module Listen
|
|
13
13
|
#
|
14
14
|
# @param [Object] object to initialize message with
|
15
15
|
#
|
16
|
-
def initialize(
|
17
|
-
self.object =
|
16
|
+
def initialize(*args)
|
17
|
+
self.object = args
|
18
18
|
end
|
19
19
|
|
20
20
|
# Generates message size and payload for given object
|
data/lib/listen/version.rb
CHANGED
data/listen.gemspec
CHANGED
@@ -28,6 +28,6 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.add_development_dependency 'bundler', '>= 1.3.5'
|
29
29
|
s.add_development_dependency 'celluloid-io', '>= 0.15.0'
|
30
30
|
s.add_development_dependency 'rake'
|
31
|
-
s.add_development_dependency 'rspec', '~>
|
31
|
+
s.add_development_dependency 'rspec', '~> 3.0.0rc1'
|
32
32
|
s.add_development_dependency 'rspec-retry'
|
33
33
|
end
|
@@ -2,23 +2,16 @@
|
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
4
|
describe 'Listen' do
|
5
|
+
let(:base_options) { { wait_for_delay: 0.1, latency: 0.1 } }
|
6
|
+
let(:polling_options) { {} }
|
5
7
|
let(:options) { {} }
|
8
|
+
let(:all_options) { base_options.merge(polling_options).merge(options) }
|
6
9
|
|
7
|
-
let(:
|
8
|
-
|
9
|
-
|
10
|
-
add_changes(:added, added)
|
11
|
-
add_changes(:removed, removed)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
let(:listener) { @listener }
|
16
|
-
before do
|
17
|
-
@listener = setup_listener(options, callback)
|
18
|
-
@listener.start
|
19
|
-
end
|
10
|
+
let(:wrapper) { setup_listener(all_options, :track_changes) }
|
11
|
+
before { wrapper.listener.start }
|
12
|
+
after { wrapper.listener.stop }
|
20
13
|
|
21
|
-
|
14
|
+
subject { wrapper }
|
22
15
|
|
23
16
|
context 'with one listen dir' do
|
24
17
|
let(:paths) { Pathname.new(Dir.pwd) }
|
@@ -26,291 +19,210 @@ describe 'Listen' do
|
|
26
19
|
|
27
20
|
context 'with change block raising' do
|
28
21
|
let(:callback) { ->(_, _, _) { fail 'foo' } }
|
22
|
+
let(:wrapper) { setup_listener(all_options, callback) }
|
29
23
|
|
30
24
|
it 'warns the backtrace' do
|
31
25
|
expect(Kernel).to receive(:warn).
|
32
26
|
with('[Listen warning]: Change block raised an exception: foo')
|
33
27
|
expect(Kernel).to receive(:warn).with(/^Backtrace:.*/)
|
34
|
-
listen { touch 'file.rb' }
|
28
|
+
wrapper.listen { touch 'file.rb' }
|
35
29
|
end
|
36
30
|
end
|
37
31
|
|
38
32
|
[false, true].each do |polling|
|
39
33
|
context "force_polling option to #{polling}" do
|
40
|
-
let(:
|
34
|
+
let(:polling_options) { { force_polling: polling } }
|
41
35
|
|
42
|
-
context '
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
36
|
+
context 'with default ignore options' do
|
37
|
+
context 'with nothing in listen dir' do
|
38
|
+
|
39
|
+
it { is_expected.to process_addition_of('file.rb') }
|
40
|
+
it { is_expected.to process_addition_of('.hidden') }
|
48
41
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
42
|
+
it 'listens to multiple files addition' do
|
43
|
+
result = wrapper.listen do
|
44
|
+
change_fs(:added, 'file1.rb')
|
45
|
+
change_fs(:added, 'file2.rb')
|
46
|
+
end
|
47
|
+
|
48
|
+
expect(result).to eq(modified: [],
|
49
|
+
added: %w(file1.rb file2.rb),
|
50
|
+
removed: [])
|
53
51
|
end
|
54
52
|
|
55
|
-
|
56
|
-
|
57
|
-
|
53
|
+
it 'listens to file moved inside' do
|
54
|
+
touch '../file.rb'
|
55
|
+
expect(wrapper.listen do
|
56
|
+
mv '../file.rb', 'file.rb'
|
57
|
+
end).to eq(modified: [], added: ['file.rb'], removed: [])
|
58
|
+
end
|
58
59
|
end
|
59
60
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
61
|
+
context 'existing file.rb in listen dir' do
|
62
|
+
around do |example|
|
63
|
+
change_fs(:added, 'file.rb')
|
64
|
+
example.run
|
65
|
+
end
|
67
66
|
|
68
|
-
|
69
|
-
|
70
|
-
touch 'file.rb'
|
71
|
-
example.run
|
72
|
-
end
|
67
|
+
it { is_expected.to process_modification_of('file.rb') }
|
68
|
+
it { is_expected.to process_removal_of('file.rb') }
|
73
69
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
70
|
+
it 'listens to file.rb moved out' do
|
71
|
+
expect(wrapper.listen do
|
72
|
+
mv 'file.rb', '../file.rb'
|
73
|
+
end).to eq(modified: [], added: [], removed: ['file.rb'])
|
74
|
+
end
|
79
75
|
|
80
|
-
|
81
|
-
|
82
|
-
open('file.rb', 'w') { |f| f.write('foo') }
|
83
|
-
end).to eq(modified: ['file.rb'], added: [], removed: [])
|
84
|
-
end
|
76
|
+
it 'listens to file mode change' do
|
77
|
+
prev_mode = File.stat('file.rb').mode
|
85
78
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
sleep 0.5
|
90
|
-
end).to eq(modified: ['file.rb'], added: [], removed: [])
|
91
|
-
end
|
79
|
+
result = wrapper.listen do
|
80
|
+
windows? ? `attrib +r file.rb` : chmod(0444, 'file.rb')
|
81
|
+
end
|
92
82
|
|
93
|
-
|
94
|
-
|
95
|
-
`echo foo > #{Dir.pwd}/file.rb`
|
96
|
-
end).to eq(modified: ['file.rb'], added: [], removed: [])
|
97
|
-
end
|
83
|
+
new_mode = File.stat('file.rb').mode
|
84
|
+
no_event = result[:modified].empty? && prev_mode == new_mode
|
98
85
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
86
|
+
# Check if chmod actually works or an attrib event happens,
|
87
|
+
# or expect nothing otherwise
|
88
|
+
#
|
89
|
+
# (e.g. fails for polling+vfat on Linux, but works with
|
90
|
+
# INotify+vfat because you get an event regardless if mode
|
91
|
+
# actually changes)
|
92
|
+
#
|
93
|
+
files = no_event ? [] : ['file.rb']
|
104
94
|
|
105
|
-
|
106
|
-
|
107
|
-
mv 'file.rb', '../file.rb'
|
108
|
-
end).to eq(modified: [], added: [], removed: ['file.rb'])
|
95
|
+
expect(result).to eq(modified: files, added: [], removed: [])
|
96
|
+
end
|
109
97
|
end
|
110
98
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
end
|
99
|
+
context 'hidden file in listen dir' do
|
100
|
+
around do |example|
|
101
|
+
change_fs(:added, '.hidden')
|
102
|
+
example.run
|
103
|
+
end
|
117
104
|
|
118
|
-
|
119
|
-
around do |example|
|
120
|
-
touch '.hidden'
|
121
|
-
example.run
|
105
|
+
it { is_expected.to process_modification_of('.hidden') }
|
122
106
|
end
|
123
107
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
end
|
108
|
+
context 'dir in listen dir' do
|
109
|
+
around do |example|
|
110
|
+
mkdir_p 'dir'
|
111
|
+
example.run
|
112
|
+
end
|
130
113
|
|
131
|
-
|
132
|
-
around do |example|
|
133
|
-
mkdir_p 'dir'
|
134
|
-
example.run
|
114
|
+
it { is_expected.to process_addition_of('dir/file.rb') }
|
135
115
|
end
|
136
116
|
|
137
|
-
|
138
|
-
|
117
|
+
context 'dir with file in listen dir' do
|
118
|
+
around do |example|
|
119
|
+
mkdir_p 'dir'
|
139
120
|
touch 'dir/file.rb'
|
140
|
-
|
141
|
-
|
142
|
-
end
|
143
|
-
|
144
|
-
context 'dir with file in listen dir' do
|
145
|
-
around do |example|
|
146
|
-
mkdir_p 'dir'
|
147
|
-
touch 'dir/file.rb'
|
148
|
-
example.run
|
149
|
-
end
|
121
|
+
example.run
|
122
|
+
end
|
150
123
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
124
|
+
it 'listens to file move' do
|
125
|
+
expected = { modified: [],
|
126
|
+
added: %w(file.rb),
|
127
|
+
removed: %w(dir/file.rb)
|
128
|
+
}
|
156
129
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
end
|
162
|
-
|
163
|
-
context 'two dirs with files in listen dir' do
|
164
|
-
around do |example|
|
165
|
-
mkdir_p 'dir1'
|
166
|
-
touch 'dir1/file1.rb'
|
167
|
-
mkdir_p 'dir2'
|
168
|
-
touch 'dir2/file2.rb'
|
169
|
-
example.run
|
130
|
+
expect(wrapper.listen do
|
131
|
+
mv 'dir/file.rb', 'file.rb'
|
132
|
+
end).to eq expected
|
133
|
+
end
|
170
134
|
end
|
171
135
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
mv 'dir1/file1.rb', 'dir2/file1.rb'
|
181
|
-
mv 'dir2/file2.rb', 'dir1/file2.rb'
|
182
|
-
end).to eq expected
|
183
|
-
end
|
136
|
+
context 'two dirs with files in listen dir' do
|
137
|
+
around do |example|
|
138
|
+
mkdir_p 'dir1'
|
139
|
+
touch 'dir1/file1.rb'
|
140
|
+
mkdir_p 'dir2'
|
141
|
+
touch 'dir2/file2.rb'
|
142
|
+
example.run
|
143
|
+
end
|
184
144
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
145
|
+
it 'listens to multiple file moves' do
|
146
|
+
expected = {
|
147
|
+
modified: [],
|
148
|
+
added: ['dir1/file2.rb', 'dir2/file1.rb'],
|
149
|
+
removed: ['dir1/file1.rb', 'dir2/file2.rb']
|
150
|
+
}
|
151
|
+
|
152
|
+
expect(wrapper.listen do
|
153
|
+
mv 'dir1/file1.rb', 'dir2/file1.rb'
|
154
|
+
mv 'dir2/file2.rb', 'dir1/file2.rb'
|
155
|
+
end).to eq expected
|
156
|
+
end
|
189
157
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
end
|
158
|
+
it 'listens to dir move' do
|
159
|
+
expected = { modified: [],
|
160
|
+
added: ['dir2/dir1/file1.rb'],
|
161
|
+
removed: ['dir1/file1.rb'] }
|
195
162
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
example.run
|
163
|
+
expect(wrapper.listen do
|
164
|
+
mv 'dir1', 'dir2/'
|
165
|
+
end).to eq expected
|
166
|
+
end
|
201
167
|
end
|
202
168
|
|
203
|
-
|
169
|
+
context 'with .bundle dir ignored by default' do
|
170
|
+
around do |example|
|
171
|
+
mkdir_p '.bundle'
|
172
|
+
example.run
|
173
|
+
end
|
204
174
|
|
205
|
-
|
206
|
-
expect(listen do
|
207
|
-
touch '.bundle/file.rb'
|
208
|
-
end).to eq(modified: [], added: [], removed: [])
|
175
|
+
it { is_expected.not_to process_addition_of('.bundle/file.rb') }
|
209
176
|
end
|
210
177
|
end
|
211
178
|
|
212
|
-
context '
|
213
|
-
|
214
|
-
|
215
|
-
touch 'ignored_dir/file.rb'
|
216
|
-
example.run
|
217
|
-
end
|
179
|
+
context 'when :ignore is *ignored_dir*' do
|
180
|
+
context 'ignored dir with file in listen dir' do
|
181
|
+
let(:options) { { ignore: /ignored_dir/ } }
|
218
182
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
end
|
183
|
+
around do |example|
|
184
|
+
mkdir_p 'ignored_dir'
|
185
|
+
example.run
|
186
|
+
end
|
224
187
|
|
225
|
-
|
226
|
-
expect(listen do
|
227
|
-
touch 'ignored_dir/file.rb'
|
228
|
-
end).to eq(modified: [], added: [], removed: [])
|
188
|
+
it { is_expected.not_to process_addition_of('ignored_dir/file.rb') }
|
229
189
|
end
|
230
|
-
end
|
231
190
|
|
232
|
-
|
233
|
-
|
234
|
-
touch 'file.rb'
|
235
|
-
example.run
|
236
|
-
end
|
237
|
-
let(:options) do
|
238
|
-
{ force_polling: polling,
|
239
|
-
latency: 0.1,
|
240
|
-
ignore: /\.rb$/ }
|
241
|
-
end
|
191
|
+
context 'when :only is *.rb' do
|
192
|
+
let(:options) { { only: /\.rb$/ } }
|
242
193
|
|
243
|
-
|
244
|
-
|
245
|
-
touch 'file.rb'
|
246
|
-
end).to eq(modified: [], added: [], removed: [])
|
194
|
+
it { is_expected.to process_addition_of('file.rb') }
|
195
|
+
it { is_expected.not_to process_addition_of('file.txt') }
|
247
196
|
end
|
248
|
-
end
|
249
197
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
latency: 0.1,
|
254
|
-
only: /\.rb$/ }
|
255
|
-
end
|
198
|
+
context 'when :ignore is bar.rb' do
|
199
|
+
context 'when :only is *.rb' do
|
200
|
+
let(:options) { { ignore: /bar\.rb$/, only: /\.rb$/ } }
|
256
201
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
end).to eq(modified: [], added: ['file.rb'], removed: [])
|
202
|
+
it { is_expected.to process_addition_of('file.rb') }
|
203
|
+
it { is_expected.not_to process_addition_of('file.txt') }
|
204
|
+
it { is_expected.not_to process_addition_of('bar.rb') }
|
205
|
+
end
|
262
206
|
end
|
263
|
-
end
|
264
207
|
|
265
|
-
|
266
|
-
|
267
|
-
{ force_polling: polling,
|
268
|
-
latency: 0.1,
|
269
|
-
ignore: /bar\.rb$/, only: /\.rb$/ }
|
270
|
-
end
|
208
|
+
context 'when default ignore is *.rb' do
|
209
|
+
let(:options) { { ignore: /\.rb$/ } }
|
271
210
|
|
272
|
-
|
273
|
-
expect(listen do
|
274
|
-
touch 'file.rb'
|
275
|
-
touch 'bar.rb'
|
276
|
-
touch 'file.txt'
|
277
|
-
end).to eq(modified: [], added: ['file.rb'], removed: [])
|
278
|
-
end
|
279
|
-
end
|
211
|
+
it { is_expected.not_to process_addition_of('file.rb') }
|
280
212
|
|
281
|
-
|
282
|
-
|
283
|
-
touch 'file.rb'
|
284
|
-
example.run
|
285
|
-
end
|
286
|
-
let(:options) do
|
287
|
-
{ force_polling: polling,
|
288
|
-
latency: 0.1,
|
289
|
-
ignore: /\.rb$/ }
|
290
|
-
end
|
213
|
+
context 'with #ignore on *.txt mask' do
|
214
|
+
before { wrapper.listener.ignore(/\.txt/) }
|
291
215
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
touch 'file.rb'
|
296
|
-
touch 'file.txt'
|
297
|
-
end).to eq(modified: [], added: [], removed: [])
|
298
|
-
end
|
299
|
-
end
|
216
|
+
it { is_expected.not_to process_addition_of('file.rb') }
|
217
|
+
it { is_expected.not_to process_addition_of('file.txt') }
|
218
|
+
end
|
300
219
|
|
301
|
-
|
302
|
-
|
303
|
-
{ force_polling: polling,
|
304
|
-
latency: 0.1,
|
305
|
-
ignore: /\.rb$/ }
|
306
|
-
end
|
220
|
+
context 'with #ignore! on *.txt mask' do
|
221
|
+
before { wrapper.listener.ignore!(/\.txt/) }
|
307
222
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
touch 'file.rb'
|
312
|
-
touch 'file.txt'
|
313
|
-
end).to eq(modified: [], added: ['file.rb'], removed: [])
|
223
|
+
it { is_expected.to process_addition_of('file.rb') }
|
224
|
+
it { is_expected.not_to process_addition_of('file.txt') }
|
225
|
+
end
|
314
226
|
end
|
315
227
|
end
|
316
228
|
end
|