Refactor massive execute_supervised_task_for_all_guards method.
- Renamed some Guard methods to be shorter and more consistent. - Extract methods from execute_supervised_task_for_all_guards for less complexity. - Added more specs for extracted methods. - Added more docs on how marking of deleted/moved files works. - Refactor Guard to be unaware of the :watch_all_modifications options for simplicity.
This commit is contained in:
parent
805fd174d9
commit
b64b7882f7
104
lib/guard.rb
104
lib/guard.rb
@ -33,10 +33,10 @@ module Guard
|
|||||||
@interactor = Interactor.new
|
@interactor = Interactor.new
|
||||||
@listener = Listener.select_and_init(@options[:watchdir] ? File.expand_path(@options[:watchdir]) : Dir.pwd, options)
|
@listener = Listener.select_and_init(@options[:watchdir] ? File.expand_path(@options[:watchdir]) : Dir.pwd, options)
|
||||||
|
|
||||||
@watch_all_modifications = options[:watch_all_modifications]
|
|
||||||
@options[:notify] && ENV['GUARD_NOTIFY'] != 'false' ? Notifier.turn_on : Notifier.turn_off
|
@options[:notify] && ENV['GUARD_NOTIFY'] != 'false' ? Notifier.turn_on : Notifier.turn_off
|
||||||
|
|
||||||
UI.clear if @options[:clear]
|
UI.clear if @options[:clear]
|
||||||
|
|
||||||
debug_command_execution if @options[:debug]
|
debug_command_execution if @options[:debug]
|
||||||
|
|
||||||
self
|
self
|
||||||
@ -112,7 +112,7 @@ module Guard
|
|||||||
|
|
||||||
UI.info "Guard is now watching at '#{ listener.directory }'"
|
UI.info "Guard is now watching at '#{ listener.directory }'"
|
||||||
|
|
||||||
execute_supervised_task_for_all_guards(:start)
|
run_guard_task(:start)
|
||||||
|
|
||||||
interactor.start
|
interactor.start
|
||||||
listener.start
|
listener.start
|
||||||
@ -123,7 +123,7 @@ module Guard
|
|||||||
def stop
|
def stop
|
||||||
UI.info 'Bye bye...', :reset => true
|
UI.info 'Bye bye...', :reset => true
|
||||||
listener.stop
|
listener.stop
|
||||||
execute_supervised_task_for_all_guards(:stop)
|
run_guard_task(:stop)
|
||||||
abort
|
abort
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ module Guard
|
|||||||
#
|
#
|
||||||
def reload
|
def reload
|
||||||
run do
|
run do
|
||||||
execute_supervised_task_for_all_guards(:reload)
|
run_guard_task(:reload)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ module Guard
|
|||||||
#
|
#
|
||||||
def run_all
|
def run_all
|
||||||
run do
|
run do
|
||||||
execute_supervised_task_for_all_guards(:run_all)
|
run_guard_task(:run_all)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -160,7 +160,7 @@ module Guard
|
|||||||
#
|
#
|
||||||
def run_on_change(paths)
|
def run_on_change(paths)
|
||||||
run do
|
run do
|
||||||
execute_supervised_task_for_all_guards(:run_on_change, paths)
|
run_guard_task(:run_on_change, paths)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -172,68 +172,104 @@ module Guard
|
|||||||
def run
|
def run
|
||||||
listener.lock
|
listener.lock
|
||||||
interactor.lock
|
interactor.lock
|
||||||
|
|
||||||
UI.clear if options[:clear]
|
UI.clear if options[:clear]
|
||||||
|
|
||||||
begin
|
begin
|
||||||
yield
|
yield
|
||||||
rescue Interrupt
|
rescue Interrupt
|
||||||
end
|
end
|
||||||
|
|
||||||
interactor.unlock
|
interactor.unlock
|
||||||
listener.unlock
|
listener.unlock
|
||||||
end
|
end
|
||||||
|
|
||||||
# Loop through all groups and execute the given task for each Guard in it,
|
# Loop through all groups and run the given task for each Guard.
|
||||||
# but halt the task execution for the all Guards within a group if one Guard
|
#
|
||||||
|
# Stop the task run for the all Guards within a group if one Guard
|
||||||
# throws `:task_has_failed` and the group has its `:halt_on_fail` option to `true`.
|
# throws `:task_has_failed` and the group has its `:halt_on_fail` option to `true`.
|
||||||
#
|
#
|
||||||
# @param [Symbol] task the task to run
|
# @param [Symbol] task the task to run
|
||||||
# @param [Array] files the list of files to pass to the task
|
# @param [Array<String>] files the list of files to pass to the task
|
||||||
#
|
#
|
||||||
def execute_supervised_task_for_all_guards(task, files = nil)
|
def run_guard_task(task, files = nil)
|
||||||
groups.each do |group|
|
groups.each do |group|
|
||||||
catch group.options[:halt_on_fail] == true ? :task_has_failed : :no_catch do
|
catch group.options[:halt_on_fail] == true ? :task_has_failed : :no_catch do
|
||||||
guards(:group => group.name).each do |guard|
|
guards(:group => group.name).each do |guard|
|
||||||
if task == :run_on_change
|
if task == :run_on_change
|
||||||
paths = Watcher.match_files(guard, files)
|
run_on_change_task(files, guard, task)
|
||||||
unless paths.empty?
|
|
||||||
if @watch_all_modifications
|
|
||||||
UI.debug "#{guard.class.name}##{task} with #{paths.inspect}"
|
|
||||||
supervised_task(guard, task, paths.select { |f| !f.start_with?('!') })
|
|
||||||
deletions = paths.collect { |f| f.slice(1..-1) if f.start_with?('!') }.compact
|
|
||||||
unless deletions.empty?
|
|
||||||
UI.debug "#{guard.class.name}#run_on_deletion with #{deletions.inspect}"
|
|
||||||
supervised_task(guard, :run_on_deletion, deletions)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
UI.debug "#{guard.class.name}##{task} with #{paths.inspect}"
|
|
||||||
supervised_task(guard, task, paths)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
supervised_task(guard, task)
|
run_supervised_task(guard, task)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Let a Guard execute its task, but fire it
|
# Run the `:run_on_change` task. When the option `watch_all_modifications` is set,
|
||||||
# if his work leads to a system failure.
|
# the task is split to run changed paths on {Guard::Guard#run_on_change}, whereas
|
||||||
|
# deleted paths run on {Guard::Guard#run_on_deletion}.
|
||||||
|
#
|
||||||
|
# @param [Array<String>] files the list of files to pass to the task
|
||||||
|
# @param [Guard::Guard] guard the guard to run
|
||||||
|
# @param [Symbol] task the task to run
|
||||||
|
#
|
||||||
|
def run_on_change_task(files, guard, task)
|
||||||
|
paths = Watcher.match_files(guard, files)
|
||||||
|
changes = changed_paths(paths)
|
||||||
|
deletions = deleted_paths(paths)
|
||||||
|
|
||||||
|
unless changes.empty?
|
||||||
|
UI.debug "#{ guard.class.name }##{ task } with #{ changes.inspect }"
|
||||||
|
run_supervised_task(guard, task, changes)
|
||||||
|
end
|
||||||
|
|
||||||
|
unless deletions.empty?
|
||||||
|
UI.debug "#{ guard.class.name }#run_on_deletion with #{ deletions.inspect }"
|
||||||
|
run_supervised_task(guard, :run_on_deletion, deletions)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Detects the paths that have changed.
|
||||||
|
#
|
||||||
|
# Deleted paths are prefixed by an exclamation point, @see Guard::Listener#modified_files
|
||||||
|
#
|
||||||
|
# @param [Array<String>] paths the watched paths
|
||||||
|
# @return [Array<String>] the changed paths
|
||||||
|
#
|
||||||
|
def changed_paths(paths)
|
||||||
|
paths.select { |f| !f.start_with?('!') }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Detects the paths that have been deleted.
|
||||||
|
#
|
||||||
|
# Deleted paths are prefixed by an exclamation point, @see Guard::Listener#modified_files
|
||||||
|
#
|
||||||
|
# @param [Array<String>] paths the watched paths
|
||||||
|
# @return [Array<String>] the deleted paths
|
||||||
|
#
|
||||||
|
def deleted_paths(paths)
|
||||||
|
paths.select { |f| f.start_with?('!') }.map { |f| f.slice(1..-1) }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run a Guard task, but remove the Guard when his work leads to a system failure.
|
||||||
#
|
#
|
||||||
# @param [Guard::Guard] guard the Guard to execute
|
# @param [Guard::Guard] guard the Guard to execute
|
||||||
# @param [Symbol] task_to_supervise the task to run
|
# @param [Symbol] task the task to run
|
||||||
# @param [Array] args the arguments for the task
|
# @param [Array] args the arguments for the task
|
||||||
# @return [Boolean, Exception] the result of the Guard
|
# @return [Boolean, Exception] the result of the Guard
|
||||||
#
|
#
|
||||||
def supervised_task(guard, task_to_supervise, *args)
|
def run_supervised_task(guard, task, *args)
|
||||||
guard.hook("#{ task_to_supervise }_begin", *args)
|
guard.hook("#{ task }_begin", *args)
|
||||||
result = guard.send(task_to_supervise, *args)
|
result = guard.send(task, *args)
|
||||||
guard.hook("#{ task_to_supervise }_end", result)
|
guard.hook("#{ task }_end", result)
|
||||||
|
|
||||||
result
|
result
|
||||||
|
|
||||||
rescue Exception => ex
|
rescue Exception => ex
|
||||||
UI.error("#{ guard.class.name } failed to achieve its <#{ task_to_supervise.to_s }>, exception was:" +
|
UI.error("#{ guard.class.name } failed to achieve its <#{ task.to_s }>, exception was:" +
|
||||||
"\n#{ ex.class }: #{ ex.message }\n#{ ex.backtrace.join("\n") }")
|
"\n#{ ex.class }: #{ ex.message }\n#{ ex.backtrace.join("\n") }")
|
||||||
|
|
||||||
guards.delete guard
|
guards.delete guard
|
||||||
UI.info("\n#{ guard.class.name } has just been fired")
|
UI.info("\n#{ guard.class.name } has just been fired")
|
||||||
|
|
||||||
|
@ -125,8 +125,11 @@ module Guard
|
|||||||
|
|
||||||
# Get the modified files.
|
# Get the modified files.
|
||||||
#
|
#
|
||||||
# If watch_all_modifications is true then moved and deleted files are also appended
|
# If the `:watch_all_modifications` option is true, then moved and
|
||||||
# to the returned array prefixed so !/home/user/dir/file.rb
|
# deleted files are also reported, but prefixed by an exclamation point.
|
||||||
|
#
|
||||||
|
# @example Deleted or moved file
|
||||||
|
# !/home/user/dir/file.rb
|
||||||
#
|
#
|
||||||
# @param [Array<String>] dirs the watched directories
|
# @param [Array<String>] dirs the watched directories
|
||||||
# @param [Hash] options the listener options
|
# @param [Hash] options the listener options
|
||||||
|
@ -342,7 +342,7 @@ describe Guard do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe ".execute_supervised_task_for_all_guards" do
|
describe ".run_guard_task" do
|
||||||
subject { ::Guard.setup }
|
subject { ::Guard.setup }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@ -363,7 +363,7 @@ describe Guard do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "executes the task for each guard in each group" do
|
it "executes the task for each guard in each group" do
|
||||||
subject.execute_supervised_task_for_all_guards(:task)
|
subject.run_guard_task(:task)
|
||||||
|
|
||||||
@sum.all? { |k, v| v == 2 }.should be_true
|
@sum.all? { |k, v| v == 2 }.should be_true
|
||||||
end
|
end
|
||||||
@ -384,7 +384,7 @@ describe Guard do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "executes the task only for guards that didn't fail for group with :halt_on_fail == true" do
|
it "executes the task only for guards that didn't fail for group with :halt_on_fail == true" do
|
||||||
subject.execute_supervised_task_for_all_guards(:task)
|
subject.run_guard_task(:task)
|
||||||
|
|
||||||
@sum[:foo].should eql 1
|
@sum[:foo].should eql 1
|
||||||
@sum[:bar].should eql 7
|
@sum[:bar].should eql 7
|
||||||
@ -392,7 +392,45 @@ describe Guard do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe ".supervised_task" do
|
describe ".run_on_change_task" do
|
||||||
|
let(:guard) do
|
||||||
|
class Guard::Dummy < Guard::Guard
|
||||||
|
def watchers
|
||||||
|
[Guard::Watcher.new(/.+\.rb/)]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Guard::Dummy.new
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'runs the :run_on_change task with the watched file changes' do
|
||||||
|
Guard.should_receive(:run_supervised_task).with(guard, :run_on_change, ['a.rb', 'b.rb'])
|
||||||
|
Guard.run_on_change_task(['a.rb', 'b.rb', 'templates/d.haml'], guard, :run_on_change)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'runs the :run_on_deletion task with the watched file deletions' do
|
||||||
|
Guard.should_receive(:run_supervised_task).with(guard, :run_on_deletion, ['c.rb'])
|
||||||
|
Guard.run_on_change_task(['!c.rb', '!templates/e.haml'], guard, :run_on_change)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe ".changed_paths" do
|
||||||
|
let(:paths) { ['a.rb', 'b.rb', '!c.rb', 'templates/d.haml', '!templates/e.haml'] }
|
||||||
|
|
||||||
|
it 'returns the changed paths' do
|
||||||
|
Guard.changed_paths(paths).should =~ ['a.rb', 'b.rb', 'templates/d.haml']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe ".deleted_paths" do
|
||||||
|
let(:paths) { ['a.rb', 'b.rb', '!c.rb', 'templates/d.haml', '!templates/e.haml'] }
|
||||||
|
|
||||||
|
it 'returns the deleted paths' do
|
||||||
|
Guard.deleted_paths(paths).should =~ ['c.rb', 'templates/e.haml']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe ".run_supervised_task" do
|
||||||
subject { ::Guard.setup }
|
subject { ::Guard.setup }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@ -408,22 +446,22 @@ describe Guard do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't fire the Guard" do
|
it "doesn't fire the Guard" do
|
||||||
lambda { subject.supervised_task(@g, :regular_without_arg) }.should_not change(subject.guards, :size)
|
lambda { subject.run_supervised_task(@g, :regular_without_arg) }.should_not change(subject.guards, :size)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns the result of the task" do
|
it "returns the result of the task" do
|
||||||
::Guard.supervised_task(@g, :regular_without_arg).should be_true
|
::Guard.run_supervised_task(@g, :regular_without_arg).should be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "passes the args to the :begin hook" do
|
it "passes the args to the :begin hook" do
|
||||||
@g.should_receive(:hook).with("regular_without_arg_begin", "given_path")
|
@g.should_receive(:hook).with("regular_without_arg_begin", "given_path")
|
||||||
::Guard.supervised_task(@g, :regular_without_arg, "given_path")
|
::Guard.run_supervised_task(@g, :regular_without_arg, "given_path")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "passes the result of the supervised method to the :end hook" do
|
it "passes the result of the supervised method to the :end hook" do
|
||||||
@g.should_receive(:hook).with("regular_without_arg_begin", "given_path")
|
@g.should_receive(:hook).with("regular_without_arg_begin", "given_path")
|
||||||
@g.should_receive(:hook).with("regular_without_arg_end", true)
|
@g.should_receive(:hook).with("regular_without_arg_end", true)
|
||||||
::Guard.supervised_task(@g, :regular_without_arg, "given_path")
|
::Guard.run_supervised_task(@g, :regular_without_arg, "given_path")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -433,17 +471,17 @@ describe Guard do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't fire the Guard" do
|
it "doesn't fire the Guard" do
|
||||||
lambda { subject.supervised_task(@g, :regular_with_arg, "given_path") }.should_not change(subject.guards, :size)
|
lambda { subject.run_supervised_task(@g, :regular_with_arg, "given_path") }.should_not change(subject.guards, :size)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns the result of the task" do
|
it "returns the result of the task" do
|
||||||
::Guard.supervised_task(@g, :regular_with_arg, "given_path").should eql "I'm a success"
|
::Guard.run_supervised_task(@g, :regular_with_arg, "given_path").should eql "I'm a success"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "calls the default begin hook but not the default end hook" do
|
it "calls the default begin hook but not the default end hook" do
|
||||||
@g.should_receive(:hook).with("failing_begin")
|
@g.should_receive(:hook).with("failing_begin")
|
||||||
@g.should_not_receive(:hook).with("failing_end")
|
@g.should_not_receive(:hook).with("failing_end")
|
||||||
::Guard.supervised_task(@g, :failing)
|
::Guard.run_supervised_task(@g, :failing)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -452,7 +490,7 @@ describe Guard do
|
|||||||
before(:each) { @g.stub!(:group) { :foo }; @g.stub!(:failing) { throw :task_has_failed } }
|
before(:each) { @g.stub!(:group) { :foo }; @g.stub!(:failing) { throw :task_has_failed } }
|
||||||
|
|
||||||
it "throws :task_has_failed" do
|
it "throws :task_has_failed" do
|
||||||
expect { subject.supervised_task(@g, :failing) }.to throw_symbol(:task_has_failed)
|
expect { subject.run_supervised_task(@g, :failing) }.to throw_symbol(:task_has_failed)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -460,12 +498,12 @@ describe Guard do
|
|||||||
before(:each) { @g.stub!(:failing) { raise "I break your system" } }
|
before(:each) { @g.stub!(:failing) { raise "I break your system" } }
|
||||||
|
|
||||||
it "fires the Guard" do
|
it "fires the Guard" do
|
||||||
lambda { subject.supervised_task(@g, :failing) }.should change(subject.guards, :size).by(-1)
|
lambda { subject.run_supervised_task(@g, :failing) }.should change(subject.guards, :size).by(-1)
|
||||||
subject.guards.should_not include(@g)
|
subject.guards.should_not include(@g)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns the exception" do
|
it "returns the exception" do
|
||||||
failing_result = ::Guard.supervised_task(@g, :failing)
|
failing_result = ::Guard.run_supervised_task(@g, :failing)
|
||||||
failing_result.should be_kind_of(Exception)
|
failing_result.should be_kind_of(Exception)
|
||||||
failing_result.message.should == 'I break your system'
|
failing_result.message.should == 'I break your system'
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user