Added #callback DSL, modified Guard and Guard::Hook a bit in consequence.
Signed-off-by: Rémy Coutable <remy@jilion.com>
This commit is contained in:
parent
b646ae53f6
commit
b83653db2e
10
lib/guard.rb
10
lib/guard.rb
@ -58,12 +58,12 @@ module Guard
|
||||
# Let a guard execute its task but
|
||||
# fire it if his work leads to a system failure
|
||||
def supervised_task(guard, task_to_supervise, *args)
|
||||
guard.hook "#{task_to_supervise.to_s}_begin"
|
||||
guard.hook "#{task_to_supervise}_begin"
|
||||
result = guard.send(task_to_supervise, *args)
|
||||
guard.hook "#{task_to_supervise.to_s}_end"
|
||||
guard.hook "#{task_to_supervise}_end"
|
||||
result
|
||||
rescue Exception
|
||||
UI.error("#{guard.class.name} guard failed to achieve its <#{task_to_supervise.to_s}> command: #{$!}")
|
||||
UI.error("#{guard.class.name} guard failed to achieve its <#{task_to_supervise}> command: #{$!}")
|
||||
::Guard.guards.delete guard
|
||||
UI.info("Guard #{guard.class.name} has just been fired")
|
||||
return $!
|
||||
@ -79,9 +79,11 @@ module Guard
|
||||
listener.start
|
||||
end
|
||||
|
||||
def add_guard(name, watchers = [], options = {})
|
||||
def add_guard(name, watchers = [], callbacks = [], options = {})
|
||||
guard_class = get_guard_class(name)
|
||||
watchers = watchers.map { |watcher| ::Guard::Watcher.new(watcher[:pattern], watcher[:action]) }
|
||||
@guards << guard_class.new(watchers, options)
|
||||
callbacks.each { |callback| ::Guard::Hook.add_callback(callback[:listener], guard_class, callback[:events]) }
|
||||
end
|
||||
|
||||
def get_guard_class(name)
|
||||
|
@ -4,7 +4,7 @@ module Guard
|
||||
class << self
|
||||
def evaluate_guardfile(options = {})
|
||||
@@options = options
|
||||
|
||||
|
||||
if File.exists?(guardfile_path)
|
||||
begin
|
||||
new.instance_eval(File.read(guardfile_path), guardfile_path, 1)
|
||||
@ -21,7 +21,7 @@ module Guard
|
||||
def guardfile_include?(guard_name)
|
||||
File.read(guardfile_path).match(/^guard\s*\(?\s*['":]#{guard_name}['"]?/)
|
||||
end
|
||||
|
||||
|
||||
def guardfile_path
|
||||
File.join(Dir.pwd, 'Guardfile')
|
||||
end
|
||||
@ -31,14 +31,24 @@ module Guard
|
||||
guard_definition.call if guard_definition && (@@options[:group].empty? || @@options[:group].include?(name))
|
||||
end
|
||||
|
||||
def guard(name, options = {}, &watch_definition)
|
||||
@watchers = []
|
||||
watch_definition.call if watch_definition
|
||||
::Guard.add_guard(name, @watchers, options)
|
||||
def guard(name, options = {}, &watch_and_callback_definition)
|
||||
@watchers = []
|
||||
@callbacks = []
|
||||
watch_and_callback_definition.call if watch_and_callback_definition
|
||||
::Guard.add_guard(name, @watchers, @callbacks, options)
|
||||
end
|
||||
|
||||
def watch(pattern, &action)
|
||||
@watchers << ::Guard::Watcher.new(pattern, action)
|
||||
@watchers << { :pattern => pattern, :action => action }
|
||||
end
|
||||
|
||||
def callback(*args, &listener)
|
||||
listener, events = if args.size > 1
|
||||
args
|
||||
else
|
||||
[listener, args[0]]
|
||||
end
|
||||
@callbacks << { :events => events, :listener => listener }
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -5,17 +5,16 @@ module Guard
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
# When passed a sybmol, #hook will generate a hook name
|
||||
# from the symbol and calling method name. When passed
|
||||
# a string, #hook will turn the string into a symbol
|
||||
# directly.
|
||||
def hook(event)
|
||||
if event.class == Symbol
|
||||
hook_name = if event.is_a? Symbol
|
||||
calling_method = caller[0][/`([^']*)'/, 1]
|
||||
hook_name = "#{calling_method}_#{event}".to_sym
|
||||
"#{calling_method}_#{event}".to_sym
|
||||
else
|
||||
hook_name = event.to_sym
|
||||
event.to_sym
|
||||
end
|
||||
|
||||
UI.info "\nHook :#{hook_name} executed for #{self.class}"
|
||||
@ -28,15 +27,15 @@ module Guard
|
||||
@callbacks ||= Hash.new { |hash, key| hash[key] = [] }
|
||||
end
|
||||
|
||||
def add(listener, guard_class, events)
|
||||
_events = events.class == Array ? events : [events]
|
||||
def add_callback(listener, guard_class, events)
|
||||
_events = events.is_a?(Array) ? events : [events]
|
||||
_events.each do |event|
|
||||
callbacks[[guard_class, event]] << listener
|
||||
end
|
||||
end
|
||||
|
||||
def has_callback?(listener, guard_class, event)
|
||||
callbacks[[guard_class, event]].include? listener
|
||||
callbacks[[guard_class, event]].include?(listener)
|
||||
end
|
||||
|
||||
def notify(guard_class, event)
|
||||
@ -45,7 +44,7 @@ module Guard
|
||||
end
|
||||
end
|
||||
|
||||
def reset!
|
||||
def reset_callbacks!
|
||||
@callbacks = nil
|
||||
end
|
||||
end
|
||||
|
@ -59,56 +59,75 @@ describe Guard::Dsl do
|
||||
end")
|
||||
end
|
||||
|
||||
it "should evaluates only the specified group" do
|
||||
::Guard.should_receive(:add_guard).with('test', anything, {})
|
||||
::Guard.should_not_receive(:add_guard).with('another', anything, {})
|
||||
it "evaluates only the specified group" do
|
||||
::Guard.should_receive(:add_guard).with('test', anything, anything, {})
|
||||
::Guard.should_not_receive(:add_guard).with('another', anything, anything, {})
|
||||
subject.evaluate_guardfile(:group => ['x'])
|
||||
end
|
||||
|
||||
it "should evaluates only the specified groups" do
|
||||
::Guard.should_receive(:add_guard).with('test', anything, {})
|
||||
::Guard.should_receive(:add_guard).with('another', anything, {})
|
||||
it "evaluates only the specified groups" do
|
||||
::Guard.should_receive(:add_guard).with('test', anything, anything, {})
|
||||
::Guard.should_receive(:add_guard).with('another', anything, anything, {})
|
||||
subject.evaluate_guardfile(:group => ['x', 'y'])
|
||||
end
|
||||
end
|
||||
|
||||
describe "#guard" do
|
||||
it "should load a guard specified as a string from the DSL" do
|
||||
it "loads a guard specified by a string" do
|
||||
mock_guardfile_content("guard 'test'")
|
||||
|
||||
::Guard.should_receive(:add_guard).with('test', [], {})
|
||||
::Guard.should_receive(:add_guard).with('test', [], [], {})
|
||||
subject.evaluate_guardfile
|
||||
end
|
||||
|
||||
it "should load a guard specified as a symbol from the DSL" do
|
||||
it "loads a guard specified as a symbol from the DSL" do
|
||||
mock_guardfile_content("guard :test")
|
||||
|
||||
::Guard.should_receive(:add_guard).with(:test, [], {})
|
||||
::Guard.should_receive(:add_guard).with(:test, [], [], {})
|
||||
subject.evaluate_guardfile
|
||||
end
|
||||
|
||||
it "should receive options when specified" do
|
||||
it "accepts options" do
|
||||
mock_guardfile_content("guard 'test', :opt_a => 1, :opt_b => 'fancy'")
|
||||
|
||||
::Guard.should_receive(:add_guard).with('test', anything, { :opt_a => 1, :opt_b => 'fancy' })
|
||||
::Guard.should_receive(:add_guard).with('test', anything, anything, { :opt_a => 1, :opt_b => 'fancy' })
|
||||
subject.evaluate_guardfile
|
||||
end
|
||||
end
|
||||
|
||||
describe "#watch" do
|
||||
it "should receive watchers when specified" do
|
||||
it "creates watchers for the guard" do
|
||||
mock_guardfile_content("
|
||||
guard 'test' do
|
||||
watch('a') { 'b' }
|
||||
watch('c')
|
||||
end")
|
||||
|
||||
::Guard.should_receive(:add_guard).with('test', anything, {}) do |name, watchers, options|
|
||||
watchers.size.should == 2
|
||||
watchers[0].pattern.should == 'a'
|
||||
watchers[0].action.call.should == proc { 'b' }.call
|
||||
watchers[1].pattern.should == 'c'
|
||||
watchers[1].action.should be_nil
|
||||
::Guard.should_receive(:add_guard).with('test', anything, anything, {}) do |name, watchers, callbacks, options|
|
||||
watchers.should have(2).items
|
||||
watchers[0][:pattern].should == 'a'
|
||||
watchers[0][:action].call.should == proc { 'b' }.call
|
||||
watchers[1][:pattern].should == 'c'
|
||||
watchers[1][:action].should be_nil
|
||||
end
|
||||
subject.evaluate_guardfile
|
||||
end
|
||||
end
|
||||
|
||||
describe "#callback" do
|
||||
it "creates callbacks for the guard" do
|
||||
class MyCustomCallback
|
||||
end
|
||||
|
||||
mock_guardfile_content("
|
||||
guard 'test' do
|
||||
callback(:start_end) { 'Guard::Test started!' }
|
||||
callback(MyCustomCallback, [:start_begin, :run_all_begin])
|
||||
end")
|
||||
|
||||
::Guard.should_receive(:add_guard).with('test', anything, anything, {}) do |name, watchers, callbacks, options|
|
||||
callbacks.should have(2).items
|
||||
callbacks[0][:events].should == :start_end
|
||||
callbacks[0][:listener].call.should == proc { 'Guard::Test started!' }.call
|
||||
callbacks[1][:events].should == [:start_begin, :run_all_begin]
|
||||
callbacks[1][:listener].should == MyCustomCallback
|
||||
end
|
||||
subject.evaluate_guardfile
|
||||
end
|
||||
|
@ -1,8 +1,8 @@
|
||||
require "spec_helper"
|
||||
require 'guard/guard'
|
||||
require "guard/hook"
|
||||
require 'spec_helper'
|
||||
|
||||
describe Guard::Hook do
|
||||
subject { Guard::Hook }
|
||||
|
||||
class Guard::Dummy < Guard::Guard
|
||||
include Guard::Hook
|
||||
|
||||
@ -16,53 +16,49 @@ describe Guard::Hook do
|
||||
let(:listener) { double('listener').as_null_object }
|
||||
|
||||
context "--module methods--" do
|
||||
before { subject.add(listener, guard_class, :start_begin) }
|
||||
before { subject.add_callback(listener, guard_class, :start_begin) }
|
||||
|
||||
after { subject.reset! }
|
||||
after { subject.reset_callbacks! }
|
||||
|
||||
describe ".add " do
|
||||
describe ".add_callback" do
|
||||
it "can add a single callback" do
|
||||
subject.has_callback?(listener, guard_class, :start_begin).should be_true
|
||||
end
|
||||
|
||||
it "can add multiple callbacks" do
|
||||
subject.add(listener, guard_class, [:event1, :event2])
|
||||
subject.add_callback(listener, guard_class, [:event1, :event2])
|
||||
subject.has_callback?(listener, guard_class, :event1).should be_true
|
||||
subject.has_callback?(listener, guard_class, :event2).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe ".notify " do
|
||||
describe ".notify" do
|
||||
it "sends :call to the given Guard class's callbacks" do
|
||||
listener.should_receive(:call).with(guard_class, :start_begin)
|
||||
subject.notify(guard_class, :start_begin)
|
||||
end
|
||||
|
||||
it "doesn't run callbacks of different types" do
|
||||
it "runs only the given callbacks" do
|
||||
listener2 = double('listener2')
|
||||
subject.add(listener2, guard_class, :start_end)
|
||||
subject.add_callback(listener2, guard_class, :start_end)
|
||||
listener2.should_not_receive(:call).with(guard_class, :start_end)
|
||||
subject.notify(guard_class, :start_begin)
|
||||
end
|
||||
|
||||
it "doesn't run callbacks of the wrong class" do
|
||||
it "runs callbacks only for the guard given" do
|
||||
guard2_class = double('Guard::Dummy2').class
|
||||
subject.add(listener, guard2_class, :start_begin)
|
||||
subject.add_callback(listener, guard2_class, :start_begin)
|
||||
listener.should_not_receive(:call).with(guard2_class, :start_begin)
|
||||
subject.notify(guard_class, :start_begin)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#hook " do
|
||||
describe "#hook" do
|
||||
it "calls Guard::Hook.notify" do
|
||||
guard = guard_class.new
|
||||
Guard::Hook.should_receive(:notify).
|
||||
with(guard_class, :run_all_begin)
|
||||
|
||||
Guard::Hook.should_receive(:notify).
|
||||
with(guard_class, :run_all_end)
|
||||
|
||||
Guard::Hook.should_receive(:notify).with(guard_class, :run_all_begin)
|
||||
Guard::Hook.should_receive(:notify).with(guard_class, :run_all_end)
|
||||
guard.run_all
|
||||
end
|
||||
|
||||
@ -74,9 +70,9 @@ describe Guard::Hook do
|
||||
end
|
||||
|
||||
guard = guard_class.new
|
||||
Guard::Hook.should_receive(:notify).
|
||||
with(guard_class, :my_hook)
|
||||
Guard::Hook.should_receive(:notify).with(guard_class, :my_hook)
|
||||
guard.start
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -91,6 +91,12 @@ describe Guard do
|
||||
::Guard.supervised_task(@g, :regular).should be_true
|
||||
::Guard.supervised_task(@g, :regular_with_arg, "given_path").should == "i'm a success"
|
||||
end
|
||||
|
||||
it "calls the default hooks" do
|
||||
@g.should_receive(:hook).with("regular_begin")
|
||||
@g.should_receive(:hook).with("regular_end")
|
||||
::Guard.supervised_task(@g, :regular)
|
||||
end
|
||||
end
|
||||
|
||||
describe "tasks that raise an exception" do
|
||||
@ -106,9 +112,13 @@ describe Guard do
|
||||
failing_result.should be_kind_of(Exception)
|
||||
failing_result.message.should == 'I break your system'
|
||||
end
|
||||
end
|
||||
|
||||
it "calls the default hooks"
|
||||
it "calls the default begin hook but not the default end hook" do
|
||||
@g.should_receive(:hook).with("failing_begin")
|
||||
@g.should_not_receive(:hook).with("failing_end")
|
||||
::Guard.supervised_task(@g, :failing)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".locate_guard" do
|
||||
|
Loading…
Reference in New Issue
Block a user