Merge branch 'master' of github.com:guard/guard
Conflicts: lib/guard.rb lib/guard/interactor.rb spec/guard_spec.rb
This commit is contained in:
commit
2fc6745837
@ -1,3 +1,15 @@
|
||||
== Nov 26, 2010 [by rymai]
|
||||
|
||||
Features:
|
||||
- It's now possible to return an enumerable in the 'watch' optional blocks in the Guardfile.
|
||||
- Listener now continue to watch changed files even when guards plugin are running.
|
||||
|
||||
Specs:
|
||||
- Guard::Watcher
|
||||
|
||||
Bugs fixes:
|
||||
- Avoid launching run_on_change guards method when no files matched. --clear guard argument is now usable.
|
||||
|
||||
== 0.2.2 (Oct 25, 2010)
|
||||
|
||||
Bugs fixes:
|
||||
|
17
README.rdoc
17
README.rdoc
@ -83,6 +83,8 @@ Signal handlers are used to interact with Guard:
|
||||
- {guard-coffeescript}[http://github.com/guard/guard-coffeescript] by {Michael Kessler}[http://github.com/netzpirat]
|
||||
- {guard-compass}[http://github.com/guard/guard-compass] by {Olivier Amblet}[http://github.com/oliamb]
|
||||
- {guard-cucumber}[http://github.com/guard/guard-cucumber] by {Michael Kessler}[http://github.com/netzpirat]
|
||||
- {guard-ego}[http://github.com/guard/guard-ego] by {Fabio Kuhn}[http://github.com/mordaroso]
|
||||
- {guard-jammit}[http://github.com/guard/guard-jammit] by {Pelle Braendgaard}[http://github.com/pelle]
|
||||
- {guard-livereload}[http://github.com/guard/guard-livereload] by {Thibaud Guillaume-Gentil}[http://github.com/thibaudgg]
|
||||
- {guard-minitest}[http://github.com/guard/guard-minitest] by {Yann Lugrin}[http://github.com/yannlugrin]
|
||||
- {guard-nanoc}[http://github.com/guard/guard-nanoc] by {Yann Lugrin}[http://github.com/yannlugrin]
|
||||
@ -90,13 +92,9 @@ Signal handlers are used to interact with Guard:
|
||||
- {guard-rspec}[http://github.com/guard/guard-rspec] by {Thibaud Guillaume-Gentil}[http://github.com/thibaudgg]
|
||||
- {guard-sass}[http://github.com/guard/guard-sass] by {Joshua Hawxwell}[http://github.com/hawx]
|
||||
- {guard-shell}[http://github.com/guard/guard-shell] by {Joshua Hawxwell}[http://github.com/hawx]
|
||||
- {guard-spork}[http://github.com/guard/guard-spork] by {Thibaud Guillaume-Gentil}[http://github.com/thibaudgg]
|
||||
- {guard-test}[http://github.com/guard/guard-test] by {Rémy Coutable}[http://github.com/rymai]
|
||||
|
||||
guard ideas:
|
||||
|
||||
- guard-spork
|
||||
- others ideas?
|
||||
|
||||
=== Add a guard to your Guardfile
|
||||
|
||||
Add it to your Gemfile (inside test group):
|
||||
@ -178,10 +176,11 @@ Looks at available guards code for more concrete example.
|
||||
Guardfile DSL consists of just two simple methods: guard & watch. Example:
|
||||
|
||||
guard 'rspec', :version => 2 do
|
||||
watch('^spec/(.*)_spec.rb')
|
||||
watch('^lib/(.*)\.rb') { |m| "spec/lib/#{m[1]}_spec.rb" }
|
||||
watch('^spec/spec_helper.rb') { "spec" }
|
||||
watch('^spec/spec_helper.rb') { `say hello` }
|
||||
watch(%|^spec/(.*)_spec\.rb|)
|
||||
watch(%|^lib/(.*)\.rb|) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
||||
watch(%|^spec/spec_helper\.rb|) { "spec" }
|
||||
watch(%|^spec/models/.*\.rb|) { ["spec/models", "spec/acceptance"] }
|
||||
watch(%|^spec/spec_helper\.rb|) { `say hello` }
|
||||
end
|
||||
|
||||
- "guard" method allow to add a guard with an optional options hash
|
||||
|
12
lib/guard.rb
12
lib/guard.rb
@ -17,7 +17,7 @@ module Guard
|
||||
@options = options
|
||||
@listener = Listener.select_and_init
|
||||
@guards = []
|
||||
return self
|
||||
self
|
||||
end
|
||||
|
||||
def start(options = {})
|
||||
@ -40,10 +40,12 @@ module Guard
|
||||
loop do
|
||||
if !running? && !listener.changed_files.empty?
|
||||
changed_files = listener.get_and_clear_changed_files
|
||||
run do
|
||||
guards.each do |guard|
|
||||
paths = Watcher.match_files(guard, changed_files)
|
||||
supervised_task(guard, :run_on_change, paths) unless paths.empty?
|
||||
if Watcher.match_files?(guards, files)
|
||||
run do
|
||||
guards.each do |guard|
|
||||
paths = Watcher.match_files(guard, changed_files)
|
||||
supervised_task(guard, :run_on_change, paths) unless paths.empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -3,7 +3,7 @@ module Guard
|
||||
|
||||
def self.evaluate_guardfile
|
||||
guardfile = "#{Dir.pwd}/Guardfile"
|
||||
if File.exists? guardfile
|
||||
if File.exists?(guardfile)
|
||||
begin
|
||||
dsl = new
|
||||
dsl.instance_eval(File.read(guardfile.to_s), guardfile.to_s, 1)
|
||||
|
@ -14,9 +14,9 @@ module Guard
|
||||
content = File.read('Guardfile')
|
||||
guard = File.read("#{::Guard.locate_guard(name)}/lib/guard/#{name}/templates/Guardfile")
|
||||
File.open('Guardfile', 'wb') do |f|
|
||||
f.puts content
|
||||
f.puts ""
|
||||
f.puts guard
|
||||
f.puts(content)
|
||||
f.puts("")
|
||||
f.puts(guard)
|
||||
end
|
||||
::Guard::UI.info "#{name} guard added to Guardfile, feel free to edit it"
|
||||
end
|
||||
|
@ -5,7 +5,7 @@ module Guard
|
||||
# Run all (Ctrl-\)
|
||||
Signal.trap('QUIT') do
|
||||
::Guard.run do
|
||||
::Guard.guards.each { |g| ::Guard.supervised_task g, :run_all }
|
||||
::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :run_all) }
|
||||
end
|
||||
end
|
||||
|
||||
@ -13,14 +13,14 @@ module Guard
|
||||
Signal.trap('INT') do
|
||||
UI.info "Bye bye...", :reset => true
|
||||
::Guard.listener.stop
|
||||
::Guard.guards.each { |g| ::Guard.supervised_task g, :stop }
|
||||
::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :stop) }
|
||||
abort("\n")
|
||||
end
|
||||
|
||||
# Reload (Ctrl-Z)
|
||||
Signal.trap('TSTP') do
|
||||
::Guard.run do
|
||||
::Guard.guards.each { |g| ::Guard.supervised_task g, :reload }
|
||||
::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :reload) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -9,12 +9,16 @@ module Guard
|
||||
end
|
||||
end
|
||||
|
||||
def error(message)
|
||||
puts "ERROR: #{message}"
|
||||
def error(message, options = {})
|
||||
unless ENV["GUARD_ENV"] == "test"
|
||||
reset_line if options[:reset]
|
||||
puts "ERROR: #{message}"
|
||||
end
|
||||
end
|
||||
|
||||
def debug(message)
|
||||
def debug(message, options = {})
|
||||
unless ENV["GUARD_ENV"] == "test"
|
||||
reset_line if options[:reset]
|
||||
puts "DEBUG: #{message}" if ::Guard.options && ::Guard.options[:debug]
|
||||
end
|
||||
end
|
||||
|
@ -9,24 +9,36 @@ module Guard
|
||||
def self.match_files(guard, files)
|
||||
guard.watchers.inject([]) do |paths, watcher|
|
||||
files.each do |file|
|
||||
if matches = file.match(watcher.pattern)
|
||||
if matches = watcher.match_file?(file)
|
||||
if watcher.action
|
||||
begin
|
||||
if watcher.action.arity == 1
|
||||
result = watcher.action.call(matches)
|
||||
else
|
||||
result = watcher.action.call
|
||||
end
|
||||
rescue
|
||||
UI.info "Problem with watch action"
|
||||
end
|
||||
paths << result if result.is_a?(String) && result != ''
|
||||
result = watcher.call_action(matches)
|
||||
paths << Array(result) if result.respond_to?(:empty?) && !result.empty?
|
||||
else
|
||||
paths << matches[0]
|
||||
end
|
||||
end
|
||||
end
|
||||
paths
|
||||
paths.flatten.map { |p| p.to_s }
|
||||
end
|
||||
end
|
||||
|
||||
def self.match_files?(guards, files)
|
||||
guards.any? do |guard|
|
||||
guard.watchers.any? do |watcher|
|
||||
files.any? { |file| watcher.match_file?(file) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def match_file?(file)
|
||||
file.match(@pattern)
|
||||
end
|
||||
|
||||
def call_action(matches)
|
||||
begin
|
||||
@action.arity > 0 ? @action.call(matches) : @action.call
|
||||
rescue
|
||||
UI.error "Problem with watch action!"
|
||||
end
|
||||
end
|
||||
|
||||
|
135
spec/guard/watcher_spec.rb
Normal file
135
spec/guard/watcher_spec.rb
Normal file
@ -0,0 +1,135 @@
|
||||
require 'spec_helper'
|
||||
require 'guard/guard'
|
||||
|
||||
describe Guard::Watcher do
|
||||
|
||||
describe "pattern" do
|
||||
it "should be required" do
|
||||
expect { Guard::Watcher.new }.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "should be set" do
|
||||
Guard::Watcher.new(%|spec_helper\.rb|).pattern.should == %|spec_helper\.rb|
|
||||
end
|
||||
end
|
||||
|
||||
describe "action" do
|
||||
it "should set action to nil by default" do
|
||||
Guard::Watcher.new(%|spec_helper\.rb|).action.should be_nil
|
||||
end
|
||||
|
||||
it "should set action with a block" do
|
||||
action = lambda { |m| "spec/#{m[1]}_spec.rb" }
|
||||
Guard::Watcher.new(%|^lib/(.*).rb|, action).action.should == action
|
||||
end
|
||||
end
|
||||
|
||||
describe ".match_files" do
|
||||
before(:all) { @guard = Guard::Guard.new }
|
||||
|
||||
describe "a watcher's with no action" do
|
||||
before(:all) { @guard.watchers = [Guard::Watcher.new(%|.*_spec\.rb|)] }
|
||||
|
||||
it "should return paths as they came" do
|
||||
Guard::Watcher.match_files(@guard, ['guard_rocks_spec.rb']).should == ['guard_rocks_spec.rb']
|
||||
end
|
||||
end
|
||||
|
||||
describe "a watcher's action with an arity equal to 0" do
|
||||
before(:all) do
|
||||
@guard.watchers = [
|
||||
Guard::Watcher.new(%|spec_helper\.rb|, lambda { 'spec' }),
|
||||
Guard::Watcher.new(%|addition\.rb|, lambda { 1 + 1 }),
|
||||
Guard::Watcher.new(%|hash\.rb|, lambda { Hash[:foo, 'bar'] }),
|
||||
Guard::Watcher.new(%|array\.rb|, lambda { ['foo', 'bar'] }),
|
||||
Guard::Watcher.new(%|blank\.rb|, lambda { '' }),
|
||||
Guard::Watcher.new(%|uptime\.rb|, lambda { `uptime > /dev/null` })
|
||||
]
|
||||
end
|
||||
|
||||
it "should return paths specified in the watcher's action" do
|
||||
Guard::Watcher.match_files(@guard, ['spec_helper.rb']).should == ['spec']
|
||||
end
|
||||
it "should return nothing if action.call doesn't respond_to :empty?" do
|
||||
Guard::Watcher.match_files(@guard, ['addition.rb']).should == []
|
||||
end
|
||||
it "should return action.call.to_a if result respond_to :empty?" do
|
||||
Guard::Watcher.match_files(@guard, ['hash.rb']).should == ['foo', 'bar']
|
||||
end
|
||||
it "should return files including files from array if paths are an array" do
|
||||
Guard::Watcher.match_files(@guard, ['spec_helper.rb', 'array.rb']).should == ['spec', 'foo', 'bar']
|
||||
end
|
||||
it "should return nothing if action.call return ''" do
|
||||
Guard::Watcher.match_files(@guard, ['blank.rb']).should == []
|
||||
end
|
||||
it "should return nothing if action.call return nil" do
|
||||
Guard::Watcher.match_files(@guard, ['uptime.rb']).should == []
|
||||
end
|
||||
end
|
||||
|
||||
describe "a watcher's action with an arity equal to 1" do
|
||||
before(:all) do
|
||||
@guard.watchers = [
|
||||
Guard::Watcher.new(%|lib/(.*)\.rb|, lambda { |m| "spec/#{m[1]}_spec.rb" }),
|
||||
Guard::Watcher.new(%|addition(.*)\.rb|, lambda { |m| 1 + 1 }),
|
||||
Guard::Watcher.new(%|hash\.rb|, lambda { Hash[:foo, 'bar'] }),
|
||||
Guard::Watcher.new(%|array(.*)\.rb|, lambda { |m| ['foo', 'bar'] }),
|
||||
Guard::Watcher.new(%|blank(.*)\.rb|, lambda { |m| '' }),
|
||||
Guard::Watcher.new(%|uptime(.*)\.rb|, lambda { |m| `uptime > /dev/null` })
|
||||
]
|
||||
end
|
||||
|
||||
it "should return paths after watcher's action has been called against them" do
|
||||
Guard::Watcher.match_files(@guard, ['lib/my_wonderful_lib.rb']).should == ['spec/my_wonderful_lib_spec.rb']
|
||||
end
|
||||
it "should return nothing if action.call doesn't respond_to :empty?" do
|
||||
Guard::Watcher.match_files(@guard, ['addition.rb']).should == []
|
||||
end
|
||||
it "should return action.call.to_a if result respond_to :empty?" do
|
||||
Guard::Watcher.match_files(@guard, ['hash.rb']).should == ['foo', 'bar']
|
||||
end
|
||||
it "should return files including files from array if paths are an array" do
|
||||
Guard::Watcher.match_files(@guard, ['lib/my_wonderful_lib.rb', 'array.rb']).should == ['spec/my_wonderful_lib_spec.rb', 'foo', 'bar']
|
||||
end
|
||||
it "should return nothing if action.call return ''" do
|
||||
Guard::Watcher.match_files(@guard, ['blank.rb']).should == []
|
||||
end
|
||||
it "should return nothing if action.call return nil" do
|
||||
Guard::Watcher.match_files(@guard, ['uptime.rb']).should == []
|
||||
end
|
||||
end
|
||||
|
||||
describe "an exception is raised" do
|
||||
before(:all) { @guard.watchers = [Guard::Watcher.new('evil.rb', lambda { raise "EVIL" })] }
|
||||
|
||||
it "should display an error" do
|
||||
Guard::UI.should_receive(:error).with("Problem with watch action!")
|
||||
Guard::Watcher.match_files(@guard, ['evil.rb'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".match_files?" do
|
||||
before(:all) do
|
||||
@guard1 = Guard::Guard.new([Guard::Watcher.new(%|.*_spec\.rb|)])
|
||||
@guard2 = Guard::Guard.new([Guard::Watcher.new(%|spec_helper\.rb|, 'spec')])
|
||||
@guards = [@guard1, @guard2]
|
||||
end
|
||||
|
||||
describe "with at least on watcher that match a file given" do
|
||||
specify { Guard::Watcher.match_files?(@guards, ['lib/my_wonderful_lib.rb', 'guard_rocks_spec.rb']).should be_true }
|
||||
end
|
||||
|
||||
describe "with no watcher matching a file given" do
|
||||
specify { Guard::Watcher.match_files?(@guards, ['lib/my_wonderful_lib.rb']).should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
describe "#match_file?" do
|
||||
subject { Guard::Watcher.new(%|.*_spec\.rb|) }
|
||||
|
||||
specify { subject.match_file?('lib/my_wonderful_lib.rb').should be_false }
|
||||
specify { subject.match_file?('guard_rocks_spec.rb').should be_true }
|
||||
end
|
||||
|
||||
end
|
@ -1,96 +1,84 @@
|
||||
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
|
||||
describe "Class Methods" do
|
||||
describe ".setup" do
|
||||
subject { ::Guard.setup }
|
||||
|
||||
it "should return Guard::RSpec" do
|
||||
Guard.get_guard_class('rspec').should == Guard::RSpec
|
||||
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.setup(opts).options.should include(:my_opts)
|
||||
end
|
||||
|
||||
it "should init listener" do
|
||||
::Guard.listener.should be_kind_of(Guard::Listener)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "locate_guard" do
|
||||
|
||||
it "should return guard-rspec gem path" do
|
||||
guard_path = Guard.locate_guard('rspec')
|
||||
guard_path.should match(/^.*\/guard-rspec-.*$/)
|
||||
guard_path.should == guard_path.chomp
|
||||
describe ".get_guard_class" do
|
||||
it "should return Guard::RSpec" do
|
||||
Guard.get_guard_class('rspec').should == Guard::RSpec
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "init" do
|
||||
subject { ::Guard.setup }
|
||||
|
||||
it "Should retrieve itself for chaining" do
|
||||
subject.should be_kind_of(Module)
|
||||
describe ".locate_guard" do
|
||||
it "should return guard-rspec gem path" do
|
||||
guard_path = Guard.locate_guard('rspec')
|
||||
guard_path.should match(/^.*\/guard-rspec-.*$/)
|
||||
guard_path.should == guard_path.chomp
|
||||
end
|
||||
end
|
||||
|
||||
it "Should init guards array" do
|
||||
::Guard.guards.should be_kind_of(Array)
|
||||
end
|
||||
describe ".supervised_task" do
|
||||
subject { ::Guard.setup }
|
||||
before(:each) do
|
||||
@g = mock(Guard::Guard)
|
||||
subject.guards.push(@g)
|
||||
end
|
||||
|
||||
it "Should init options" do
|
||||
opts = {:my_opts => true}
|
||||
::Guard.setup(opts).options.should be_include(:my_opts)
|
||||
end
|
||||
describe "tasks that succeed" do
|
||||
before(:each) do
|
||||
@g.stub!(:regular) { true }
|
||||
@g.stub!(:regular_with_arg).with("given_path") { "i'm a success" }
|
||||
end
|
||||
|
||||
it "Should init listeners" do
|
||||
::Guard.listener.should be_kind_of(Guard::Listener)
|
||||
end
|
||||
end
|
||||
it "should not fire the guard with a supervised method without argument" do
|
||||
lambda { subject.supervised_task(@g, :regular) }.should_not change(subject.guards, :size)
|
||||
end
|
||||
|
||||
describe "supervised_task" do
|
||||
subject { ::Guard.setup }
|
||||
it "should not fire the guard with a supervised method with argument" do
|
||||
lambda { subject.supervised_task(@g, :regular_with_arg, "given_path") }.should_not change(subject.guards, :size)
|
||||
end
|
||||
|
||||
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 return the result of the supervised method" do
|
||||
::Guard.supervised_task(@g, :regular).should be_true
|
||||
::Guard.supervised_task(@g, :regular_with_arg, "given_path").should == "i'm a success"
|
||||
end
|
||||
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
|
||||
describe "tasks that raise an exception" do
|
||||
before(:each) { @g.stub!(:failing) { raise "I break your system" } }
|
||||
|
||||
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" do
|
||||
lambda { subject.supervised_task(@g, :failing) }.should change(subject.guards, :size).by(-1)
|
||||
subject.guards.should_not 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"
|
||||
it "should return the exception object" do
|
||||
failing_result = ::Guard.supervised_task(@g, :failing)
|
||||
failing_result.should be_kind_of(Exception)
|
||||
failing_result.message.should == 'I break your system'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -2,6 +2,8 @@ require 'rubygems'
|
||||
require 'guard'
|
||||
require 'rspec'
|
||||
|
||||
ENV["GUARD_ENV"] = 'test'
|
||||
|
||||
Dir["#{File.expand_path('..', __FILE__)}/support/**/*.rb"].each { |f| require f }
|
||||
|
||||
puts "Please do not update/create files while tests are running."
|
||||
@ -9,13 +11,11 @@ puts "Please do not update/create files while tests are running."
|
||||
RSpec.configure do |config|
|
||||
config.color_enabled = true
|
||||
|
||||
config.filter_run :focus => true
|
||||
config.run_all_when_everything_filtered = true
|
||||
|
||||
config.before(:each) do
|
||||
ENV["GUARD_ENV"] = 'test'
|
||||
@fixture_path = Pathname.new(File.expand_path('../fixtures/', __FILE__))
|
||||
end
|
||||
|
||||
config.after(:each) do
|
||||
ENV["GUARD_ENV"] = nil
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue
Block a user