listen 0.7.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,62 +4,11 @@ module Listen
4
4
  # Adapter implementation for Mac OS X `FSEvents`.
5
5
  #
6
6
  class Darwin < Adapter
7
- extend DependencyManager
8
-
9
- # Declare the adapter's dependencies
10
- dependency 'rb-fsevent', '~> 0.9'
11
-
12
7
  LAST_SEPARATOR_REGEX = /\/$/
13
8
 
14
- # Initializes the Adapter. See {Listen::Adapter#initialize} for more info.
15
- #
16
- def initialize(directories, options = {}, &callback)
17
- super
18
- @worker = init_worker
19
- end
20
-
21
- # Starts the adapter.
22
- #
23
- # @param [Boolean] blocking whether or not to block the current thread after starting
24
- #
25
- def start(blocking = true)
26
- @mutex.synchronize do
27
- return if @stop == false
28
- super
29
- end
30
-
31
- @worker_thread = Thread.new { @worker.run }
32
-
33
- # The FSEvent worker needs sometime to startup. Turnstiles can't
34
- # be used to wait for it as it runs in a loop.
35
- # TODO: Find a better way to block until the worker starts.
36
- sleep 0.1
37
9
 
38
- @poll_thread = Thread.new { poll_changed_dirs } if @report_changes
39
- @worker_thread.join if blocking
40
- end
41
-
42
- # Stops the adapter.
43
- #
44
- def stop
45
- @mutex.synchronize do
46
- return if @stop == true
47
- super
48
- end
49
-
50
- @worker.stop
51
- @worker_thread.join if @worker_thread
52
- @poll_thread.join if @poll_thread
53
- end
54
-
55
- # Checks if the adapter is usable on the current OS.
56
- #
57
- # @return [Boolean] whether usable or not
58
- #
59
- def self.usable?
60
- return false unless RbConfig::CONFIG['target_os'] =~ /darwin(1.+)?$/i
61
- super
62
- end
10
+ def self.target_os_regex; /darwin(1.+)?$/i; end
11
+ def self.adapter_gem; 'rb-fsevent'; end
63
12
 
64
13
  private
65
14
 
@@ -68,17 +17,31 @@ module Listen
68
17
  #
69
18
  # @return [FSEvent] initialized worker
70
19
  #
71
- def init_worker
20
+ # @see Listen::Adapter#initialize_worker
21
+ #
22
+ def initialize_worker
72
23
  FSEvent.new.tap do |worker|
73
- worker.watch(@directories.dup, :latency => @latency) do |changes|
74
- next if @paused
75
- @mutex.synchronize do
76
- changes.each { |path| @changed_dirs << path.sub(LAST_SEPARATOR_REGEX, '') }
24
+ worker.watch(directories.dup, :latency => latency) do |changes|
25
+ next if paused
26
+
27
+ mutex.synchronize do
28
+ changes.each { |path| @changed_directories << path.sub(LAST_SEPARATOR_REGEX, '') }
77
29
  end
78
30
  end
79
31
  end
80
32
  end
81
33
 
34
+ # Starts the worker in a new thread and sleep 0.1 second.
35
+ #
36
+ # @see Listen::Adapter#start_worker
37
+ #
38
+ def start_worker
39
+ @worker_thread = Thread.new { worker.run }
40
+ # The FSEvent worker needs some time to start up. Turnstiles can't
41
+ # be used to wait for it as it runs in a loop.
42
+ # TODO: Find a better way to block until the worker starts.
43
+ sleep 0.1
44
+ end
82
45
  end
83
46
 
84
47
  end
@@ -4,17 +4,12 @@ module Listen
4
4
  # Listener implementation for Linux `inotify`.
5
5
  #
6
6
  class Linux < Adapter
7
- extend DependencyManager
8
-
9
- # Declare the adapter's dependencies
10
- dependency 'rb-inotify', '~> 0.9'
11
-
12
7
  # Watched inotify events
