Merge branch 'master' into stdin

Conflicts:
	lib/guard/listener.rb
This commit is contained in:
Thibaud Guillaume-Gentil 2011-09-01 21:28:03 +02:00
commit 5c1fb285e8
7 changed files with 122 additions and 12 deletions

View File

@ -1,3 +1,10 @@
## Master
### New features:
- Pull request [#130](https://github.com/guard/guard/pull/130): Adds ignore_paths option to DSL. ([@ianwhite][])
- Pull request [#128](https://github.com/guard/guard/pull/128): Users can add additional settings to ~/.guard.rb that augment the existing Guardfile. ([@tpope][])
## 0.6.2 - August 17, 2011
### Bugs fixes:

View File

@ -256,10 +256,13 @@ Optional:
* The `#watch` method allows you to define which files are supervised by this guard. An optional block can be added to overwrite the paths sent to the guard's `#run_on_change` method or to launch any arbitrary command.
* The `#group` method allows you to group several guards together. Groups to be run can be specified with the Guard DSL option `--group` (or `-g`). This comes in handy especially when you have a huge Guardfile and want to focus your development on a certain part. Guards that don't belong to a group are considered global and are always run.
* The `#ignore_paths` method allows you to ignore top level directories altogether. This comes is handy when you have large amounts of non-source data in you project. By default .bundle, .git, log, tmp, and vendor are ignored. Currently it is only possible to ignore the immediate descendants of the watched directory.
Example:
``` ruby
ignore_paths 'foo', 'bar'
group 'backend' do
guard 'bundler' do
watch('Gemfile')
@ -332,6 +335,21 @@ Group frontend:
livereload
```
User config file
----------------
If a .guard.rb is found in your home directory, it will be appended to
the Guardfile. This can be used for tasks you want guard to handle but
other users probably don't. For example, indexing your source tree with
[Ctags](http://ctags.sourceforge.net):
``` ruby
guard 'shell' do
watch(%r{^(?:app|lib)/.+\.rb$}) { `ctags -R` }
end
```
Create a new guard
------------------

View File

@ -7,7 +7,8 @@ module Guard
options.is_a?(Hash) or raise ArgumentError.new("evaluate_guardfile not passed a Hash!")
@@options = options.dup
instance_eval_guardfile(fetch_guardfile_contents)
fetch_guardfile_contents
instance_eval_guardfile(guardfile_contents_with_user_config)
UI.error "No guards found in Guardfile, please add at least one." if !::Guard.guards.nil? && ::Guard.guards.empty?
end
@ -72,14 +73,17 @@ module Guard
UI.error "The command file(#{@@options[:guardfile]}) seems to be empty."
exit 1
end
guardfile_contents
end
def guardfile_contents
@@options ? @@options[:guardfile_contents] : ""
end
def guardfile_contents_with_user_config
config = File.read(user_config_path) if File.exist?(user_config_path)
[guardfile_contents, config].join("\n")
end
def guardfile_path
@@options ? @@options[:guardfile_path] : ""
end
@ -102,6 +106,10 @@ module Guard
File.expand_path(File.join("~", ".Guardfile"))
end
def user_config_path
File.expand_path(File.join("~", ".guard.rb"))
end
end
def group(name, &guard_definition)
@ -126,5 +134,9 @@ module Guard
@watchers << ::Guard::Watcher.new(pattern, action)
end
def ignore_paths(*paths)
UI.info "Ignoring paths: #{paths.join(', ')}"
::Guard.listener.ignore_paths.push(*paths)
end
end
end

View File

@ -10,7 +10,8 @@ module Guard
class Listener
attr_reader :directory, :locked
DefaultIgnorePaths = %w[. .. .bundle .git log tmp vendor]
attr_reader :directory, :ignore_paths, :locked
def self.select_and_init(*a)
if mac? && Darwin.usable?
@ -25,12 +26,14 @@ module Guard
end
end
def initialize(directory=Dir.pwd, options={})
def initialize(directory = Dir.pwd, options = {})
@directory = directory.to_s
@sha1_checksums_hash = {}
@relativize_paths = options.fetch(:relativize_paths, true)
@changed_files = []
@locked = false
@ignore_paths = options[:ignore_paths] || DefaultIgnorePaths
update_last_event
start_reactor
end
@ -84,7 +87,7 @@ module Guard
@last_event = Time.now
end
def modified_files(dirs, options={})
def modified_files(dirs, options = {})
files = potentially_modified_files(dirs, options).select { |path| file_modified?(path) }
update_last_event
relativize_paths(files)
@ -114,14 +117,19 @@ module Guard
def relativize_paths?
!!@relativize_paths
end
# return children of the passed dirs that are not in the ignore_paths list
def exclude_ignored_paths(dirs, ignore_paths = self.ignore_paths)
Dir.glob(dirs.map { |d| "#{d.sub(%r{/+$}, '')}/*" }, File::FNM_DOTMATCH).reject do |path|
ignore_paths.include?(File.basename(path))
end
end
private
def potentially_modified_files(dirs, options={})
paths = Dir.glob(dirs.map { |d| "#{d.sub(%r{/+$}, '')}/*" }, File::FNM_DOTMATCH).reject do |path|
%w[. .. .bundle .git log tmp vendor].include?(File.basename(path))
end
paths = exclude_ignored_paths(dirs)
if options[:all]
paths.inject([]) do |array, path|
if File.file?(path)

View File

@ -1,7 +1,11 @@
require 'spec_helper'
describe Guard::DslDescriber do
before(:each) { ::Guard.stub!(:guards).and_return([mock('Guard')]) }
before(:each) do
::Guard.stub!(:guards).and_return([mock('Guard')])
user_config_path = File.expand_path(File.join('~', '.guard.rb'))
File.stub(:exist?).with(user_config_path) { false }
end
subject { described_class }

View File

@ -5,12 +5,18 @@ describe Guard::Dsl do
before(:each) do
@local_guardfile_path = File.join(Dir.pwd, 'Guardfile')
@home_guardfile_path = File.expand_path(File.join("~", ".Guardfile"))
@user_config_path = File.expand_path(File.join("~", ".guard.rb"))
::Guard.stub!(:options).and_return(:debug => true)
::Guard.stub!(:guards).and_return([mock('Guard')])
end
def self.disable_user_config
before(:each) { File.stub(:exist?).with(@user_config_path) { false } }
end
describe "it should select the correct data source for Guardfile" do
before(:each) { ::Guard::Dsl.stub!(:instance_eval_guardfile) }
disable_user_config
it "should use a string for initializing" do
Guard::UI.should_not_receive(:error)
@ -51,6 +57,15 @@ describe Guard::Dsl do
lambda { subject.evaluate_guardfile(:guardfile => '/abc/Guardfile') }.should_not raise_error
subject.guardfile_contents.should == "guard :foo"
end
it 'should append the user config file if present' do
fake_guardfile('/abc/Guardfile', "guard :foo")
fake_guardfile(@user_config_path, "guard :bar")
Guard::UI.should_not_receive(:error)
lambda { subject.evaluate_guardfile(:guardfile => '/abc/Guardfile') }.should_not raise_error
subject.guardfile_contents_with_user_config.should == "guard :foo\nguard :bar"
end
end
it "displays an error message when no Guardfile is found" do
@ -68,6 +83,7 @@ describe Guard::Dsl do
describe "correctly reads data from its valid data source" do
before(:each) { ::Guard::Dsl.stub!(:instance_eval_guardfile) }
disable_user_config
it "reads correctly from a string" do
lambda { subject.evaluate_guardfile(:guardfile_contents => valid_guardfile_string) }.should_not raise_error
@ -199,7 +215,21 @@ describe Guard::Dsl do
end
end
describe "#ignore_paths" do
disable_user_config
it "adds the paths to the listener's ignore_paths" do
::Guard.stub!(:listener).and_return(mock('Listener'))
::Guard.listener.should_receive(:ignore_paths).and_return(ignore_paths = ['faz'])
subject.evaluate_guardfile(:guardfile_contents => "ignore_paths 'foo', 'bar'")
ignore_paths.should == ['faz', 'foo', 'bar']
end
end
describe "#group" do
disable_user_config
it "evaluates only the specified string group" do
::Guard.should_receive(:add_guard).with(:pow, [], { :group => :default })
::Guard.should_receive(:add_guard).with(:test, [], { :group => :w })
@ -242,6 +272,8 @@ describe Guard::Dsl do
end
describe "#guard" do
disable_user_config
it "loads a guard specified as a quoted string from the DSL" do
::Guard.should_receive(:add_guard).with(:test, [], { :group => :default })
@ -274,6 +306,8 @@ describe Guard::Dsl do
end
describe "#watch" do
disable_user_config
it "should receive watchers when specified" do
guardfile_with_watchers = "guard 'test' do
watch('a') { 'b' }

View File

@ -158,5 +158,32 @@ describe Guard::Listener do
end
end
end
describe "#ignore_paths" do
it "defaults to the default ignore paths" do
subject.new.ignore_paths.should == Guard::Listener::DefaultIgnorePaths
end
it "can be added to via :ignore_paths option" do
listener = subject.new 'path', :ignore_paths => ['foo', 'bar']
listener.ignore_paths.should include('foo', 'bar')
end
end
describe "#exclude_ignored_paths [<dirs>]" do
let(:ignore_paths) { nil }
subject { described_class.new(@fixture_path, {:ignore_paths => ignore_paths}) }
it "returns children of <dirs>" do
subject.exclude_ignored_paths(["spec/fixtures"]).should =~ ["spec/fixtures/.dotfile", "spec/fixtures/folder1", "spec/fixtures/Guardfile"]
end
describe "when ignore_paths set to some of <dirs> children" do
let(:ignore_paths) { ['Guardfile', '.dotfile'] }
it "excludes the ignored paths" do
subject.exclude_ignored_paths(["spec/fixtures"]).should =~ ["spec/fixtures/folder1"]
end
end
end
end