Permalink
Browse files

change Watcher.new to take an options hash; improve functional tests;…

… glob understands ** and **/
  • Loading branch information...
1 parent e3725ed commit 3a222c1c837540a266f78283d64fb078714e2803 @alexch committed Jul 2, 2012
Showing with 99 additions and 45 deletions.
  1. +2 −0 .rspec
  2. +1 −1 Rakefile
  3. +20 −0 lib/rerun/glob.rb
  4. +1 −3 lib/rerun/runner.rb
  5. +27 −23 lib/rerun/watcher.rb
  6. +15 −9 spec/functional_spec.rb
  7. +31 −1 spec/glob_spec.rb
  8. +1 −1 spec/spec_helper.rb
  9. +1 −7 spec/watcher_spec.rb
View
2 .rspec
@@ -0,0 +1,2 @@
+--color
+--format=documentation
View
2 Rakefile
@@ -10,7 +10,7 @@ desc "Run all specs"
RSpec::Core::RakeTask.new('spec') do |t|
ENV['ENV'] = "test"
t.pattern = 'spec/**/*_spec.rb'
- t.ruby_opts = ['-rubygems'] if defined? Gem
+ t.rspec_opts = ['--color']
end
$rubyforge_project = 'pivotalrb'
View
20 lib/rerun/glob.rb
@@ -12,6 +12,9 @@ def initialize glob_string
def to_regexp_string
chars = @glob_string.split('')
+
+ chars = smoosh(chars)
+
curlies = 0;
escaping = false;
chars.map do |char|
@@ -20,6 +23,8 @@ def to_regexp_string
char
else
case char
+ when '**'
+ "([^/]+/)*"
when '*'
".*"
when "?"
@@ -58,5 +63,20 @@ def to_regexp_string
def to_regexp
Regexp.new(to_regexp_string)
end
+
+ def smoosh chars
+ out = []
+ until chars.empty?
+ char = chars.shift
+ if char == "*" and chars.first == "*"
+ chars.shift
+ chars.shift if chars.first == "/"
+ out.push("**")
+ else
+ out.push(char)
+ end
+ end
+ out
+ end
end
end
View
4 lib/rerun/runner.rb
@@ -144,12 +144,10 @@ def start
unless @watcher
- watcher = Watcher.new do
+ watcher = Watcher.new(:directory => dir, :pattern => pattern) do
restart unless @restarting
end
say "Watching #{dir}/#{pattern}"
- watcher.add_directory(dir, pattern)
- watcher.sleep_time = 1
watcher.start
@watcher = watcher
end
View
50 lib/rerun/watcher.rb
@@ -13,38 +13,40 @@ class Watcher
MODIFIED = 1
DELETED = 2
- attr_accessor :sleep_time, :priority
- attr_reader :directory
-
- def initialize(&client_callback)
+ attr_reader :directory, :pattern, :priority
+
+ # Create a file system watcher. Start it by calling #start.
+ #
+ # @param options[:directory] the directory to watch (default ".")
+ # @param options[:pattern] the glob pattern to search under the watched directory (default "**/*")
+ # @param options[:priority] the priority of the watcher thread (default 0)
+ #
+ def initialize(options = {}, &client_callback)
@client_callback = client_callback
- @sleep_time = 1
- @priority = 0
+ options = {
+ :directory => ".",
+ :pattern => "**/*",
+ :priority => 0,
+ }.merge(options)
- @directory = nil
- @files = []
+ @pattern = options[:pattern]
+ @directory = options[:directory]
+ if FileTest.exists?(directory) && FileTest.readable?(directory) then
+ @directory = Directory.new(directory, @pattern)
+ else
+ raise InvalidDirectoryError, "Dir '#{directory}' either doesnt exist or isnt readable"
+ end
+ @priority = options[:priority]
@found = nil
@first_time = true
@thread = nil
-
- end
-
- # add a directory to be watched
- # @param dir the directory to watch
- # @param expression the glob pattern to search under the watched directory
- def add_directory(dir, expression="**/*")
- if FileTest.exists?(dir) && FileTest.readable?(dir) then
- @directory = Directory.new(dir, expression)
- else
- raise InvalidDirectoryError, "Dir '#{dir}' either doesnt exist or isnt readable"
- end
end
def prime
@first_time = true
- @found = Hash.new()
+ @found = {}
examine
@first_time = false
end
@@ -58,13 +60,15 @@ def start
@thread = Thread.new do
# todo: multiple dirs
+
# todo: convert each dir's pattern to a regex and get Listen to do the file scan for us
- @listener = Listen::Listener.new(@directory.dir) do |modified, added, removed|
+ regexp = Glob.new(@pattern).to_regexp
+ puts "regexp is #{regexp.inspect}"
+ @listener = Listen::Listener.new(@directory.dir, :filter => regexp) do |modified, added, removed|
#d { modified }
#d { added }
#d { removed }
examine
- sleep(@sleep_time)
end
@listener.start
end
View
24 spec/functional_spec.rb
@@ -2,7 +2,7 @@
require "#{here}/spec_helper.rb"
require 'tmpdir'
-describe "Rerun functionally" do
+describe "the rerun command" do
before do
@dir = Dir.tmpdir + "/#{Time.now.to_i}"
FileUtils.mkdir_p(@dir)
@@ -15,15 +15,16 @@
after do
# puts "Killing #{@pid}"
- Process.kill("KILL", @pid) && Process.wait(@pid)
+ Process.kill("KILL", @pid) && Process.wait(@pid) rescue Errno::ESRCH
end
def launch_inc
@pid = fork do
root = File.dirname(__FILE__) + "/.."
exec("#{root}/bin/rerun -d '#{@dir}' ruby #{root}/inc.rb #{@file}")
end
- sleep 4
+ sleep 0.5 until File.exist?(@file)
+ sleep 2 # let inc get going
end
def read
@@ -51,14 +52,14 @@ def type char
# todo: send a character to stdin of the rerun process
end
- it "counts up" do
+ it "increments a test file once per second" do
x = current_count
sleep 1
y = current_count
y.should be > x
end
- it "restarts when an app file is modified" do
+ it "restarts its target when an app file is modified" do
first_launched_at, count = read
touch @app_file
sleep 4
@@ -67,7 +68,7 @@ def type char
second_launched_at.should be > first_launched_at
end
- it "restarts when an app file is created" do
+ it "restarts its target when an app file is created" do
first_launched_at, count = read
touch @app_file2
sleep 4
@@ -76,9 +77,14 @@ def type char
second_launched_at.should be > first_launched_at
end
- it "sends its child process a SIGINT when restarting"
+ #it "sends its child process a SIGINT to restart"
- it "dies when sent a control-C (SIGINT)"
+ it "dies when sent a control-C (SIGINT)" do
+ Process.kill("INT", @pid)
+ timeout(6) {
+ Process.wait(@pid) rescue Errno::ESRCH
+ }
+ end
- it "accepts a key press"
+ #it "accepts a key press"
end
View
32 spec/glob_spec.rb
@@ -26,7 +26,7 @@ module Rerun
"\\*" => "\\*",
"\\\\" => "\\\\",
- #"**/*.txt" => "([^/]*/)*.*\\.txt"
+ "**/*.txt" => "([^/]+/)*.*\\.txt",
}.each_pair do |glob_string, regexp_string|
specify glob_string do
@@ -42,6 +42,36 @@ module Rerun
end
end
+ describe "#smoosh" do
+
+ def check_smoosh string, array
+ glob = Glob.new("")
+ glob.smoosh(string.split('')).should == array
+ end
+
+ it "ignores non-stars" do
+ check_smoosh "", []
+ check_smoosh "abc", ["a", "b", "c"]
+ end
+
+ it "passes solitary stars" do
+ check_smoosh "*", ["*"]
+ check_smoosh "a*b", ["a", "*", "b"]
+ end
+
+ it "smooshes two stars in a row into a single '**' string" do
+ check_smoosh "**", ["**"]
+ check_smoosh "a**b", ["a", "**", "b"]
+ check_smoosh "**b", ["**", "b"]
+ check_smoosh "a**", ["a", "**"]
+ end
+
+ it "treats **/ like **" do
+ check_smoosh "**/", ["**"]
+ check_smoosh "a**/b", ["a", "**", "b"]
+ end
+ end
+
end
end
View
2 spec/spec_helper.rb
@@ -2,7 +2,7 @@
require "rspec"
#require "rspec/autorun"
-require "wrong"
+require "wrong/adapters/rspec"
include Wrong::D
here = File.expand_path(File.dirname(__FILE__))
View
8 spec/watcher_spec.rb
@@ -6,20 +6,14 @@
module Rerun
describe Watcher do
- def create_watcher(&block)
- Watcher.new(&block)
- end
-
before do
@dir = Dir.tmpdir + "/#{Time.now.to_i}"
FileUtils.mkdir_p(@dir)
@log = []
- @watcher = create_watcher do |status, file|
+ @watcher = Watcher.new(:directory => @dir, :pattern => "*.txt") do |status, file|
@log << [status, file]
end
- @watcher.add_directory(@dir, "*.txt")
- @watcher.sleep_time = 0.1
@watcher.start
@test_file = "#{@dir}/test.txt"

0 comments on commit 3a222c1

Please sign in to comment.