diff --git a/Guardfile b/Guardfile
index 6f5fb755..4433f010 100644
--- a/Guardfile
+++ b/Guardfile
@@ -1,4 +1,4 @@
-guard 'rspec', :cli => "-c -f doc" do
+guard 'rspec', :version => 2 do
watch(%r{^spec/.+_spec\.rb})
watch(%r{^lib/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
diff --git a/README.rdoc b/README.rdoc
index 3e4a837c..0ef28b35 100644
--- a/README.rdoc
+++ b/README.rdoc
@@ -77,6 +77,7 @@ Former :color, :drb, :fail_fast and :formatter false # don't display Growl (or Libnotify) notification after the specs are done running, default: true
:all_after_pass => false # don't run all specs after changed specs pass, default: true
:all_on_start => false # don't run all the specs at startup, default: true
+ :keep_failed => true # keep failed specs untill them pass (useful with {:focus RSpec option}[http://relishapp.com/rspec/rspec-core/v/2-6-rc/dir/filtering/inclusion-filters]), default: true
== Notification
diff --git a/lib/guard/rspec.rb b/lib/guard/rspec.rb
index 3a022810..d7997a9a 100644
--- a/lib/guard/rspec.rb
+++ b/lib/guard/rspec.rb
@@ -3,41 +3,50 @@
module Guard
class RSpec < Guard
-
autoload :Runner, 'guard/rspec/runner'
autoload :Inspector, 'guard/rspec/inspector'
def initialize(watchers=[], options={})
super
- @all_after_pass = options.delete(:all_after_pass)
- @all_on_start = options.delete(:all_on_start)
+ @options = {
+ :all_after_pass => true,
+ :all_on_start => true,
+ :keep_failed => true
+ }.update(options)
+ @last_failed = false
+ @failed_paths = []
+
Runner.set_rspec_version(options)
end
# Call once when guard starts
def start
UI.info "Guard::RSpec is running, with RSpec #{Runner.rspec_version}!"
- run_all unless @all_on_start == false
+ run_all if @options[:all_on_start]
end
def run_all
- @last_failed = !Runner.run(["spec"], options.merge(:message => "Running all specs"))
+ passed = Runner.run(["spec"], options.merge(:message => "Running all specs"))
+
+ @failed_paths = [] if passed
+ @last_failed = !passed
end
def run_on_change(paths)
paths = Inspector.clean(paths)
- passed = Runner.run(paths, options)
+ paths += @failed_paths if @options[:keep_failed]
+ passed = Runner.run(paths.uniq, options)
- if @all_after_pass == false
- passed
- else
+ if passed
+ # clean failed paths memory
+ @failed_paths -= paths if @options[:keep_failed]
# run all the specs if the changed specs failed, like autotest
- if passed && @last_failed
- run_all
- else
- # track whether the changed specs failed for the next change
- @last_failed = !passed
- end
+ run_all if @last_failed && @options[:all_after_pass]
+ else
+ # remember failed paths for the next change
+ @failed_paths += paths if @options[:keep_failed]
+ # track whether the changed specs failed for the next change
+ @last_failed = true
end
end
diff --git a/spec/guard/rspec_spec.rb b/spec/guard/rspec_spec.rb
index 6aa4e2b4..9b2b8bf8 100644
--- a/spec/guard/rspec_spec.rb
+++ b/spec/guard/rspec_spec.rb
@@ -1,6 +1,7 @@
require 'spec_helper'
describe Guard::RSpec do
+ let(:default_options) { { :all_after_pass => true, :all_on_start => true, :keep_failed => true } }
subject { Guard::RSpec.new }
describe '#initialize' do
@@ -12,12 +13,12 @@
describe "#start" do
it "calls #run_all" do
- Guard::RSpec::Runner.should_receive(:run).with(["spec"], :message => "Running all specs")
+ Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options.merge(:message => "Running all specs"))
subject.start
end
it "doesn't call #run_all if the :all_on_start option is false" do
- Guard::RSpec::Runner.should_not_receive(:run).with(["spec"], :message => "Running all specs")
+ Guard::RSpec::Runner.should_not_receive(:run).with(["spec"], default_options.merge(:all_on_start => false, :message => "Running all specs"))
subject = Guard::RSpec.new([], :all_on_start => false)
subject.start
end
@@ -25,48 +26,67 @@
describe "#run_all" do
it "runs all specs" do
- Guard::RSpec::Runner.should_receive(:run).with(["spec"], :message => "Running all specs")
+ Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options.merge(:message => "Running all specs"))
subject.run_all
end
it "directly passes :cli option to runner" do
subject = Guard::RSpec.new([], { :cli => "--color" })
- Guard::RSpec::Runner.should_receive(:run).with(["spec"], :message => "Running all specs", :cli => "--color")
+ Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options.merge(:message => "Running all specs", :cli => "--color"))
subject.run_all
end
+
+ it "should clean failed memory if passed" do
+ Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], default_options).and_return(false)
+ subject.run_on_change(["spec/foo"])
+ Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options.merge(:message => "Running all specs")).and_return(true)
+ subject.run_all
+ Guard::RSpec::Runner.should_receive(:run).with(["spec/bar"], default_options).and_return(true)
+ subject.run_on_change(["spec/bar"])
+ end
end
describe "#run_on_change" do
it "runs rspec with paths" do
- Guard::RSpec::Runner.should_receive(:run).with(["spec"], {})
+ Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options)
subject.run_on_change(["spec"])
end
it "directly passes :cli option to runner" do
subject = Guard::RSpec.new([], { :cli => "--color" })
- Guard::RSpec::Runner.should_receive(:run).with(["spec"], :cli => "--color")
+ Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options.merge(:cli => "--color"))
subject.run_on_change(["spec"])
end
it "calls #run_all if the changed specs pass after failing" do
- Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], {}).and_return(false, true)
- Guard::RSpec::Runner.should_receive(:run).with(["spec"], :message => "Running all specs")
+ Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], default_options).and_return(false, true)
+ Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options.merge(:message => "Running all specs"))
subject.run_on_change(["spec/foo"])
subject.run_on_change(["spec/foo"])
end
it "doesn't call #run_all if the changed specs pass after failing but the :all_after_pass option is false" do
subject = Guard::RSpec.new([], :all_after_pass => false)
- Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], {}).and_return(false, true)
- Guard::RSpec::Runner.should_not_receive(:run).with(["spec"], :message => "Running all specs")
+ Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], default_options.merge(:all_after_pass => false)).and_return(false, true)
+ Guard::RSpec::Runner.should_not_receive(:run).with(["spec"], default_options.merge(:all_after_pass => false, :message => "Running all specs"))
subject.run_on_change(["spec/foo"])
subject.run_on_change(["spec/foo"])
end
it "doesn't call #run_all if the changed specs pass without failing" do
- Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], {}).and_return(true)
- Guard::RSpec::Runner.should_not_receive(:run).with(["spec"], :message => "Running all specs")
+ Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], default_options).and_return(true)
+ Guard::RSpec::Runner.should_not_receive(:run).with(["spec"], default_options.merge(:message => "Running all specs"))
+ subject.run_on_change(["spec/foo"])
+ end
+
+ it "should keep failed spec and rerun later" do
+ Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], default_options).and_return(false)
subject.run_on_change(["spec/foo"])
+ Guard::RSpec::Runner.should_receive(:run).with(["spec/bar", "spec/foo"], default_options).and_return(true)
+ Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options.merge(:message => "Running all specs")).and_return(true)
+ subject.run_on_change(["spec/bar"])
+ Guard::RSpec::Runner.should_receive(:run).with(["spec/bar"], default_options).and_return(true)
+ subject.run_on_change(["spec/bar"])
end
end