listen 2.7.5 → 2.7.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|