Merge branch 'master' into hook
Conflicts: Guardfile lib/guard.rb lib/guard/dsl.rb spec/guard/interactor_spec.rb spec/guard/listeners/darwin_spec.rb
This commit is contained in:
commit
11495687f4
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,5 +1,8 @@
|
|||||||
pkg/*
|
pkg/*
|
||||||
*.gem
|
*.gem
|
||||||
|
*.rbc
|
||||||
|
.*.swp
|
||||||
|
*.bak
|
||||||
.bundle
|
.bundle
|
||||||
Gemfile.lock
|
Gemfile.lock
|
||||||
|
|
||||||
|
@ -2,9 +2,13 @@ rvm:
|
|||||||
- 1.8.7
|
- 1.8.7
|
||||||
- 1.9.2
|
- 1.9.2
|
||||||
- ree
|
- ree
|
||||||
|
- jruby
|
||||||
|
- rbx
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
- hook
|
- hook
|
||||||
|
- stdin
|
||||||
|
- jruby_on_travis
|
||||||
notifications:
|
notifications:
|
||||||
irc: "irc.freenode.org#guard"
|
irc: "irc.freenode.org#guard"
|
52
CHANGELOG.md
52
CHANGELOG.md
@ -1,3 +1,42 @@
|
|||||||
|
## Master
|
||||||
|
|
||||||
|
### Major Changes
|
||||||
|
|
||||||
|
- Posix Signals handlers (`Ctrl-C`, `Ctrl-\` and `Ctrl-Z`) are no more supported and replaced by `$stdin.gets`. Please refer to the "Interactions" section in the README for more information. ([@thibaudgg][])
|
||||||
|
- JRuby support (beta). ([@thibaudgg][])
|
||||||
|
- Rubinius support (beta). ([@thibaudgg][])
|
||||||
|
|
||||||
|
### New feature:
|
||||||
|
|
||||||
|
- Ability to 'pause' files modification listening. Please refer to the "Interactions" section in the README for more information. ([@thibaudgg][])
|
||||||
|
|
||||||
|
### Improvement:
|
||||||
|
|
||||||
|
- Remove the need to scan the whole directory after guard's `run_on_change` method. ([@thibaudgg][])
|
||||||
|
|
||||||
|
## 0.6.3 - September 1, 2011
|
||||||
|
|
||||||
|
### 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:
|
||||||
|
|
||||||
|
- Re-add the possibility to use the `growl` gem since the `growl_notify` gem this is currently known to not work in conjunction with Spork. ([@netzpirat][])
|
||||||
|
- Ensure that scoped groups and group name are symbolized before checking for inclusion. ([@rymai][])
|
||||||
|
|
||||||
|
### New features:
|
||||||
|
|
||||||
|
- Groups are now stored in a @groups variable (will be used for future features). ([@rymai][])
|
||||||
|
- Guards will now receive their group in the options hash at initialization (will be used for future features). ([@rymai][])
|
||||||
|
|
||||||
|
### Improvement:
|
||||||
|
|
||||||
|
- Explain the growl/growl_notify differences in the README. ([@netzpirat][])
|
||||||
|
|
||||||
## 0.6.1 - August 15, 2011
|
## 0.6.1 - August 15, 2011
|
||||||
|
|
||||||
### Bugs fixes:
|
### Bugs fixes:
|
||||||
@ -12,11 +51,11 @@
|
|||||||
- Pull request [#107](https://github.com/guard/guard/pull/107): Small spelling fix. ([@dnagir][])
|
- Pull request [#107](https://github.com/guard/guard/pull/107): Small spelling fix. ([@dnagir][])
|
||||||
- Dir.glob now ignores files that don't need to be watched. ([@rymai][])
|
- Dir.glob now ignores files that don't need to be watched. ([@rymai][])
|
||||||
|
|
||||||
### New features
|
### New features:
|
||||||
|
|
||||||
- Pull request [#112](https://github.com/guard/guard/pull/112): Add `list` command to CLI. ([@docwhat][])
|
- Pull request [#112](https://github.com/guard/guard/pull/112): Add `list` command to CLI. ([@docwhat][])
|
||||||
|
|
||||||
### Improvements
|
### Improvements:
|
||||||
|
|
||||||
- Pull request [#99](https://github.com/guard/guard/pull/99): [OS X] Switch from growl gem to growl_notify gem. ([@johnbintz][])
|
- Pull request [#99](https://github.com/guard/guard/pull/99): [OS X] Switch from growl gem to growl_notify gem. ([@johnbintz][])
|
||||||
- Pull request [#115](https://github.com/guard/guard/pull/115): [Linux] Add ':transient => true' to default libnotify options. ([@zonque][])
|
- Pull request [#115](https://github.com/guard/guard/pull/115): [Linux] Add ':transient => true' to default libnotify options. ([@zonque][])
|
||||||
@ -35,12 +74,12 @@
|
|||||||
|
|
||||||
## 0.5.0 - July 2, 2011
|
## 0.5.0 - July 2, 2011
|
||||||
|
|
||||||
### New features
|
### New features:
|
||||||
|
|
||||||
- Guard::Ego is now part of Guard, so Guardfile is automagically re-evaluated when modified. ([@thibaudgg][])
|
- Guard::Ego is now part of Guard, so Guardfile is automagically re-evaluated when modified. ([@thibaudgg][])
|
||||||
- Pull request [#91](https://github.com/guard/guard/pull/91): Show Guards in Guardfile with the `guard -T`. ([@johnbintz][])
|
- Pull request [#91](https://github.com/guard/guard/pull/91): Show Guards in Guardfile with the `guard -T`. ([@johnbintz][])
|
||||||
|
|
||||||
### Improvements
|
### Improvements:
|
||||||
|
|
||||||
- Issue [#98](https://github.com/guard/guard/issues/98): Multiple calls per watch event on linux with rb-inotify. ([@jeffutter][] & [@netzpirat][])
|
- Issue [#98](https://github.com/guard/guard/issues/98): Multiple calls per watch event on linux with rb-inotify. ([@jeffutter][] & [@netzpirat][])
|
||||||
- Pull request [#94](https://github.com/guard/guard/pull/94): Show backtrace in terminal when a problem with a watch action occurs. ([@capotej][])
|
- Pull request [#94](https://github.com/guard/guard/pull/94): Show backtrace in terminal when a problem with a watch action occurs. ([@capotej][])
|
||||||
@ -62,7 +101,7 @@
|
|||||||
|
|
||||||
## 0.4.1 - June 7, 2011
|
## 0.4.1 - June 7, 2011
|
||||||
|
|
||||||
### Improvements
|
### Improvements:
|
||||||
|
|
||||||
- Pull request [#77](https://github.com/guard/guard/pull/77): Refactor `get_guard_class` to first try the constant and fallback to require + various tweaks. ([@mislav][])
|
- Pull request [#77](https://github.com/guard/guard/pull/77): Refactor `get_guard_class` to first try the constant and fallback to require + various tweaks. ([@mislav][])
|
||||||
- Notifier improvement, don't use system notification library if could not be required. ([@yannlugrin][])
|
- Notifier improvement, don't use system notification library if could not be required. ([@yannlugrin][])
|
||||||
@ -78,7 +117,7 @@
|
|||||||
- Pull request [#73](https://github.com/guard/guard/pull/73): Allow DSL's `group` method to accept a Symbol as group name. ([@johnbintz][])
|
- Pull request [#73](https://github.com/guard/guard/pull/73): Allow DSL's `group` method to accept a Symbol as group name. ([@johnbintz][])
|
||||||
- Pull request [#51](https://github.com/guard/guard/pull/51): Allow options (like `:priority`) to be passed through to the Notifier. ([@indirect][] & [@netzpirat][])
|
- Pull request [#51](https://github.com/guard/guard/pull/51): Allow options (like `:priority`) to be passed through to the Notifier. ([@indirect][] & [@netzpirat][])
|
||||||
|
|
||||||
### Improvements
|
### Improvements:
|
||||||
|
|
||||||
- Pull request [#74](https://github.com/guard/guard/pull/74): Added link definitions to make the CHANGELOG more DRY! That's for sure now, we have the cleanest CHANGELOG ever! (even the link definitions are sorted alphabetically!) ([@pcreux][])
|
- Pull request [#74](https://github.com/guard/guard/pull/74): Added link definitions to make the CHANGELOG more DRY! That's for sure now, we have the cleanest CHANGELOG ever! (even the link definitions are sorted alphabetically!) ([@pcreux][])
|
||||||
|
|
||||||
@ -210,6 +249,7 @@
|
|||||||
[@Gazer]: https://github.com/Gazer
|
[@Gazer]: https://github.com/Gazer
|
||||||
[@gix]: https://github.com/gix
|
[@gix]: https://github.com/gix
|
||||||
[@hashrocketeer]: https://github.com/hashrocketeer
|
[@hashrocketeer]: https://github.com/hashrocketeer
|
||||||
|
[@ianwhite]: https://github.com/ianwhite
|
||||||
[@indirect]: https://github.com/indirect
|
[@indirect]: https://github.com/indirect
|
||||||
[@jeffutter]: https://github.com/jeffutter
|
[@jeffutter]: https://github.com/jeffutter
|
||||||
[@johnbintz]: https://github.com/johnbintz
|
[@johnbintz]: https://github.com/johnbintz
|
||||||
|
2
Gemfile
2
Gemfile
@ -12,7 +12,7 @@ require 'rbconfig'
|
|||||||
|
|
||||||
if RbConfig::CONFIG['target_os'] =~ /darwin/i
|
if RbConfig::CONFIG['target_os'] =~ /darwin/i
|
||||||
gem 'rb-fsevent', '>= 0.4.0', :require => false
|
gem 'rb-fsevent', '>= 0.4.0', :require => false
|
||||||
gem 'growl_notify', :require => false
|
gem 'growl', '~> 1.0.3', :require => false
|
||||||
end
|
end
|
||||||
if RbConfig::CONFIG['target_os'] =~ /linux/i
|
if RbConfig::CONFIG['target_os'] =~ /linux/i
|
||||||
gem 'rb-inotify', '>= 0.8.5', :require => false
|
gem 'rb-inotify', '>= 0.8.5', :require => false
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
guard :rspec, :version => 2, :keep_failed => false, :cli => '-f doc' do
|
guard :rspec, :version => 2, :all_on_start => false, :all_after_pass => false, :keep_failed => false, :cli => '--format doc' do
|
||||||
watch(%r{^spec/.+_spec\.rb$})
|
watch(%r{^spec/.+_spec\.rb$})
|
||||||
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
||||||
watch('spec/spec_helper.rb') { "spec" }
|
watch('spec/spec_helper.rb') { "spec" }
|
||||||
|
79
README.md
79
README.md
@ -1,4 +1,4 @@
|
|||||||
Guard [![Build Status](https://secure.travis-ci.org/guard/guard.png)](http://travis-ci.org/guard/guard)
|
Guard [![Build Status](http://travis-ci.org/guard/guard.png)](http://travis-ci.org/guard/guard)
|
||||||
=====
|
=====
|
||||||
|
|
||||||
Guard is a command line tool that easily handle events on files modifications.
|
Guard is a command line tool that easily handle events on files modifications.
|
||||||
@ -13,14 +13,13 @@ Features
|
|||||||
* [Directory Change Notification](http://msdn.microsoft.com/en-us/library/aa365261\(VS.85\).aspx) support on Windows ([rb-fchange, >= 0.0.2](https://rubygems.org/gems/rb-fchange) required).
|
* [Directory Change Notification](http://msdn.microsoft.com/en-us/library/aa365261\(VS.85\).aspx) support on Windows ([rb-fchange, >= 0.0.2](https://rubygems.org/gems/rb-fchange) required).
|
||||||
* Polling on the other operating systems (help us to support more OS).
|
* Polling on the other operating systems (help us to support more OS).
|
||||||
* Automatic & Super fast (when polling is not used) files modifications detection (even new files are detected).
|
* Automatic & Super fast (when polling is not used) files modifications detection (even new files are detected).
|
||||||
* Growl notifications ([growlnotify](http://growl.info/documentation/growlnotify.php) & [growl gem](https://rubygems.org/gems/growl) required).
|
* Visual notifications on Mac OSX ([Growl](http://growl.info)), Linux ([Libnotify](http://developer.gnome.org/libnotify)) and Windows ([Notifu](http://www.paralint.com/projects/notifu)).
|
||||||
* Libnotify notifications ([libnotify gem](https://rubygems.org/gems/libnotify) required).
|
|
||||||
* Tested against Ruby 1.8.7, 1.9.2 and REE.
|
* Tested against Ruby 1.8.7, 1.9.2 and REE.
|
||||||
|
|
||||||
Screencast
|
Screencast
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Ryan Bates made a screencast on Guard, you can view it here: http://railscasts.com/episodes/264-guard
|
Ryan Bates made a Railscast on Guard, you can view it here: http://railscasts.com/episodes/264-guard
|
||||||
|
|
||||||
Install
|
Install
|
||||||
-------
|
-------
|
||||||
@ -31,12 +30,18 @@ Install the gem:
|
|||||||
$ gem install guard
|
$ gem install guard
|
||||||
```
|
```
|
||||||
|
|
||||||
Add it to your Gemfile (inside the `development` group):
|
Or add it to your Gemfile (inside the `development` group):
|
||||||
|
|
||||||
``` ruby
|
``` ruby
|
||||||
gem 'guard'
|
gem 'guard'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
and install it via Bundler:
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
$ bundle install
|
||||||
|
```
|
||||||
|
|
||||||
Generate an empty Guardfile with:
|
Generate an empty Guardfile with:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
@ -44,6 +49,7 @@ $ guard init
|
|||||||
```
|
```
|
||||||
|
|
||||||
You may optionally place a .Guardfile in your home directory to use it across multiple projects.
|
You may optionally place a .Guardfile in your home directory to use it across multiple projects.
|
||||||
|
Also note that if a `.guard.rb` is found in your home directory, it will be appended to the Guardfile.
|
||||||
|
|
||||||
Add the guards you need to your Guardfile (see the existing guards below).
|
Add the guards you need to your Guardfile (see the existing guards below).
|
||||||
|
|
||||||
@ -55,28 +61,42 @@ Install the rb-fsevent gem for [FSEvent](http://en.wikipedia.org/wiki/FSEvents)
|
|||||||
$ gem install rb-fsevent
|
$ gem install rb-fsevent
|
||||||
```
|
```
|
||||||
|
|
||||||
Install the growl_notify gem if you want notification support:
|
You have two possibilities:
|
||||||
|
|
||||||
|
Use the [growl_notify gem](https://rubygems.org/gems/growl_notify) (recommended):
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
$ gem install growl_notify
|
$ gem install growl_notify
|
||||||
```
|
```
|
||||||
|
|
||||||
And add it to your Gemfile:
|
Use the [growlnotify](http://growl.info/extras.php#growlnotify) (cli tool for growl) + the [growl gem](https://rubygems.org/gems/growl).
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
$ brew install growlnotify
|
||||||
|
$ gem install growl
|
||||||
|
```
|
||||||
|
|
||||||
|
And add them to your Gemfile:
|
||||||
|
|
||||||
``` ruby
|
``` ruby
|
||||||
gem 'rb-fsevent'
|
gem 'rb-fsevent'
|
||||||
gem 'growl_notify'
|
gem 'growl_notify' # or gem 'growl'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The difference between growl and growl_notify is that growl_notify uses AppleScript to
|
||||||
|
display a message, whereas growl uses the `growlnotify` command. In general the AppleScript
|
||||||
|
approach is preferred, but you may also use the older growl gem. Have a look at the
|
||||||
|
[Guard Wiki](https://github.com/guard/guard/wiki/Use-growl_notify-or-growl-gem) for more information.
|
||||||
|
|
||||||
### On Linux
|
### On Linux
|
||||||
|
|
||||||
Install the rb-inotify gem for [inotify](http://en.wikipedia.org/wiki/Inotify) support:
|
Install the [rb-inotify gem](https://rubygems.org/gems/rb-inotify) for [inotify](http://en.wikipedia.org/wiki/Inotify) support:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
$ gem install rb-inotify
|
$ gem install rb-inotify
|
||||||
```
|
```
|
||||||
|
|
||||||
Install the Libnotify gem if you want notification support:
|
Install the [libnotify gem](https://rubygems.org/gems/libnotify) if you want visual notification support:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
$ gem install libnotify
|
$ gem install libnotify
|
||||||
@ -91,19 +111,19 @@ gem 'libnotify'
|
|||||||
|
|
||||||
### On Windows
|
### On Windows
|
||||||
|
|
||||||
Install the rb-fchange gem for [Directory Change Notification](http://msdn.microsoft.com/en-us/library/aa365261\(VS.85\).aspx) support:
|
Install the [rb-fchange gem](https://rubygems.org/gems/rb-fchange) for [Directory Change Notification](http://msdn.microsoft.com/en-us/library/aa365261\(VS.85\).aspx) support:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
$ gem install rb-fchange
|
$ gem install rb-fchange
|
||||||
```
|
```
|
||||||
|
|
||||||
Install the win32console gem if you want colors in your terminal:
|
Install the [win32console gem](https://rubygems.org/gems/win32console) if you want colors in your terminal:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
$ gem install win32console
|
$ gem install win32console
|
||||||
```
|
```
|
||||||
|
|
||||||
Install the Notifu gem if you want notification support:
|
Install the [rb-notifu gem](https://rubygems.org/gems/rb-notifu) if you want visual notification support:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
$ gem install rb-notifu
|
$ gem install rb-notifu
|
||||||
@ -114,6 +134,7 @@ And add them to your Gemfile:
|
|||||||
``` ruby
|
``` ruby
|
||||||
gem 'rb-fchange'
|
gem 'rb-fchange'
|
||||||
gem 'rb-notifu'
|
gem 'rb-notifu'
|
||||||
|
gem 'win32console'
|
||||||
```
|
```
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
@ -198,16 +219,17 @@ An exhaustive list of options is available with:
|
|||||||
$ guard help [TASK]
|
$ guard help [TASK]
|
||||||
```
|
```
|
||||||
|
|
||||||
Signal handlers
|
Interactions
|
||||||
---------------
|
------------
|
||||||
|
|
||||||
Signal handlers are used to interact with Guard:
|
**From version >= 0.7.0 Posix Signal handlers are no more used to interact with Guard.**
|
||||||
|
|
||||||
* `Ctrl-C` - Calls each guard's `#stop` method, in the same order they are declared in the Guardfile, and then quits Guard itself.
|
When Guard do nothing you can interact with by entering a command + hitting enter:
|
||||||
* `Ctrl-\` - Calls each guard's `#run_all` method, in the same order they are declared in the Guardfile.
|
|
||||||
* `Ctrl-Z` - Calls each guard's `#reload` method, in the same order they are declared in the Guardfile.
|
|
||||||
|
|
||||||
You can read more about [configure the signal keyboard shortcuts](https://github.com/guard/guard/wiki/Configure-keyboard-shortcuts) in the wiki.
|
* `stop|quit|exit|s|q|e + enter` - Calls each guard's `#stop` method, in the same order they are declared in the Guardfile, and then quits Guard itself.
|
||||||
|
* `reload|r|z + enter` - Calls each guard's `#reload` method, in the same order they are declared in the Guardfile.
|
||||||
|
* `pause|p + enter` - Toggle files modification listening. Useful when switching git branches.
|
||||||
|
* `just enter (no commands)` - Calls each guard's `#run_all` method, in the same order they are declared in the Guardfile.
|
||||||
|
|
||||||
Available Guards
|
Available Guards
|
||||||
----------------
|
----------------
|
||||||
@ -249,10 +271,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 `#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 `#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:
|
Example:
|
||||||
|
|
||||||
``` ruby
|
``` ruby
|
||||||
|
ignore_paths 'foo', 'bar'
|
||||||
|
|
||||||
group 'backend' do
|
group 'backend' do
|
||||||
guard 'bundler' do
|
guard 'bundler' do
|
||||||
watch('Gemfile')
|
watch('Gemfile')
|
||||||
@ -325,6 +350,20 @@ Group frontend:
|
|||||||
livereload
|
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
|
Create a new guard
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
76
lib/guard.rb
76
lib/guard.rb
@ -10,14 +10,15 @@ module Guard
|
|||||||
autoload :Hook, 'guard/hook'
|
autoload :Hook, 'guard/hook'
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
attr_accessor :options, :guards, :groups, :listener
|
attr_accessor :options, :guards, :groups, :interactor, :listener
|
||||||
|
|
||||||
# initialize this singleton
|
# initialize this singleton
|
||||||
def setup(options = {})
|
def setup(options = {})
|
||||||
@options = options
|
@options = options
|
||||||
@listener = Listener.select_and_init(@options[:watchdir] ? File.expand_path(@options[:watchdir]) : Dir.pwd)
|
|
||||||
@groups = [:default]
|
|
||||||
@guards = []
|
@guards = []
|
||||||
|
@groups = [:default]
|
||||||
|
@interactor = Interactor.new
|
||||||
|
@listener = Listener.select_and_init(@options[:watchdir] ? File.expand_path(@options[:watchdir]) : Dir.pwd)
|
||||||
|
|
||||||
@options[:notify] && ENV["GUARD_NOTIFY"] != 'false' ? Notifier.turn_on : Notifier.turn_off
|
@options[:notify] && ENV["GUARD_NOTIFY"] != 'false' ? Notifier.turn_on : Notifier.turn_off
|
||||||
|
|
||||||
@ -28,24 +29,54 @@ module Guard
|
|||||||
end
|
end
|
||||||
|
|
||||||
def start(options = {})
|
def start(options = {})
|
||||||
Interactor.init_signal_traps
|
|
||||||
|
|
||||||
setup(options)
|
setup(options)
|
||||||
|
|
||||||
Dsl.evaluate_guardfile(options)
|
Dsl.evaluate_guardfile(options)
|
||||||
|
|
||||||
listener.on_change do |files|
|
listener.on_change do |files|
|
||||||
Dsl.reevaluate_guardfile if Watcher.match_guardfile?(files)
|
Dsl.reevaluate_guardfile if Watcher.match_guardfile?(files)
|
||||||
|
listener.changed_files += files if Watcher.match_files?(guards, files)
|
||||||
run { run_on_change_for_all_guards(files) } if Watcher.match_files?(guards, files)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
UI.info "Guard is now watching at '#{listener.directory}'"
|
UI.info "Guard is now watching at '#{listener.directory}'"
|
||||||
guards.each { |guard| supervised_task(guard, :start) }
|
guards.each { |guard| supervised_task(guard, :start) }
|
||||||
|
|
||||||
|
interactor.start
|
||||||
listener.start
|
listener.start
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_on_change_for_all_guards(files)
|
def stop
|
||||||
|
UI.info "Bye bye...", :reset => true
|
||||||
|
listener.stop
|
||||||
|
guards.each { |guard| supervised_task(guard, :stop) }
|
||||||
|
abort
|
||||||
|
end
|
||||||
|
|
||||||
|
def reload
|
||||||
|
run do
|
||||||
|
guards.each { |guard| supervised_task(guard, :reload) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_all
|
||||||
|
run do
|
||||||
|
guards.each { |guard| supervised_task(guard, :run_all) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pause
|
||||||
|
if listener.locked
|
||||||
|
UI.info "Un-paused files modification listening", :reset => true
|
||||||
|
listener.clear_changed_files
|
||||||
|
listener.unlock
|
||||||
|
else
|
||||||
|
UI.info "Paused files modification listening", :reset => true
|
||||||
|
listener.lock
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_on_change(files)
|
||||||
|
run do
|
||||||
guards.each do |guard|
|
guards.each do |guard|
|
||||||
paths = Watcher.match_files(guard, files)
|
paths = Watcher.match_files(guard, files)
|
||||||
unless paths.empty?
|
unless paths.empty?
|
||||||
@ -53,14 +84,21 @@ module Guard
|
|||||||
supervised_task(guard, :run_on_change, paths)
|
supervised_task(guard, :run_on_change, paths)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Reparse the whole directory to catch new files modified during the guards run
|
|
||||||
new_modified_files = listener.modified_files([listener.directory], :all => true)
|
|
||||||
if !new_modified_files.empty? && Watcher.match_files?(guards, new_modified_files)
|
|
||||||
run { run_on_change_for_all_guards(new_modified_files) }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
listener.lock
|
||||||
|
interactor.lock
|
||||||
|
UI.clear if options[:clear]
|
||||||
|
begin
|
||||||
|
yield
|
||||||
|
rescue Interrupt
|
||||||
|
end
|
||||||
|
interactor.unlock
|
||||||
|
listener.unlock
|
||||||
|
end
|
||||||
|
|
||||||
# Let a guard execute its task but
|
# Let a guard execute its task but
|
||||||
# fire it if his work leads to a system failure
|
# fire it if his work leads to a system failure
|
||||||
def supervised_task(guard, task_to_supervise, *args)
|
def supervised_task(guard, task_to_supervise, *args)
|
||||||
@ -76,22 +114,12 @@ module Guard
|
|||||||
return ex
|
return ex
|
||||||
end
|
end
|
||||||
|
|
||||||
def run
|
|
||||||
listener.stop
|
|
||||||
UI.clear if options[:clear]
|
|
||||||
begin
|
|
||||||
yield
|
|
||||||
rescue Interrupt
|
|
||||||
end
|
|
||||||
listener.start
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_guard(name, watchers = [], callbacks = [], options = {})
|
def add_guard(name, watchers = [], callbacks = [], options = {})
|
||||||
if name.to_sym == :ego
|
if name.to_sym == :ego
|
||||||
UI.deprecation("Guard::Ego is now part of Guard. You can remove it from your Guardfile.")
|
UI.deprecation("Guard::Ego is now part of Guard. You can remove it from your Guardfile.")
|
||||||
else
|
else
|
||||||
guard_class = get_guard_class(name)
|
guard_class = get_guard_class(name)
|
||||||
callbacks.each { |callback| ::Guard::Hook.add_callback(callback[:listener], guard_class, callback[:events]) }
|
callbacks.each { |callback| Hook.add_callback(callback[:listener], guard_class, callback[:events]) }
|
||||||
@guards << guard_class.new(watchers, options)
|
@guards << guard_class.new(watchers, options)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -7,7 +7,8 @@ module Guard
|
|||||||
options.is_a?(Hash) or raise ArgumentError.new("evaluate_guardfile not passed a Hash!")
|
options.is_a?(Hash) or raise ArgumentError.new("evaluate_guardfile not passed a Hash!")
|
||||||
|
|
||||||
@@options = options.dup
|
@@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?
|
UI.error "No guards found in Guardfile, please add at least one." if !::Guard.guards.nil? && ::Guard.guards.empty?
|
||||||
end
|
end
|
||||||
@ -72,14 +73,17 @@ module Guard
|
|||||||
UI.error "The command file(#{@@options[:guardfile]}) seems to be empty."
|
UI.error "The command file(#{@@options[:guardfile]}) seems to be empty."
|
||||||
exit 1
|
exit 1
|
||||||
end
|
end
|
||||||
|
|
||||||
guardfile_contents
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def guardfile_contents
|
def guardfile_contents
|
||||||
@@options ? @@options[:guardfile_contents] : ""
|
@@options ? @@options[:guardfile_contents] : ""
|
||||||
end
|
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
|
def guardfile_path
|
||||||
@@options ? @@options[:guardfile_path] : ""
|
@@options ? @@options[:guardfile_path] : ""
|
||||||
end
|
end
|
||||||
@ -102,6 +106,10 @@ module Guard
|
|||||||
File.expand_path(File.join("~", ".Guardfile"))
|
File.expand_path(File.join("~", ".Guardfile"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user_config_path
|
||||||
|
File.expand_path(File.join("~", ".guard.rb"))
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def group(name, &guard_definition)
|
def group(name, &guard_definition)
|
||||||
@ -132,5 +140,9 @@ module Guard
|
|||||||
@callbacks << { :events => events, :listener => listener }
|
@callbacks << { :events => events, :listener => listener }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def ignore_paths(*paths)
|
||||||
|
UI.info "Ignoring paths: #{paths.join(', ')}"
|
||||||
|
::Guard.listener.ignore_paths.push(*paths)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,54 +1,40 @@
|
|||||||
module Guard
|
module Guard
|
||||||
module Interactor
|
class Interactor
|
||||||
extend self
|
|
||||||
|
|
||||||
def run_all
|
attr_reader :locked
|
||||||
::Guard.run do
|
|
||||||
::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :run_all) }
|
def initialize
|
||||||
end
|
@locked = false
|
||||||
end
|
end
|
||||||
|
|
||||||
def stop
|
def start
|
||||||
UI.info "Bye bye...", :reset => true
|
return if ENV["GUARD_ENV"] == 'test'
|
||||||
::Guard.listener.stop
|
Thread.new do
|
||||||
::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :stop) }
|
loop do
|
||||||
abort
|
if (entry = $stdin.gets) && !@locked
|
||||||
end
|
entry.gsub! /\n/, ''
|
||||||
|
case entry
|
||||||
def reload
|
when 'stop', 'quit', 'exit', 's', 'q', 'e'
|
||||||
::Guard.run do
|
::Guard.stop
|
||||||
::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :reload) }
|
when 'reload', 'r', 'z'
|
||||||
end
|
::Guard.reload
|
||||||
end
|
when 'pause', 'p'
|
||||||
|
::Guard.pause
|
||||||
def self.init_signal_traps
|
|
||||||
# Run all (Ctrl-\)
|
|
||||||
if Signal.list.has_key?('QUIT')
|
|
||||||
Signal.trap('QUIT') do
|
|
||||||
run_all
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
UI.info "Your system doesn't support QUIT signal, so Ctrl-\\ (Run all) won't work"
|
::Guard.run_all
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Stop (Ctrl-C)
|
def lock
|
||||||
if Signal.list.has_key?('INT')
|
@locked = true
|
||||||
Signal.trap('INT') do
|
|
||||||
stop
|
|
||||||
end
|
|
||||||
else
|
|
||||||
UI.info "Your system doesn't support INT signal, so Ctrl-C (Stop) won't work"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Reload (Ctrl-Z)
|
def unlock
|
||||||
if Signal.list.has_key?('TSTP')
|
@locked = false
|
||||||
Signal.trap('TSTP') do
|
|
||||||
reload
|
|
||||||
end
|
|
||||||
else
|
|
||||||
UI.info "Your system doesn't support TSTP signal, so Ctrl-Z (Reload) won't work"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -10,7 +10,9 @@ module Guard
|
|||||||
|
|
||||||
class Listener
|
class Listener
|
||||||
|
|
||||||
attr_reader :directory
|
DefaultIgnorePaths = %w[. .. .bundle .git log tmp vendor]
|
||||||
|
attr_accessor :changed_files
|
||||||
|
attr_reader :directory, :ignore_paths, :locked
|
||||||
|
|
||||||
def self.select_and_init(*a)
|
def self.select_and_init(*a)
|
||||||
if mac? && Darwin.usable?
|
if mac? && Darwin.usable?
|
||||||
@ -25,11 +27,32 @@ module Guard
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(directory=Dir.pwd, options={})
|
def initialize(directory = Dir.pwd, options = {})
|
||||||
@directory = directory.to_s
|
@directory = directory.to_s
|
||||||
@sha1_checksums_hash = {}
|
@sha1_checksums_hash = {}
|
||||||
@relativize_paths = options.fetch(:relativize_paths, true)
|
@relativize_paths = options.fetch(:relativize_paths, true)
|
||||||
|
@changed_files = []
|
||||||
|
@locked = false
|
||||||
|
@ignore_paths = DefaultIgnorePaths
|
||||||
|
@ignore_paths |= options[:ignore_paths] if options[:ignore_paths]
|
||||||
|
|
||||||
update_last_event
|
update_last_event
|
||||||
|
start_reactor
|
||||||
|
end
|
||||||
|
|
||||||
|
def start_reactor
|
||||||
|
return if ENV["GUARD_ENV"] == 'test'
|
||||||
|
Thread.new do
|
||||||
|
loop do
|
||||||
|
if @changed_files != [] && !@locked
|
||||||
|
changed_files = @changed_files.dup
|
||||||
|
clear_changed_files
|
||||||
|
::Guard.run_on_change(changed_files)
|
||||||
|
else
|
||||||
|
sleep 0.1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def start
|
def start
|
||||||
@ -39,6 +62,18 @@ module Guard
|
|||||||
def stop
|
def stop
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def lock
|
||||||
|
@locked = true
|
||||||
|
end
|
||||||
|
|
||||||
|
def unlock
|
||||||
|
@locked = false
|
||||||
|
end
|
||||||
|
|
||||||
|
def clear_changed_files
|
||||||
|
@changed_files.clear
|
||||||
|
end
|
||||||
|
|
||||||
def on_change(&callback)
|
def on_change(&callback)
|
||||||
@callback = callback
|
@callback = callback
|
||||||
end
|
end
|
||||||
@ -47,9 +82,10 @@ module Guard
|
|||||||
@last_event = Time.now
|
@last_event = Time.now
|
||||||
end
|
end
|
||||||
|
|
||||||
def modified_files(dirs, options={})
|
def modified_files(dirs, options = {})
|
||||||
files = potentially_modified_files(dirs, options).select { |path| file_modified?(path) }
|
last_event = @last_event
|
||||||
update_last_event
|
update_last_event
|
||||||
|
files = potentially_modified_files(dirs, options).select { |path| file_modified?(path, last_event) }
|
||||||
relativize_paths(files)
|
relativize_paths(files)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -78,12 +114,17 @@ module Guard
|
|||||||
!!@relativize_paths
|
!!@relativize_paths
|
||||||
end
|
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
|
private
|
||||||
|
|
||||||
def potentially_modified_files(dirs, options={})
|
def potentially_modified_files(dirs, options={})
|
||||||
paths = Dir.glob(dirs.map { |d| "#{d.sub(%r{/+$}, '')}/*" }, File::FNM_DOTMATCH).reject do |path|
|
paths = exclude_ignored_paths(dirs)
|
||||||
%w[. .. .bundle .git log tmp vendor].include?(File.basename(path))
|
|
||||||
end
|
|
||||||
|
|
||||||
if options[:all]
|
if options[:all]
|
||||||
paths.inject([]) do |array, path|
|
paths.inject([]) do |array, path|
|
||||||
@ -99,14 +140,17 @@ module Guard
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Depending on the filesystem, mtime is probably only precise to the second, so round
|
# Depending on the filesystem, mtime/ctime is probably only precise to the second, so round
|
||||||
# both values down to the second for the comparison.
|
# both values down to the second for the comparison.
|
||||||
def file_modified?(path)
|
# ctime is used only on == comparaison to always catches Rails 3.1 Assets pipelined on Mac OSX
|
||||||
if File.mtime(path).to_i == @last_event.to_i
|
def file_modified?(path, last_event)
|
||||||
|
if File.ctime(path).to_i == last_event.to_i
|
||||||
file_content_modified?(path, sha1_checksum(path))
|
file_content_modified?(path, sha1_checksum(path))
|
||||||
elsif File.mtime(path).to_i > @last_event.to_i
|
elsif File.mtime(path).to_i > last_event.to_i
|
||||||
set_sha1_checksums_hash(path, sha1_checksum(path))
|
set_sha1_checksums_hash(path, sha1_checksum(path))
|
||||||
true
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
end
|
end
|
||||||
rescue
|
rescue
|
||||||
false
|
false
|
||||||
|
@ -3,7 +3,6 @@ module Guard
|
|||||||
|
|
||||||
def initialize(*)
|
def initialize(*)
|
||||||
super
|
super
|
||||||
|
|
||||||
@inotify = INotify::Notifier.new
|
@inotify = INotify::Notifier.new
|
||||||
@files = []
|
@files = []
|
||||||
@latency = 0.5
|
@latency = 0.5
|
||||||
@ -47,7 +46,7 @@ module Guard
|
|||||||
|
|
||||||
def watch(directory)
|
def watch(directory)
|
||||||
# The event selection is based on https://github.com/guard/guard/wiki/Analysis-of-inotify-events-for-different-editors
|
# The event selection is based on https://github.com/guard/guard/wiki/Analysis-of-inotify-events-for-different-editors
|
||||||
worker.watch(directory, :recursive, :create, :move_self, :close_write) do |event|
|
worker.watch(directory, :recursive, :attrib, :create, :move_self, :close_write) do |event|
|
||||||
unless event.name == "" # Event on root directory
|
unless event.name == "" # Event on root directory
|
||||||
@files << event.absolute_name
|
@files << event.absolute_name
|
||||||
end
|
end
|
||||||
|
@ -3,7 +3,6 @@ module Guard
|
|||||||
|
|
||||||
def initialize(*)
|
def initialize(*)
|
||||||
super
|
super
|
||||||
|
|
||||||
@fchange = FChange::Notifier.new
|
@fchange = FChange::Notifier.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -47,10 +47,18 @@ module Guard
|
|||||||
def self.notify_mac(title, message, image, options)
|
def self.notify_mac(title, message, image, options)
|
||||||
require_growl # need for guard-rspec formatter that is called out of guard scope
|
require_growl # need for guard-rspec formatter that is called out of guard scope
|
||||||
|
|
||||||
options = { :description => message, :title => title, :icon => image_path(image), :application_name => APPLICATION_NAME }.merge(options)
|
default_options = { :title => title, :icon => image_path(image), :name => APPLICATION_NAME }
|
||||||
options.delete(:name)
|
default_options.merge!(options)
|
||||||
|
|
||||||
GrowlNotify.send_notification(options) if enabled?
|
if defined?(GrowlNotify)
|
||||||
|
default_options[:description] = message
|
||||||
|
default_options[:application_name] = APPLICATION_NAME
|
||||||
|
default_options.delete(:name)
|
||||||
|
|
||||||
|
GrowlNotify.send_notification(default_options) if enabled?
|
||||||
|
else
|
||||||
|
Growl.notify message, default_options.merge(options) if enabled?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.notify_linux(title, message, image, options)
|
def self.notify_linux(title, message, image, options)
|
||||||
@ -94,6 +102,7 @@ module Guard
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.require_growl
|
def self.require_growl
|
||||||
|
begin
|
||||||
require 'growl_notify'
|
require 'growl_notify'
|
||||||
|
|
||||||
if GrowlNotify.application_name != APPLICATION_NAME
|
if GrowlNotify.application_name != APPLICATION_NAME
|
||||||
@ -102,9 +111,12 @@ module Guard
|
|||||||
c.application_name = c.notifications.first
|
c.application_name = c.notifications.first
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
rescue LoadError
|
||||||
|
require 'growl'
|
||||||
|
end
|
||||||
rescue LoadError
|
rescue LoadError
|
||||||
turn_off
|
turn_off
|
||||||
UI.info "Please install growl_notify gem for Mac OS X notification support and add it to your Gemfile"
|
UI.info "Please install growl_notify or growl gem for Mac OS X notification support and add it to your Gemfile"
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.require_libnotify
|
def self.require_libnotify
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
module Guard
|
module Guard
|
||||||
VERSION = "0.6.1" unless defined? Guard::VERSION
|
VERSION = "0.6.3" unless defined? Guard::VERSION
|
||||||
end
|
end
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Guard::DslDescriber do
|
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 }
|
subject { described_class }
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,12 +8,18 @@ describe Guard::Dsl do
|
|||||||
before(:each) do
|
before(:each) do
|
||||||
@local_guardfile_path = File.join(Dir.pwd, 'Guardfile')
|
@local_guardfile_path = File.join(Dir.pwd, 'Guardfile')
|
||||||
@home_guardfile_path = File.expand_path(File.join("~", ".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!(:options).and_return(:debug => true)
|
||||||
::Guard.stub!(:guards).and_return([mock('Guard')])
|
::Guard.stub!(:guards).and_return([mock('Guard')])
|
||||||
end
|
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
|
describe "it should select the correct data source for Guardfile" do
|
||||||
before(:each) { ::Guard::Dsl.stub!(:instance_eval_guardfile) }
|
before(:each) { ::Guard::Dsl.stub!(:instance_eval_guardfile) }
|
||||||
|
disable_user_config
|
||||||
|
|
||||||
it "should use a string for initializing" do
|
it "should use a string for initializing" do
|
||||||
Guard::UI.should_not_receive(:error)
|
Guard::UI.should_not_receive(:error)
|
||||||
@ -54,6 +60,15 @@ describe Guard::Dsl do
|
|||||||
lambda { subject.evaluate_guardfile(:guardfile => '/abc/Guardfile') }.should_not raise_error
|
lambda { subject.evaluate_guardfile(:guardfile => '/abc/Guardfile') }.should_not raise_error
|
||||||
subject.guardfile_contents.should == "guard :foo"
|
subject.guardfile_contents.should == "guard :foo"
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
it "displays an error message when no Guardfile is found" do
|
it "displays an error message when no Guardfile is found" do
|
||||||
@ -71,6 +86,7 @@ describe Guard::Dsl do
|
|||||||
|
|
||||||
describe "correctly reads data from its valid data source" do
|
describe "correctly reads data from its valid data source" do
|
||||||
before(:each) { ::Guard::Dsl.stub!(:instance_eval_guardfile) }
|
before(:each) { ::Guard::Dsl.stub!(:instance_eval_guardfile) }
|
||||||
|
disable_user_config
|
||||||
|
|
||||||
it "reads correctly from a string" do
|
it "reads correctly from a string" do
|
||||||
lambda { subject.evaluate_guardfile(:guardfile_contents => valid_guardfile_string) }.should_not raise_error
|
lambda { subject.evaluate_guardfile(:guardfile_contents => valid_guardfile_string) }.should_not raise_error
|
||||||
@ -202,7 +218,21 @@ describe Guard::Dsl do
|
|||||||
end
|
end
|
||||||
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
|
describe "#group" do
|
||||||
|
disable_user_config
|
||||||
|
|
||||||
it "evaluates only the specified string group" do
|
it "evaluates only the specified string group" do
|
||||||
::Guard.should_receive(:add_guard).with(:pow, [], [], { :group => :default })
|
::Guard.should_receive(:add_guard).with(:pow, [], [], { :group => :default })
|
||||||
::Guard.should_receive(:add_guard).with(:test, [], [], { :group => :w })
|
::Guard.should_receive(:add_guard).with(:test, [], [], { :group => :w })
|
||||||
@ -245,6 +275,8 @@ describe Guard::Dsl do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe "#guard" do
|
describe "#guard" do
|
||||||
|
disable_user_config
|
||||||
|
|
||||||
it "loads a guard specified as a quoted string from the DSL" do
|
it "loads a guard specified as a quoted string from the DSL" do
|
||||||
::Guard.should_receive(:add_guard).with(:test, [], [], { :group => :default })
|
::Guard.should_receive(:add_guard).with(:test, [], [], { :group => :default })
|
||||||
|
|
||||||
@ -277,6 +309,8 @@ describe Guard::Dsl do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe "#watch" do
|
describe "#watch" do
|
||||||
|
disable_user_config
|
||||||
|
|
||||||
it "should receive watchers when specified" do
|
it "should receive watchers when specified" do
|
||||||
::Guard.should_receive(:add_guard).with(:dummy, anything, anything, { :group => :default }) do |name, watchers, callbacks, options|
|
::Guard.should_receive(:add_guard).with(:dummy, anything, anything, { :group => :default }) do |name, watchers, callbacks, options|
|
||||||
watchers.size.should == 2
|
watchers.size.should == 2
|
||||||
|
@ -1,35 +1,26 @@
|
|||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Guard::Interactor do
|
describe Guard::Interactor do
|
||||||
subject { Guard::Interactor }
|
subject { Guard::Interactor.new }
|
||||||
|
|
||||||
let(:guard) { mock "guard" }
|
describe "#initialize" do
|
||||||
|
it "un-lock by default" do
|
||||||
before :each do
|
subject.locked.should be_false
|
||||||
Guard.stub!(:guards).and_return([guard])
|
|
||||||
Guard.stub!(:options).and_return({})
|
|
||||||
Guard.stub!(:listener).and_return(mock(:start => nil, :stop => nil))
|
|
||||||
guard.should_receive(:hook).twice
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ".run_all" do
|
|
||||||
it "sends :run_all to all guards" do
|
|
||||||
guard.should_receive(:run_all)
|
|
||||||
subject.run_all
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe ".stop" do
|
describe "#lock" do
|
||||||
it "sends :stop to all guards" do
|
it "locks" do
|
||||||
guard.should_receive(:stop)
|
subject.lock
|
||||||
lambda { subject.stop }.should raise_error(SystemExit)
|
subject.locked.should be_true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe ".reload" do
|
describe "#unlock" do
|
||||||
it "sends :reload to all guards" do
|
it "unlocks" do
|
||||||
guard.should_receive(:reload)
|
subject.unlock
|
||||||
subject.reload
|
subject.locked.should be_false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -128,7 +128,6 @@ describe Guard::Listener do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe "working directory" do
|
describe "working directory" do
|
||||||
|
|
||||||
context "unspecified" do
|
context "unspecified" do
|
||||||
subject { described_class.new }
|
subject { described_class.new }
|
||||||
it "defaults to Dir.pwd" do
|
it "defaults to Dir.pwd" do
|
||||||
@ -158,7 +157,33 @@ describe Guard::Listener do
|
|||||||
stop
|
stop
|
||||||
end
|
end
|
||||||
end
|
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
|
end
|
||||||
|
@ -21,7 +21,7 @@ describe Guard::Darwin do
|
|||||||
subject.should be_usable
|
subject.should be_usable
|
||||||
end
|
end
|
||||||
|
|
||||||
it_should_behave_like "a listener that reacts to #on_change", 0.7
|
it_should_behave_like "a listener that reacts to #on_change"
|
||||||
it_should_behave_like "a listener scoped to a specific directory", 0.7
|
it_should_behave_like "a listener scoped to a specific directory"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -39,9 +39,19 @@ describe Guard::Notifier do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "without the GrowlNofity library available" do
|
context "with the Growl library available" do
|
||||||
|
it "loads the library and enables the notifications" do
|
||||||
|
subject.should_receive(:require).with('growl_notify').and_raise LoadError
|
||||||
|
subject.should_receive(:require).with('growl').and_return true
|
||||||
|
subject.turn_on
|
||||||
|
subject.should be_enabled
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "without the Growl library available" do
|
||||||
it "disables the notifications" do
|
it "disables the notifications" do
|
||||||
subject.should_receive(:require).with('growl_notify').and_raise LoadError
|
subject.should_receive(:require).with('growl_notify').and_raise LoadError
|
||||||
|
subject.should_receive(:require).with('growl').and_raise LoadError
|
||||||
subject.turn_on
|
subject.turn_on
|
||||||
subject.should_not be_enabled
|
subject.should_not be_enabled
|
||||||
end
|
end
|
||||||
@ -102,6 +112,51 @@ describe Guard::Notifier do
|
|||||||
subject.stub(:require_growl)
|
subject.stub(:require_growl)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with growl gem' do
|
||||||
|
before do
|
||||||
|
Object.send(:remove_const, :Growl) if defined?(Growl)
|
||||||
|
Growl = Object.new
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
Object.send(:remove_const, :Growl)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "passes the notification to Growl" do
|
||||||
|
Growl.should_receive(:notify).with("great",
|
||||||
|
:title => "Guard",
|
||||||
|
:icon => Pathname.new(File.dirname(__FILE__)).join('../../images/success.png').to_s,
|
||||||
|
:name => "Guard"
|
||||||
|
)
|
||||||
|
subject.notify 'great', :title => 'Guard'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "don't passes the notification to Growl if library is not available" do
|
||||||
|
Growl.should_not_receive(:notify)
|
||||||
|
subject.should_receive(:enabled?).and_return(true, false)
|
||||||
|
subject.notify 'great', :title => 'Guard'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "allows additional notification options" do
|
||||||
|
Growl.should_receive(:notify).with("great",
|
||||||
|
:title => "Guard",
|
||||||
|
:icon => Pathname.new(File.dirname(__FILE__)).join('../../images/success.png').to_s,
|
||||||
|
:name => "Guard",
|
||||||
|
:priority => 1
|
||||||
|
)
|
||||||
|
subject.notify 'great', :title => 'Guard', :priority => 1
|
||||||
|
end
|
||||||
|
|
||||||
|
it "allows to overwrite a default notification option" do
|
||||||
|
Growl.should_receive(:notify).with("great",
|
||||||
|
:title => "Guard",
|
||||||
|
:icon => Pathname.new(File.dirname(__FILE__)).join('../../images/success.png').to_s,
|
||||||
|
:name => "Guard-Cucumber"
|
||||||
|
)
|
||||||
|
subject.notify 'great', :title => 'Guard', :name => "Guard-Cucumber"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'with growl_notify gem' do
|
context 'with growl_notify gem' do
|
||||||
before do
|
before do
|
||||||
Object.send(:remove_const, :GrowlNotify) if defined?(GrowlNotify)
|
Object.send(:remove_const, :GrowlNotify) if defined?(GrowlNotify)
|
||||||
|
@ -28,7 +28,7 @@ private
|
|||||||
|
|
||||||
shared_examples_for 'a listener that reacts to #on_change' do |rest_delay|
|
shared_examples_for 'a listener that reacts to #on_change' do |rest_delay|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
@rest_delay = rest_delay
|
@rest_delay = rest_delay if rest_delay.is_a?(Integer) || rest_delay.is_a?(Float) # jruby workaround
|
||||||
@listener = described_class.new
|
@listener = described_class.new
|
||||||
record_results
|
record_results
|
||||||
end
|
end
|
||||||
@ -61,6 +61,15 @@ shared_examples_for 'a listener that reacts to #on_change' do |rest_delay|
|
|||||||
results.should =~ ['spec/fixtures/folder1/file1.txt']
|
results.should =~ ['spec/fixtures/folder1/file1.txt']
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "not catches a single file chmod update" do
|
||||||
|
file = @fixture_path.join("folder1/file1.txt")
|
||||||
|
File.exists?(file).should be_true
|
||||||
|
start
|
||||||
|
File.chmod(0777, file)
|
||||||
|
stop
|
||||||
|
results.should =~ []
|
||||||
|
end
|
||||||
|
|
||||||
it "catches a dotfile update" do
|
it "catches a dotfile update" do
|
||||||
file = @fixture_path.join(".dotfile")
|
file = @fixture_path.join(".dotfile")
|
||||||
File.exists?(file).should be_true
|
File.exists?(file).should be_true
|
||||||
@ -108,7 +117,7 @@ end
|
|||||||
|
|
||||||
shared_examples_for "a listener scoped to a specific directory" do |rest_delay|
|
shared_examples_for "a listener scoped to a specific directory" do |rest_delay|
|
||||||
before :each do
|
before :each do
|
||||||
@rest_delay = rest_delay
|
@rest_delay = rest_delay if rest_delay.is_a?(Integer) || rest_delay.is_a?(Float) # jruby workaround
|
||||||
@wd = @fixture_path.join("folder1")
|
@wd = @fixture_path.join("folder1")
|
||||||
@listener = described_class.new @wd
|
@listener = described_class.new @wd
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user