#!/usr/bin/env ruby require 'rspactor' Growl = RSpactor::Growl root = ENV['HOME'] $mappings = [] $libs = [] def map(regex, &block) $mappings << [regex, block] end def libs $libs end def title $title end listener = RSpactor::Listener.new do |changed_files| changed_files.reject! do |file| file.index(root + "/Library/") == 0 end if changed_files.size == 1 changed_file = changed_files.first dir = changed_file hook = nil until hook or (dir = File.dirname(dir)) == root candidate = dir + "/.rspactor" hook = candidate if File.exists?(candidate) end if hook targets = [] $title = "Test results" $mappings.clear $libs.replace ['lib'] load hook unless $mappings.empty? relative_path = changed_file.sub(dir + '/', '') for regex, block in $mappings if match = relative_path.match(regex) targets.concat Array(block.call(relative_path, match)) break end end existing_targets = targets.select { |file| File.exist?(File.join(dir, file)) } else inspector = RSpactor::Inspector.new(dir) existing_targets = inspector.determine_spec_files(changed_file) end unless existing_targets.empty? case existing_targets.first when %r{^test/} $libs << 'test' when %r{^spec/} $libs << 'spec' end Dir.chdir(dir) do unless 'spec' == $libs.last command = "ruby -I#{$libs.join(':')} -e 'ARGV.each{|f| load f}' " else command = "RUBYOPT='-I#{$libs.join(':')}' spec --color " end command << existing_targets.join(' ') # puts command system command end if $?.success? Growl::notify $title, "You rock!", Growl::image_path('success') else Growl::notify $title, "YOU LOSE", Growl::image_path('failed') end else $stderr.puts "-- don't know how to run #{changed_file}" end end end end listener.run(root)