13
8
  #
14
9
  # @see http://www.tin.org/bin/man.cgi?section=7&topic=inotify
15
10
  # @see https://github.com/nex3/rb-inotify/blob/master/lib/rb-inotify/notifier.rb#L99-L177
16
11
  #
17
- EVENTS = %w[recursive attrib create delete move close_write]
12
+ EVENTS = [:recursive, :attrib, :create, :delete, :move, :close_write]
18
13
 
19
14
  # The message to show when the limit of inotify watchers is not enough
20
15
  #
@@ -25,63 +20,31 @@ module Listen
25
20
  for information on how to solve this issue.
26
21
  EOS
27
22
 
28
- # Initializes the Adapter. See {Listen::Adapter#initialize} for more info.
23
+ def self.target_os_regex; /linux/i; end
24
+ def self.adapter_gem; 'rb-inotify'; end
25
+
26
+ # Initializes the Adapter.
27
+ #
28
+ # @see Listen::Adapter#initialize
29
29
  #
30
30
  def initialize(directories, options = {}, &callback)
31
31
  super
32
- @worker = init_worker
33
32
  rescue Errno::ENOSPC
34
33
  abort(INOTIFY_LIMIT_MESSAGE)
35
34
  end
36
35
 
37
- # Starts the adapter.
38
- #
39
- # @param [Boolean] blocking whether or not to block the current thread after starting
40
- #
41
- def start(blocking = true)
42
- @mutex.synchronize do
43
- return if @stop == false
44
- super
45
- end
46
-
47
- @worker_thread = Thread.new { @worker.run }
48
- @poll_thread = Thread.new { poll_changed_dirs } if @report_changes
49
-
50
- @worker_thread.join if blocking
51
- end
52
-
53
- # Stops the adapter.
54
- #
55
- def stop
56
- @mutex.synchronize do
57
- return if @stop == true
58
- super
59
- end
60
-
61
- @worker.stop
62
- Thread.kill(@worker_thread) if @worker_thread
63
- @poll_thread.join if @poll_thread
64
- end
65
-
66
- # Checks if the adapter is usable on the current OS.
67
- #
68
- # @return [Boolean] whether usable or not
69
- #
70
- def self.usable?
71
- return false unless RbConfig::CONFIG['target_os'] =~ /linux/i
72
- super
73
- end
74
-
75
- private
36
+ private
76
37
 
77
38
  # Initializes a INotify worker and adds a watcher for
78
39
  # each directory passed to the adapter.
79
40
  #
80
41
  # @return [INotify::Notifier] initialized worker
81
42
  #
82
- def init_worker
43
+ # @see Listen::Adapter#initialize_worker
44
+ #
45
+ def initialize_worker
83
46
  callback = lambda do |event|
