class Snooper::Snoop

Public: Watches over a directory, executing a comand when files change

The fine-grained behaviour of this class is controlled by the parameters passed to the new method.

Public Class Methods

new(config) click to toggle source

Public: Create a new source code spy

config - The String containing the path to the config or a Snooper::Config

like object. If the path is a directory and not a file then
default config names are searched for in the direcory.
# File lib/snooper/snoop.rb, line 25
def initialize(config)
  case config
  when String
    @config = Snooper::Config.load config
  else
    @config = config
  end
end

Public Instance Methods

do_listening() click to toggle source

Internal : Do the Filesystem Listening

This function blocks while it listens to the filsystem for changes. When the lisetner terminates it returns the listener's status

Returns the result of the listener

# File lib/snooper/snoop.rb, line 195
def do_listening
  in_dir @config.base_path do

    # Notify people if we are using fallback mode
    if @config.force_poll
      puts statusbar "Using polling fallback listener", &:yellow
    end

    # Force a change to start with
    run_command

    params = {
      latency: 0.5,
    }

    params[:only] = Regexp.new(@config.filters.join("|")) unless @config.filters.empty?
    params[:ignore] = Regexp.new(@config.ignored.join("|")) unless @config.ignored.empty?

    if @config.force_poll
      params[:latency] = @config.force_poll
      params[:force_poll] = true
    end

    @listener = Listen.to(*@config.paths, params) do |*args|
      self.on_change *args
    end
    
    @listener.start
  end
end
in_dir(directory) { |block| ... } click to toggle source

Internal: Run a block in a dir

direcotry - The String containing the path to change to block - The block to run

Returns the result of the block's execution.

# File lib/snooper/snoop.rb, line 57
def in_dir(directory, &block)
  old_dir = File.expand_path '.'
  Dir.chdir directory if directory
  r = yield block
  Dir.chdir old_dir
  r
end
on_change(modified, added, removed) click to toggle source

Internal: Change callback

Called when a filesystem change is detected by listen. Runs the command passed to t he constructor and prints a summary of the output.

modified - The Array of paths that were modified since the last change added - The Array of paths that were added since the last change removed - The Array of paths that were removed since the last change

Raises nothing.

Returns nothing.

# File lib/snooper/snoop.rb, line 78
def on_change(modified, added, removed)
  # Puase the listener to avoid spurious triggers from build output
  @listener.pause if @listener
  
  # summarise the changes made
  changes = modified + added + removed
  
  statusline = ('-' * removed.length).red
  statusline << ('.' * modified.length).blue
  statusline << ('+' * added.length).green
  puts "#{statusline} #{changes.length.to_s.magenta.bold} changes"
  
  @config.hooks.each do |hook|
    hook.run changes
  end

  run_command
  
  # return to listening
  @listener.unpause if @listener
rescue Exception => e
  puts e.message
  puts e.backtrace
end
run() click to toggle source

Public: Main run loop

Registers for filesystem notifications and dispatches them to the on_change handler. This method also forces a dummy update to ensure that tests are run when watching begins.

Returns the result of the listener

# File lib/snooper/snoop.rb, line 159
def run
  evq = Queue.new

  if @config.file_path
    dir = File.dirname @config.file_path
    filter = %r{#{File.basename @config.file_path}$}
    @cfg_listener = Listen.to dir do |*args|
      next unless args.reduce(&:+).include? @config.file_path
      if @listener
        puts statusbar "Re-loading Config File...", &:yellow
        @listener.stop
        evq.push true
      end
    end
    @cfg_listener.start
  end

  # on C-c tell all listeners to stop
  Signal.trap "INT", "DEFAULT"

  # loop forever listening, each time the above block causes the listener
  # to stop it will re-start listening with the new config.
  while true
    do_listening
    break unless evq.pop
    @config.reload
  end
end
run_command() click to toggle source

Internal: Run command and print the result

Return result of the command

# File lib/snooper/snoop.rb, line 107
def run_command
  # run the test suite and check the result
  res, time = time_command @config.command
  if res then
    puts statusbar "✓ All tests passed", time, &:white_on_green
  else
    puts statusbar "✗ Tests failed", time, &:white_on_red
  end
  res
end
statusbar(message, time=nil) { |message| ... } click to toggle source

Internal: Prettify a status line

Prints the message at the center of the line, automatically detected from the terminal info. If a block is supplied then the resulting message is post-filtered by it before being returned.

message - the message to print

Yields the String that has been aligned to the terminal width.

Returns the prettified String.

# File lib/snooper/snoop.rb, line 145
def statusbar(message, time=nil)
  message << " (#{time.round(3)}s)" if time
  message = message.to_s.center term_width
  block_given? ? yield(message) : message
end
term_width() click to toggle source
Internal: Get the Terminal Width

Returns the width of the terminal, if one is connected, in characters

# File lib/snooper/snoop.rb, line 123
def term_width
  return @@terminal_width unless @terminal_width == nil
  begin
    require 'terminfo'
    @@terminal_width = TermInfo.screen_width - 1
  rescue
    @@terminal_width = 79
  end
end
time_command(command) click to toggle source

Internal: Time Command

Run a command and time how long it takes. The exit status of the command and the time taken to run the command are both returned.

command - The command to run

Returns the result of the command and the time taken to run it, in seconds

# File lib/snooper/snoop.rb, line 43
def time_command(command)
  before = Time.new
  result = system command
  after = Time.new
  return result, after - before
end