class DirectoryWatcher::EventableScanner

An Eventable Scanner is one that can be utilized by something that has an Event Loop. It is intended to be subclassed by classes that implement the specific event loop semantics for say EventMachine or Cool.io.

The Events that the EventableScanner is programmed for are:

#on_scan - this should be called every interval times #on_modified - If the event loop can monitor individual files then this should

be called when the file is modified

#on_removed - Similar to #on_modified but called when a file is removed.

Sub classes are required to implement the following:

start_loop_with_attached_scan_timer() - Instance Method
  This method is to start up the loop, if necessary assign to @loop_thread
  instance variable the Thread that is controlling the event loop.

  This method must also assign an object to @timer which is what does the
  periodic scanning of the globs. This object must respond to +detach()+ so
  that it may be detached from the event loop.

stop_loop() - Instance Method
  This method must shut down the event loop, or detach these classes from
  the event loop if we just attached to an existing event loop.

Watcher - An Embedded class
  This is a class that must have a class method +watcher(path,scanner)+
  which is used to instantiate a file watcher. The Watcher instance must
  respond to +detach()+ so that it may be independently detached from the
  event loop.

Attributes

iterations[R]
maximum_iterations[R]
watchers[R]

A Hash of Watcher objects.

Public Class Methods

new( config ) click to toggle source

config - the Configuration instances

# File lib/directory_watcher/eventable_scanner.rb, line 43
def initialize( config )
  @config = config
  @scan_and_queue = DirectoryWatcher::ScanAndQueue.new(config.glob, config.collection_queue)
  @watchers = {}
  @stopping = false
  @timer = nil
  @loop_thread = nil
  @paused = false
end

Public Instance Methods

collection_queue() click to toggle source

The queue on which to put FileStat and Scan items.

# File lib/directory_watcher/eventable_scanner.rb, line 55
def collection_queue
  @config.collection_queue
end
finished_iterations?() click to toggle source

Have we completed up to the #maximum_iterations?

# File lib/directory_watcher/eventable_scanner.rb, line 146
def finished_iterations?
  self.iterations >= self.maximum_iterations
end
interval() click to toggle source

The interval at which to scan

# File lib/directory_watcher/eventable_scanner.rb, line 61
def interval
  @config.interval
end
join( limit = nil ) click to toggle source

EventableScanners do not join

# File lib/directory_watcher/eventable_scanner.rb, line 119
def join( limit = nil )
end
maximum_iterations=(value) click to toggle source

Setting maximum iterations means hooking into the periodic timer event and counting the number of times it is going on. This also resets the current iterations count

# File lib/directory_watcher/eventable_scanner.rb, line 133
def maximum_iterations=(value)
  unless value.nil?
    value = Integer(value)
    raise ArgumentError, "maximum iterations must be >= 1" unless value >= 1
  end
  @iterations = 0
  @maximum_iterations = value
end
on_modified(watcher, new_stat) click to toggle source

This callback is invoked by the Watcher instance when it is triggered by the loop for file modifications.

# File lib/directory_watcher/eventable_scanner.rb, line 163
def on_modified(watcher, new_stat)
  logger.debug "on_modified called"
  queue_item(new_stat)
end
on_removed(watcher, new_stat) click to toggle source

This callback is invoked by the Watcher instance when it is triggered by the loop for file removals

# File lib/directory_watcher/eventable_scanner.rb, line 171
def on_removed(watcher, new_stat)
  logger.debug "on_removed called"
  unwatch_file(watcher.path)
  queue_item(new_stat)
end
on_scan() click to toggle source

This callback is invoked by the Timer instance when it is triggered by the Loop. This method will check for added files and stable files and notify the directory watcher accordingly.

# File lib/directory_watcher/eventable_scanner.rb, line 154
def on_scan
  logger.debug "on_scan called"
  scan_and_watch_files
  progress_towards_maximum_iterations
end
pause() click to toggle source

Pause the scanner.

Pausing the scanner does not stop the scanning per se, it stops items from being sent to the collection queue

# File lib/directory_watcher/eventable_scanner.rb, line 97
def pause
  logger.debug "pausing scanner"
  @paused = true
end
paused?() click to toggle source

Is the Scanner currently paused.

# File lib/directory_watcher/eventable_scanner.rb, line 113
def paused?
  @paused
end
resume() click to toggle source

Resume the scanner.

This removes the blockage on sending items to the collection queue.

# File lib/directory_watcher/eventable_scanner.rb, line 106
def resume
  logger.debug "resuming scanner"
  @paused = false
end
run() click to toggle source

Do a single scan and send those items to the collection queue.

# File lib/directory_watcher/eventable_scanner.rb, line 124
def run
  logger.debug "running scan and queue"
  @scan_and_queue.scan_and_queue
end
running?() click to toggle source

Returns true if the scanner is currently running. Returns false if this is not the case.

# File lib/directory_watcher/eventable_scanner.rb, line 68
def running?
  return !@stopping if @timer
  return false
end
start() click to toggle source

Start up the scanner. If the scanner is already running, nothing happens.

# File lib/directory_watcher/eventable_scanner.rb, line 75
def start
  return if running?
  logger.debug "starting scanner"
  start_loop_with_attached_scan_timer
end
stop() click to toggle source

Stop the scanner. If the scanner is not running, nothing happens.

# File lib/directory_watcher/eventable_scanner.rb, line 83
def stop
  return unless running?
  logger.debug "stoping scanner"
  @stopping = true
  teardown_timer_and_watches
  @stopping = false
  stop_loop
end

Private Instance Methods

progress_towards_maximum_iterations() click to toggle source

Make progress towards maximum iterations. And if we get there, then stop monitoring files.

# File lib/directory_watcher/eventable_scanner.rb, line 235
def progress_towards_maximum_iterations
  if maximum_iterations then
    @iterations += 1
    stop if finished_iterations?
  end
end
queue_item( item ) click to toggle source

Send the given item to the collection queue

# File lib/directory_watcher/eventable_scanner.rb, line 183
def queue_item( item )
  if paused? then
    logger.debug "Not queueing item, we're paused"
  else
    logger.debug "enqueuing #{item} to #{collection_queue}"
    collection_queue.enq item
  end
end
scan_and_watch_files() click to toggle source

Run a single scan and turn on watches for all the files found in that scan that do not already have watchers on them.

# File lib/directory_watcher/eventable_scanner.rb, line 196
def scan_and_watch_files
  logger.debug "scanning and watching files"
  scan = @scan_and_queue.scan_and_queue
  scan.results.each do |stat|
    watch_file(stat.path)
  end
end
teardown_timer_and_watches() click to toggle source

Remove the timer and the watches from the event loop

# File lib/directory_watcher/eventable_scanner.rb, line 206
def teardown_timer_and_watches
  @timer.detach rescue nil
  @timer = nil

  @watchers.each_value {|w| w.detach}
  @watchers.clear
end
unwatch_file( fn ) click to toggle source

Remove the watcher instance from our tracking

# File lib/directory_watcher/eventable_scanner.rb, line 227
def unwatch_file( fn )
  logger.debug "Unwatching file #{fn}"
  @watchers.delete(fn)
end
watch_file( fn ) click to toggle source

Create and return a new Watcher instance for the given filename fn. A watcher will only be created once for a particular fn.

# File lib/directory_watcher/eventable_scanner.rb, line 217
def watch_file( fn )
  unless @watchers[fn] then
    logger.debug "Watching file #{fn}"
    w = self.class::Watcher.watch(fn, self)
    @watchers[fn] = w
  end
end