84
- if @paused || (
47
+ if paused || (
85
48
  # Event on root directory
86
49
  event.name == ""
87
50
  ) || (
@@ -89,24 +52,29 @@ module Listen
89
52
  # on the directories themselves too.
90
53
  #
91
54
  # @see http://linux.die.net/man/7/inotify
92
- event.flags.include?(:isdir) and event.flags & [:close, :modify] != []
55
+ event.flags.include?(:isdir) and (event.flags & [:close, :modify]).any?
93
56
  )
94
57
  # Skip all of these!
95
58
  next
96
59
  end
97
60
 
98
- @mutex.synchronize do
99
- @changed_dirs << File.dirname(event.absolute_name)
61
+ mutex.synchronize do
62
+ @changed_directories << File.dirname(event.absolute_name)
100
63
  end
101
64
  end
102
65
 
103
66
  INotify::Notifier.new.tap do |worker|
104
- @directories.each do |directory|
105
- worker.watch(directory, *EVENTS.map(&:to_sym), &callback)
106
- end
67
+ directories.each { |dir| worker.watch(dir, *EVENTS, &callback) }
107
68
  end
108
69
  end
109
70
 
71
+ # Starts the worker in a new thread.
72
+ #
73
+ # @see Listen::Adapter#start_worker
74
+ #
75
+ def start_worker
76
+ @worker_thread = Thread.new { worker.run }
77
+ end
110
78
  end
111
79
 
112
80
  end
@@ -1,66 +1,57 @@
1
1
  module Listen
2
2
  module Adapters
3
3
 
4
- # The default delay between checking for changes.
5
4
  DEFAULT_POLLING_LATENCY = 1.0
6
5
 
7
6
  # Polling Adapter that works cross-platform and
8
7
  # has no dependencies. This is the adapter that
9
8
  # uses the most CPU processing power and has higher
10
- # file IO that the other implementations.
9
+ # file IO than the other implementations.
11
10
  #
12
11
  class Polling < Adapter
13
- extend DependencyManager
12
+ private
14
13
 
15
- # Initialize the Adapter. See {Listen::Adapter#initialize} for more info.
14
+ # The default delay between checking for changes.
16
15
  #
17
- def initialize(directories, options = {}, &callback)
18
- @latency ||= DEFAULT_POLLING_LATENCY
19
- super
16
+ # @see Listen::Adapter#default_latency
17
+ #
18
+ def default_latency
19
+ 1.0
20
20
  end
21
21
 
22
- # Start the adapter.
22
+ # The thread on which the main thread should wait
23
+ # when the adapter has been started in blocking mode.
23
24
  #
24
- # @param [Boolean] blocking whether or not to block the current thread after starting
25
+ # @see Listen::Adapter#blocking_thread
25
26
  #
26
- def start(blocking = true)
27
- @mutex.synchronize do
28
- return if @stop == false
29
- super
30
- end
31
-
32
- @poll_thread = Thread.new { poll }
33
- @poll_thread.join if blocking
27
+ def blocking_thread
28
+ poller_thread
34
29
  end
35
30
 
36
- # Stop the adapter.
31
+ # @see Listen::Adapter#start_worker
37
32
  #
38
- def stop
39
- @mutex.synchronize do
40
- return if @stop == true
41
- super
42
- end
43
-
44
- @poll_thread.join
33
+ # @see Listen::Adapter#start_worker
34
+ #
35
+ def start_worker
36
+ # The polling adapter has no worker! Sad panda! :'(
45
37
  end
46
38
 
47
- private
48
-
49
39
  # Poll listener directory for file system changes.
50
40
  #
51
- def poll
52
- until @stop
53
- next if @paused
41
+ # @see Listen::Adapter#poll_changed_directories
42
+ #
43
+ def poll_changed_directories
44
+ until stopped
45
+ next if paused
54
46
 
55
47
  start = Time.now.to_f
56
- @callback.call(@directories.dup, :recursive => true)
57
- @turnstile.signal
58
- nap_time = @latency - (Time.now.to_f - start)
48
+ callback.call(directories.dup, :recursive => true)
49
+ turnstile.signal
50
+ nap_time = latency - (Time.now.to_f - start)
59
51
  sleep(nap_time) if nap_time > 0
60
52
  end
61
53
  rescue Interrupt
62
54
  end
63
-
64
55
  end
65
56
 
66
57
  end
@@ -1,4 +1,5 @@
1
1
  require 'set'
2
+ require 'rubygems'
2
3
 
3
4
  module Listen
4
5
  module Adapters
@@ -6,81 +7,84 @@ module Listen
6
7
  # Adapter implementation for Windows `wdm`.
7
8
  #
8
9
  class Windows < Adapter
9
- extend DependencyManager
10
10
 
11
- # Declare the adapter's dependencies
12
- dependency 'wdm', '~> 0.1'
11
+ BUNDLER_DECLARE_GEM = <<-EOS.gsub(/^ {6}/, '')
12
+ Please add the following to your Gemfile to avoid polling for changes:
13
+ require 'rbconfig'
14
+ gem 'wdm', '>= 0.1.0' if RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
15
+ EOS
13
16
 
14
- # Initializes the Adapter. See {Listen::Adapter#initialize} for more info.
17
+ def self.target_os_regex; /mswin|mingw/i; end
18
+ def self.adapter_gem; 'wdm'; end
19
+
20
+ # Checks if the adapter is usable on target OS.
15
21
  #
16
- def initialize(directories, options = {}, &callback)
17
- super
18
- @worker = init_worker
22
+ # @return [Boolean] whether usable or not
23
+ #
24
+ def self.usable?
25
+ super if mri? && at_least_ruby_1_9?
19
26
  end
20
27
 
21
- # Starts the adapter.
28
+ # Load the adapter gem
22
29
  #
23
- # @param [Boolean] blocking whether or not to block the current thread after starting
30
+ # @return [Boolean] whether required or not
24
31
  #
25
- def start(blocking = true)
26
- @mutex.synchronize do
27
- return if @stop == false
28
- super
29
- end
30
-
31
- @worker_thread = Thread.new { @worker.run! }
32
-
33
- # Wait for the worker to start. This is needed to avoid a deadlock
34
- # when stopping immediately after starting.
35
- sleep 0.1
36
-
37
- @poll_thread = Thread.new { poll_changed_dirs } if @report_changes
38
-
39
- @worker_thread.join if blocking
32
+ def self.load_dependency
33
+ super
34
+ rescue Gem::LoadError
35
+ Kernel.warn BUNDLER_DECLARE_GEM
40
36
  end
41
37
 
42
- # Stops the adapter.
43
- #
44
- def stop
45
- @mutex.synchronize do
46
- return if @stop == true
47
- super
48
- end
38
+ private
49
39
 
50
- @worker.stop
51
- @worker_thread.join if @worker_thread
52
- @poll_thread.join if @poll_thread
40
+ # Checks if Ruby engine is MRI.
41
+ #
42
+ # @return [Boolean]
43
+ #
44
+ def self.mri?
45
+ defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby'
53
46
  end
54
47
 
55
- # Checks if the adapter is usable on the current OS.
48
+ # Checks if Ruby engine is MRI.
56
49
  #
57
- # @return [Boolean] whether usable or not
50
+ # @return [Boolean]
58
51
  #
59
- def self.usable?
60
- return false unless RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
61
- super
52
+ def self.at_least_ruby_1_9?
53
+ Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('1.9.2')
62
54
  end
63
55
 
64
- private
65
-
66
56
  # Initializes a WDM monitor and adds a watcher for
67
57
  # each directory passed to the adapter.
68
58
  #
69
59
  # @return [WDM::Monitor] initialized worker
70
60
  #
71
- def init_worker
61
+ # @see Listen::Adapter#initialize_worker
62
+ #
63
+ def initialize_worker
72
64
  callback = Proc.new do |change|
73
- next if @paused
74
- @mutex.synchronize do
75
- @changed_dirs << File.dirname(change.path)
65
+ next if paused
66
+
67
+ mutex.synchronize do
68
+ @changed_directories << File.dirname(change.path)
76
69
  end
77
70
  end
78
71
 
79
72
  WDM::Monitor.new.tap do |worker|
80
- @directories.each { |d| worker.watch_recursively(d, &callback) }
73
+ directories.each { |dir| worker.watch_recursively(dir, &callback) }
81
74
  end
82
75
  end
83
76
 
77
+ # Start the worker in a new thread and sleep 0.1 second.
78
+ #
79
+ # @see Listen::Adapter#start_worker
80
+ #
81
+ def start_worker
82
+ @worker_thread = Thread.new { worker.run! }
83
+ # Wait for the worker to start. This is needed to avoid a deadlock
84
+ # when stopping immediately after starting.
85
+ sleep 0.1
86
+ end
87
+
84
88
  end
85
89
 
86
90
  end