diff --git a/README.rdoc b/README.rdoc index c04dda4..e2d5f41 100644 --- a/README.rdoc +++ b/README.rdoc @@ -136,15 +136,16 @@ lib/guard/guard-name.rb inherit from guard/guard and should overwrite at least o # = Guard method = # ================ + # If one of those methods raise an exception, the Guard instance + # will be removed from the active guard. + # Call once when guard starts # Please override initialize method to init stuff def start true end - # Call with Ctrl-C signal (when Guard quit). - # This method must return a true value - # if everything went well or guard will not stop. + # Call with Ctrl-C signal (when Guard quit) def stop true end diff --git a/lib/guard.rb b/lib/guard.rb index 98187c9..87b692b 100644 --- a/lib/guard.rb +++ b/lib/guard.rb @@ -12,10 +12,16 @@ module Guard class << self attr_accessor :options, :guards, :listener - def start(options = {}) + # initialize this singleton + def init(options = {}) @options = options @listener = Listener.init @guards = [] + return self + end + + def start(options = {}) + init options Dsl.evaluate_guardfile if guards.empty? @@ -27,13 +33,13 @@ module Guard run do guards.each do |guard| paths = Watcher.match_files(guard, files) - guard.run_on_change(paths) unless paths.empty? + supervised_task(guard, :run_on_change, paths) unless paths.empty? end end end UI.info "Guard is now watching at '#{Dir.pwd}'" - guards.each { |g| g.start } + guards.each { |g| supervised_task(g, :start) } listener.start end end @@ -54,6 +60,19 @@ module Guard UI.error "Could not find gem 'guard-#{name}' in the current Gemfile." end + # Let a guard execute his task but + # fire it if his work lead to system failure + def supervised_task(guard, task_to_supervise, *args) + begin + guard.send(task_to_supervise, *args) + rescue Exception + UI.error("#{guard.class.name} guard failed to achieve its <#{task_to_supervise.to_s}> command: #{$!}") + ::Guard.guards.delete guard + UI.info("Guard #{guard.class.name} has just been fired") + return $! + end + end + def locate_guard(name) `gem open guard-#{name} --latest --command echo`.chomp rescue diff --git a/lib/guard/guard.rb b/lib/guard/guard.rb index 5dad41a..f205a1d 100644 --- a/lib/guard/guard.rb +++ b/lib/guard/guard.rb @@ -33,7 +33,6 @@ module Guard end # Call once when guard quit - # Retrieve a true value if the instance successfuly stopped def stop true end diff --git a/lib/guard/interactor.rb b/lib/guard/interactor.rb index 566187a..7240106 100644 --- a/lib/guard/interactor.rb +++ b/lib/guard/interactor.rb @@ -5,25 +5,22 @@ module Guard # Run all (Ctrl-\) Signal.trap('QUIT') do ::Guard.run do - ::Guard.guards.each { |g| g.run_all } + ::Guard.guards.each { |g| ::Guard.supervised_task g, :run_all } end end # Stop (Ctrl-C) Signal.trap('INT') do ::Guard.listener.stop - if ::Guard.guards.all? { |g| g.stop } - UI.info "Bye bye...", :reset => true - abort("\n") - else - ::Guard.listener.start - end + ::Guard.guards.each { |g| ::Guard.supervised_task g, :stop } + UI.info "Bye bye...", :reset => true + abort("\n") end # Reload (Ctrl-Z) Signal.trap('TSTP') do ::Guard.run do - ::Guard.guards.each { |g| g.reload } + ::Guard.guards.each { |g| ::Guard.supervised_task g, :reload } end end end diff --git a/spec/guard_spec.rb b/spec/guard_spec.rb index b90adfb..f6a3f5b 100644 --- a/spec/guard_spec.rb +++ b/spec/guard_spec.rb @@ -1,5 +1,19 @@ require 'spec_helper' +# mute UI +module Guard::UI + class << self + def info(message, options = {}) + end + + def error(message) + end + + def debug(message) + end + end +end + describe Guard do describe "get_guard_class" do @@ -20,4 +34,64 @@ describe Guard do end + describe "init" do + subject { ::Guard.init } + + it "Should retrieve itself for chaining" do + subject.should be_kind_of Module + end + + it "Should init guards array" do + ::Guard.guards.should be_kind_of Array + end + + it "Should init options" do + opts = {:my_opts => true} + ::Guard.init(opts).options.should be_include :my_opts + end + + it "Should init listeners" do + ::Guard.listener.should be_kind_of Guard::Listener + end + end + + describe "supervised_task" do + subject {::Guard.init} + + before :each do + @g = mock(Guard::Guard) + @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" } + subject.guards.push @g + end + + it "should let it go when nothing special occurs" do + subject.guards.should be_include @g + subject.supervised_task(@g, :regular).should be_true + subject.guards.should be_include @g + end + + it "should let it work with some tools" do + subject.guards.should be_include @g + subject.supervised_task(@g, :regular).should be_true + subject.guards.should be_include @g + end + + it "should fire the guard on spy act discovery" do + subject.guards.should be_include @g + ::Guard.supervised_task(@g, :spy).should be_kind_of Exception + subject.guards.should_not be_include @g + ::Guard.supervised_task(@g, :spy).message.should == 'I break your system' + end + + it "should fire the guard on pirate act discovery" do + subject.guards.should be_include @g + ::Guard.supervised_task(@g, :regular_arg, "given_path").should be_kind_of String + subject.guards.should be_include @g + ::Guard.supervised_task(@g, :regular_arg, "given_path").should == "given_path" + end + end + end