listen 2.7.5 → 2.7.6

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -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
@@ -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 = { type: 'Dir', recursive: true, silence: true }
33
- listener.registry[:change_pool].change(path, options)
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
@@ -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 = 'Unknown')
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 == 'File'
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
- if listener.options[:only]
63
- @only_patterns = Array(listener.options[:only])
64
- end
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
@@ -6,4 +6,3 @@ rescue LoadError
6
6
  end
7
7
 
8
8
  require 'listen/adapter/tcp'
9
- require 'listen/tcp/listener'
@@ -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 @server
32
- @sockets.clear
33
- @server.close
34
- @server = nil
35
- end
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.each do |socket|
41
- unicast(socket, payload)
42
+ active_sockets = @sockets.select do |socket|
43
+ _unicast(socket, payload)
42
44
  end
43
- end
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
- handle_connection(socket)
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
- # Handles incoming socket connection
65
- def handle_connection(socket)
66
- @sockets << socket
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
@@ -13,8 +13,8 @@ module Listen
13
13
  #
14
14
  # @param [Object] object to initialize message with
15
15
  #
16
- def initialize(object = nil)
17
- self.object = object if object
16
+ def initialize(*args)
17
+ self.object = args
18
18
  end
19
19
 
20
20
  # Generates message size and payload for given object
@@ -1,3 +1,3 @@
1
1
  module Listen
2
- VERSION = '2.7.5'
2
+ VERSION = '2.7.6'
3
3
  end
@@ -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', '~> 2.14'
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(:callback) do
8
- lambda do |modified, added, removed|
9
- add_changes(:modified, modified)
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
- after { listener.stop }
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(:options) { { force_polling: polling, latency: 0.1 } }
34
+ let(:polling_options) { { force_polling: polling } }
41
35
 
42
- context 'nothing in listen dir' do
43
- it 'listens to file addition' do
44
- expect(listen do
45
- touch 'file.rb'
46
- end).to eq(modified: [], added: ['file.rb'], removed: [])
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
- it 'listens to multiple files addition' do
50
- result = listen do
51
- touch 'file1.rb'
52
- touch 'file2.rb'
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
- expect(result).to eq(modified: [],
56
- added: %w(file1.rb file2.rb),
57
- removed: [])
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
- it 'listens to file moved inside' do
61
- touch '../file.rb'
62
- expect(listen do
63
- mv '../file.rb', 'file.rb'
64
- end).to eq(modified: [], added: ['file.rb'], removed: [])
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
- context 'file in listen dir' do
69
- around do |example|
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
- it 'listens to file touch' do
75
- expect(listen do
76
- touch 'file.rb'
77
- end).to eq(modified: ['file.rb'], added: [], removed: [])
78
- end
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
- it 'listens to file modification' do
81
- expect(listen do
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
- it 'listens to file modification and wait' do
87
- expect(listen do
88
- open('file.rb', 'w') { |f| f.write('foo') }
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
- it 'listens to file echo' do
94
- expect(listen do
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
- it 'listens to file removal' do
100
- expect(listen do
101
- rm 'file.rb'
102
- end).to eq(modified: [], added: [], removed: ['file.rb'])
103
- end
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
- it 'listens to file moved out' do
106
- expect(listen do
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
- it 'listens to file mode change' do
112
- expect(listen do
113
- chmod 0777, 'file.rb'
114
- end).to eq(modified: ['file.rb'], added: [], removed: [])
115
- end
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
- context 'hidden file in listen dir' do
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
- it 'listens to file touch' do
125
- expect(listen do
126
- touch '.hidden'
127
- end).to eq(modified: ['.hidden'], added: [], removed: [])
128
- end
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
- context 'dir in listen dir' do
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
- it 'listens to file touch' do
138
- expect(listen do
117
+ context 'dir with file in listen dir' do
118
+ around do |example|
119
+ mkdir_p 'dir'
139
120
  touch 'dir/file.rb'
140
- end).to eq(modified: [], added: ['dir/file.rb'], removed: [])
141
- end
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
- it 'listens to file move' do
152
- expected = { modified: [],
153
- added: %w(file.rb),
154
- removed: %w(dir/file.rb)
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
- expect(listen do
158
- mv 'dir/file.rb', 'file.rb'
159
- end).to eq expected
160
- end
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
- it 'listens to multiple file moves' do
173
- expected = {
174
- modified: [],
175
- added: ['dir1/file2.rb', 'dir2/file1.rb'],
176
- removed: ['dir1/file1.rb', 'dir2/file2.rb']
177
- }
178
-
179
- expect(listen do
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
- it 'listens to dir move' do
186
- expected = { modified: [],
187
- added: ['dir2/dir1/file1.rb'],
188
- removed: ['dir1/file1.rb'] }
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
- expect(listen do
191
- mv 'dir1', 'dir2/'
192
- end).to eq expected
193
- end
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
- context 'default ignored dir with file in listen dir' do
197
- around do |example|
198
- mkdir_p '.bundle'
199
- touch '.bundle/file.rb'
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
- let(:options) { { force_polling: polling, latency: 0.1 } }
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
- it "doesn't listen to file touch" do
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 'ignored dir with file in listen dir' do
213
- around do |example|
214
- mkdir_p 'ignored_dir'
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
- let(:options) do
220
- { force_polling: polling,
221
- latency: 0.1,
222
- ignore: /ignored_dir/ }
223
- end
183
+ around do |example|
184
+ mkdir_p 'ignored_dir'
185
+ example.run
186
+ end
224
187
 
225
- it "doesn't listen to file touch" do
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
- context 'with ignored file in listen dir' do
233
- around do |example|
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
- it "doesn't listen to file touch" do
244
- expect(listen do
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
- context 'with only option' do
251
- let(:options) do
252
- { force_polling: polling,
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
- it 'listens only to file touch matching with only patterns' do
258
- expect(listen do
259
- touch 'file.rb'
260
- touch 'file.txt'
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
- context 'with ignore and only option' do
266
- let(:options) do
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
- it 'listens only to file touch matching with only patterns' do
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
- describe '#ignore' do
282
- around do |example|
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
- it 'overwrites existing patterns' do
293
- expect(listen do
294
- listener.ignore(/\.txt/)
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
- describe '#ignore!' do
302
- let(:options) do
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
- it 'overwrites existing patterns' do
309
- expect(listen do
310
- listener.ignore!(/\.txt/)
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