diff --git a/lib/guard.rb b/lib/guard.rb index d9ed364..0f443a6 100644 --- a/lib/guard.rb +++ b/lib/guard.rb @@ -39,7 +39,13 @@ module Guard end UI.info "Guard is now watching at '#{Dir.pwd}'" - guards.each { |g| supervised_task(g, :start) } + guards.each do |guard| + if supervised_task(guard, :start) + (guard.class.instance_methods(false) | ::Guard::Guard.instance_methods(false)).each do |m| + guard.send(:"#{$1}") if m.to_s =~ /^(.+)_at_start\?$/ && guard.send(:"#{$1}_at_start?") + end + end + end listener.start end end @@ -63,7 +69,11 @@ module Guard # Let a guard execute his task but # fire it if his work lead to system failure def supervised_task(guard, task_to_supervise, *args) - guard.send(task_to_supervise, *args) + if !guard.respond_to(:"#{task_to_supervise}?") || guard.send(:"#{task_to_supervise}?") + guard.send(task_to_supervise, *args) + else + false + end rescue Exception UI.error("#{guard.class.name} guard failed to achieve its <#{task_to_supervise.to_s}> command: #{$!}") ::Guard.guards.delete guard diff --git a/lib/guard/guard.rb b/lib/guard/guard.rb index f205a1d..e3e00c9 100644 --- a/lib/guard/guard.rb +++ b/lib/guard/guard.rb @@ -1,9 +1,14 @@ module Guard class Guard attr_accessor :watchers, :options + + DEFAULT_OPTIONS = { + :reload => {:at_start => false, :disable => false}, + :run_all => {:at_start => false, :disable => false} + }.freeze def initialize(watchers = [], options = {}) - @watchers, @options = watchers, options + @watchers, @options = watchers, DEFAULT_OPTIONS.merge(options) end # Guardfile template needed inside guard gem @@ -41,11 +46,31 @@ module Guard def reload true end + + # disable reload method if return true. When is overwriten, must return false if `super' return false + def reload? + options[:reload] == true || (options[:reload].is_a?(Hash) && !options[:reload][:disable]) + end + + # enable call of reload method after start method if return true. When is overwriten, must return false if `super' return false + def reload_at_start? + options[:reload].is_a?(Hash) && !!options[:reload][:at_start] + end # Should be principally used for long action like running all specs/tests/... def run_all true end + + # disable run_all method if return true. When is overwriten, must return false if `super' return false + def run_all? + options[:run_all] == true || (options[:run_all].is_a?(Hash) && !options[:run_all][:disable]) + end + + # enable call of run_all method after start method if return true. When is overwriten, must return false if `super' return false + def run_all_at_start? + options[:run_all].is_a?(Hash) && !!options[:run_all][:at_start] + end def run_on_change(paths) true diff --git a/spec/guard/guard_spec.rb b/spec/guard/guard_spec.rb new file mode 100644 index 0000000..29aade9 --- /dev/null +++ b/spec/guard/guard_spec.rb @@ -0,0 +1,152 @@ +require 'spec_helper' +require 'guard/guard' + +describe Guard::Guard do + subject { Guard::Guard } + + it "should be initialized with watchers" do + watcher = mock(Guard::Watcher) + guard = subject.new([watcher]) + guard.watchers.should == [watcher] + end + + it "should be initialized with options" do + watcher = mock(Guard::Watcher) + guard = subject.new([], {:test => true}) + guard.options[:test].should be_true + guard.options[:fake].should be_nil + end + + context "#reload?" do + + it "should return true by default" do + subject.new.reload?.should be_true + end + + it "should return true with option `:reload => {:disable => false}'" do + guard = subject.new([], :reload => {:disable => false}) + guard.reload?.should be_true + end + + it "should return true with option `:reload => {}'" do + guard = subject.new([], :reload => {}) + guard.reload?.should be_true + end + + it "should return true with option `:reload => true'" do + guard = subject.new([], :reload => true) + guard.reload?.should be_true + end + + it "should return false with option `:reload => {:disable => true}'" do + guard = subject.new([], :reload => {:disable => true}) + guard.reload?.should be_false + end + + it "should return false with option `:reload => false'" do + guard = subject.new([], :reload => false) + guard.reload?.should be_false + end + + end + + context "#reload_at_start?" do + + it "should return false by default" do + subject.new.reload_at_start?.should be_false + end + + it "should return false with option `:reload => {:at_start => false}'" do + guard = subject.new([], :reload => {:at_start => false}) + guard.reload_at_start?.should be_false + end + + it "should return false with option `:reload => {}'" do + guard = subject.new([], :reload => {}) + guard.reload_at_start?.should be_false + end + + it "should return false with option `:reload => true'" do + guard = subject.new([], :reload => true) + guard.reload_at_start?.should be_false + end + + it "should return false with option `:reload => false'" do + guard = subject.new([], :reload => false) + guard.reload_at_start?.should be_false + end + + it "should return true with option `:reload => {:at_start => true}'" do + guard = subject.new([], :reload => {:at_start => true}) + guard.reload_at_start?.should be_true + end + + end + + context "#run_all?" do + + it "should return true by default" do + subject.new.run_all?.should be_true + end + + it "should return true with option `:reload => {:disable => false}'" do + guard = subject.new([], :run_all => {:disable => false}) + guard.run_all?.should be_true + end + + it "should return true with option `:reload => {}'" do + guard = subject.new([], :run_all => {}) + guard.run_all?.should be_true + end + + it "should return true with option `:reload => true'" do + guard = subject.new([], :run_all => true) + guard.run_all?.should be_true + end + + it "should return false with option `:reload => {:disable => true}'" do + guard = subject.new([], :run_all => {:disable => true}) + guard.run_all?.should be_false + end + + it "should return false with option `:reload => false'" do + guard = subject.new([], :run_all => false) + guard.run_all?.should be_false + end + + end + + context "#run_all_at_start?" do + + it "should return false by default" do + subject.new.run_all_at_start?.should be_false + end + + it "should return false with option `:reload => {:at_start => false}'" do + guard = subject.new([], :run_all => {:at_start => false}) + guard.run_all_at_start?.should be_false + end + + it "should return false with option `:reload => {}'" do + guard = subject.new([], :run_all => {}) + guard.run_all_at_start?.should be_false + end + + it "should return false with option `:reload => true'" do + guard = subject.new([], :run_all => true) + guard.run_all_at_start?.should be_false + end + + it "should return false with option `:reload => false'" do + guard = subject.new([], :run_all => false) + guard.run_all_at_start?.should be_false + end + + it "should return true with option `:reload => {:at_start => true}'" do + guard = subject.new([], :run_all => {:at_start => true}) + guard.run_all_at_start?.should be_true + end + + end + +end diff --git a/spec/guard_spec.rb b/spec/guard_spec.rb index 7e34d57..e8648e4 100644 --- a/spec/guard_spec.rb +++ b/spec/guard_spec.rb @@ -54,16 +54,87 @@ describe Guard do ::Guard.listener.should be_kind_of(Guard::Listener) end end + + describe "start" do + + before(:each) do + @guard = mock(::Guard::Guard) + @guard.stub!(:reload_at_start?).and_return(false) + @guard.stub!(:run_all_at_start?).and_return(false) + + @listener = mock(::Guard::Polling) + @listener.stub!(:on_change) + @listener.stub!(:start).and_return(true) + + ::Guard::Listener.stub!(:init).and_return(@listener) + ::Guard::Dsl.stub!(:evaluate_guardfile) + ::Guard::Interactor.stub!(:init_signal_traps) + subject.stub!(:guards).and_return([@guard]) + subject.stub!(:supervised_task).with(anything(), :start).and_return(true) + end + + it 'should evaluate Guardfile' do + ::Guard::Dsl.should_receive(:evaluate_guardfile) + subject.start + end + + it 'should init signal traps' do + ::Guard::Interactor.should_receive(:init_signal_traps) + subject.start + end + + it 'should define listener on_change' do + @listener.should_receive(:on_change) + subject.start + end + + it 'should start guards' do + subject.should_receive(:supervised_task).with(@guard, :start).and_return(true) + subject.start + end + + it 'should call method definined to run at start' do + @guard.class.stub(:instance_methods).with(false).and_return([:test, :test_at_start?]) + + @guard.should_receive(:run_all_at_start?).and_return(true) + @guard.should_receive(:run_all).and_return(true) + + @guard.should_receive(:test_at_start?).and_return(true) + @guard.should_receive(:test).and_return(true) + + subject.start + end + + it 'should not call method definined to not run at start' do + @guard.class.stub(:instance_methods).with(false).and_return([:test, :test_at_start?]) + + @guard.should_receive(:run_all_at_start?).and_return(false) + @guard.should_not_receive(:run_all) + + @guard.should_receive(:test_at_start?).and_return(false) + @guard.should_not_receive(:test) + + subject.start + end + + end describe "supervised_task" do subject { ::Guard.init } before :each do @g = mock(Guard::Guard) + @g.stub!(:respond_to).and_return { false } @g.stub!(:regular).and_return { true } @g.stub!(:spy).and_return { raise "I break your system" } @g.stub!(:pirate).and_raise Exception.new("I blow your system up") @g.stub!(:regular_arg).with("given_path").and_return { "given_path" } + @g.stub!(:enable_method).and_return { true } + @g.stub!(:enable_method?).and_return { true } + @g.stub!(:respond_to).with(:enable_method?).and_return { true } + @g.stub!(:disable_method).and_return { true } + @g.stub!(:disable_method?).and_return { false } + @g.stub!(:respond_to).with(:disable_method?).and_return { true } subject.guards.push @g end @@ -92,6 +163,19 @@ describe Guard do subject.guards.should be_include(@g) ::Guard.supervised_task(@g, :regular_arg, "given_path").should == "given_path" end + + it 'should let it go when method is enable by guard options' do + subject.guards.should be_include(@g) + subject.supervised_task(@g, :enable_method).should be_true + subject.guards.should be_include(@g) + end + + it 'should not let it go when method is disable by guard options' do + subject.guards.should be_include(@g) + subject.supervised_task(@g, :disable_method).should be_false + subject.guards.should be_include(@g) + end + end end