Class: DirectoryWatcher::EmScanner
- Defined in:
- lib/directory_watcher/em_scanner.rb
Overview
The EmScanner uses the EventMachine reactor loop to monitor changes to files in the watched directory. This scanner is more efficient than the pure Ruby scanner because it relies on the operating system kernel notifictions instead of a periodic polling and stat of every file in the watched directory (the technique used by the Scanner class).
EventMachine cannot notify us when a file is added to the watched directory; therefore, added files are only picked up when we apply the glob pattern to the directory. This is done at the configured interval.
Notes:
* Kqueue does not generate notifications when "touch" is used to update
a file's timestamp. This applies to Mac and BSD systems.
* New files are detected only when the watched directory is polled at the
configured interval.
Defined Under Namespace
Classes: Watcher
Instance Attribute Summary
Attributes inherited from Scanner
#files, #glob, #interval, #stable
Instance Method Summary collapse
-
#_event!(watcher) ⇒ Object
:stopdoc:.
-
#initialize(&block) ⇒ EmScanner
constructor
call-seq: EmScanner.new { |events| block }.
-
#join(limit = nil) ⇒ Object
call-seq: join( limit = nil ).
-
#running? ⇒ Boolean
Returns
true
if the scanner is currently running. -
#start ⇒ Object
Start the EventMachine scanner.
-
#stop ⇒ Object
Stop the EventMachine scanner.
Methods inherited from Scanner
Constructor Details
#initialize(&block) ⇒ EmScanner
call-seq:
EmScanner.new { |events| block }
Create an EventMachine based scanner that will generate file events and pass those events (as an array) to the given block.
39 40 41 42 43 44 |
# File 'lib/directory_watcher/em_scanner.rb', line 39 def initialize( &block ) super(&block) @timer = nil @run_loop = lambda {_run_loop} @watchers = {} end |
Instance Method Details
#_event!(watcher) ⇒ Object
:stopdoc:
This callback is invoked by a Watcher instance when some event has occured on the file. The scanner determines if the file has been modified or deleted and notifies the directory watcher accordingly.
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/directory_watcher/em_scanner.rb', line 113 def _event!( watcher ) fn = watcher.path stat = watcher.stat if stat _watch_file fn unless watcher.active? @files[fn] = stat @events << ::DirectoryWatcher::Event.new(:modified, fn) else if watcher.active? watcher.stop_watching @watchers.delete fn end @files.delete fn @events << ::DirectoryWatcher::Event.new(:removed, fn) end notify end |
#join(limit = nil) ⇒ Object
call-seq:
join( limit = nil )
This is a no-op method for the EventMachine file scanner.
104 105 |
# File 'lib/directory_watcher/em_scanner.rb', line 104 def join( limit = nil ) end |
#running? ⇒ Boolean
Returns true
if the scanner is currently running. Returns false
if this is not the case.
49 50 51 |
# File 'lib/directory_watcher/em_scanner.rb', line 49 def running? !@timer.nil? end |
#start ⇒ Object
Start the EventMachine scanner. If the scanner has already been started this method will return without taking any action.
If the EventMachine reactor is not running, it will be started by this method.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/directory_watcher/em_scanner.rb', line 59 def start return if running? unless EventMachine.reactor_running? @thread = Thread.new {EventMachine.run} Thread.pass until EventMachine.reactor_running? end @files.keys.each do |fn| if test ?e, fn _watch_file fn next end @files.delete fn @events << ::DirectoryWatcher::Event.new(:removed, fn) end _run_loop end |
#stop ⇒ Object
Stop the EventMachine scanner. If the scanner is already stopped this method will return without taking any action.
The EventMachine reactor will not be stopped by this method. It is up to the user to stop the reactor using the EventMachine#stop_event_loop method.
87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/directory_watcher/em_scanner.rb', line 87 def stop return unless running? EventMachine.cancel_timer @timer rescue nil @timer = nil @watchers.each_value {|w| w.stop_watching if w.active?} @watchers.clear notify end |