Compare commits
No commits in common. "master" and "guard_dependencies" have entirely different histories.
master
...
guard_depe
2
.gitignore
vendored
2
.gitignore
vendored
@ -6,8 +6,6 @@ doc/*
|
||||
*.bak
|
||||
.bundle
|
||||
.yardoc
|
||||
.rbx
|
||||
.rvmrc
|
||||
Gemfile.lock
|
||||
|
||||
## MAC OS
|
||||
|
@ -8,8 +8,6 @@ branches:
|
||||
only:
|
||||
- master
|
||||
- guard_dependencies
|
||||
env:
|
||||
- GUARD_SLEEP=1
|
||||
notifications:
|
||||
recipients:
|
||||
- thibaud@thibaud.me
|
||||
|
233
CHANGELOG.md
233
CHANGELOG.md
@ -1,68 +1,6 @@
|
||||
## Master
|
||||
|
||||
### Improvements
|
||||
|
||||
- Add cli option (-i / --no-interactions) to turn off Guard terminal interactions. ([@thibaudgg][])
|
||||
- Add support for Growl Notification Transport Protocol. ([@netzpirat][])
|
||||
- [#157](https://github.com/guard/guard/pull/157): Allow any return from the Guard watchers. ([@earlonrails][])
|
||||
- [#156](https://github.com/guard/guard/pull/156): Log error and diagnostic messages to STDERR. ([@sunaku][])
|
||||
- [#152](https://github.com/guard/guard/pull/152): Growl Notify API update for a graceful fail. ([@scottdavis][])
|
||||
|
||||
### Bug fix
|
||||
|
||||
- [#149](https://github.com/guard/guard/issues/160): Avoid `Guard is not missing constant ...` exceptions. (reported by [@earlonrails][], fixed by [@netzpirat][])
|
||||
|
||||
## 0.8.4 - October 3, 2011
|
||||
|
||||
### Bug fix
|
||||
|
||||
- [#149](https://github.com/guard/guard/issues/149) & [#150](https://github.com/guard/guard/pull/150): Fix issue where interator thread was continuing to capture input from stdin while a guard is being executed. (reported by [@hardipe][], fixed by [@f1sherman][])
|
||||
|
||||
## 0.8.3 - October 1, 2011
|
||||
|
||||
### Bug fix
|
||||
|
||||
- [#145](https://github.com/guard/guard/pull/145): Fix over-utilization of CPU in Interactor. ([@johnbintz][])
|
||||
|
||||
### Improvements
|
||||
|
||||
- [#146](https://github.com/guard/guard/pull/146): Use a mutex instead of a lock for more efficient/simple locking. ([@f1sherman][])
|
||||
- Make Guard implementation of `:task_has_failed` simple. ([@netzpirat][])
|
||||
|
||||
## 0.8.2 - September 30, 2011
|
||||
|
||||
### Bug fix
|
||||
|
||||
- Fixed guard stop to prevent run_guard_task(:stop) to be skipped [guard-spork issue #28](https://github.com/guard/guard-spork/issues/28). ([@thibaudgg][])
|
||||
|
||||
### Improvement
|
||||
|
||||
- Update docs regarding :task_has_failed. ([@netzpirat][])
|
||||
|
||||
## 0.8.1 - September 29, 2011
|
||||
|
||||
### Bug fix
|
||||
|
||||
- [#144](https://github.com/guard/guard/pull/144): Fix `guard init`. (reported by [@fabioyamate][], fixed by [@rymai][])
|
||||
|
||||
## 0.8.0 - September 28, 2011
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- [#137](https://github.com/guard/guard/pull/137): Fix interacting with tools like ruby-debug. ([@hron][] & [@netzpirat][])
|
||||
- [#138](https://github.com/guard/guard/pull/138): Fixed comments in example scaffold to reference interactions. ([@rmm5t][] & [@netzpirat][])
|
||||
|
||||
### New feature
|
||||
|
||||
- [#136](https://github.com/guard/guard/pull/136): New CLI `:watch_all_modifications`/`-A` option to watch for deleted and moved files too. ([@limeyd][] & [@netzpirat][])
|
||||
- [#97](https://github.com/guard/guard/issues/97): Guard dependencies. Task execution can now be halted if a Guard throws `:task_has_failed` and `Guard::Dsl#group` options include `:halt_on_fail => true`. ([@rymai][])
|
||||
- [#121](https://github.com/guard/guard/issues/121): `Guard.guards` and `Guard.groups` are now smart accessors. Filters can be passed to find a specific Guard/group or several Guards/groups that match (see YARDoc). ([@rymai][] & [@ches][])
|
||||
- New `Guard::Group` class to store groups defined in Guardfile (with `Guard::Dsl#group`). ([@rymai][])
|
||||
|
||||
### Improvements
|
||||
|
||||
- Specs refactoring. ([@netzpirat][])
|
||||
- Full YARD documentation. ([@netzpirat][] & a little of [@rymai][])
|
||||
- Pull request [#137](https://github.com/guard/guard/pull/137): Fix interacting with tools like ruby-debug. ([@hron][] & [@netzpirat][])
|
||||
|
||||
## 0.7.0 - September 14, 2011
|
||||
|
||||
@ -71,226 +9,235 @@
|
||||
### 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 & Rubinius support (beta). ([@thibaudgg][] & [@netzpirat][])
|
||||
- JRuby & Rubinius support (beta). ([@thibaudgg][] and [@netzpirat][])
|
||||
|
||||
### New features
|
||||
### New feature:
|
||||
|
||||
- [#42](https://github.com/guard/guard/pull/42): New DSL method: `callback` allows you to execute arbitrary code before or after any of the `start`, `stop`, `reload`, `run_all` and `run_on_change` guards' method. New [Wiki page](https://github.com/guard/guard/wiki/Hooks-and-callbacks) for documenting it. ([@monocle][] & [@rymai][])
|
||||
- Pull request [#42](https://github.com/guard/guard/pull/42): New DSL method: `callback` allows you to execute arbitrary code before or after any of the `start`, `stop`, `reload`, `run_all` and `run_on_change` guards' method. New [Wiki page](https://github.com/guard/guard/wiki/Hooks-and-callbacks) for documenting it. ([@monocle][] & [@rymai][])
|
||||
- Ability to 'pause' files modification listening. Please refer to the "Interactions" section in the README for more information. ([@thibaudgg][])
|
||||
|
||||
### Improvement
|
||||
### 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
|
||||
### New features:
|
||||
|
||||
- [#130](https://github.com/guard/guard/pull/130): Adds `ignore_paths` method to DSL. ([@ianwhite][])
|
||||
- [#128](https://github.com/guard/guard/pull/128): Users can add additional settings to `~/.guard.rb` that augment the existing Guardfile. ([@tpope][])
|
||||
- Pull request [#130](https://github.com/guard/guard/pull/130): Adds `ignore_paths` method 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
|
||||
|
||||
### Bug fixes
|
||||
### 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
|
||||
### 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
|
||||
### Improvement:
|
||||
|
||||
- Explain the growl/growl_notify differences in the README. ([@netzpirat][])
|
||||
|
||||
## 0.6.1 - August 15, 2011
|
||||
|
||||
### Bug fixes
|
||||
### Bugs fixes:
|
||||
|
||||
- [#120](https://github.com/guard/guard/pull/120): remove `guardfile_contents` when re-evaluating so that the Guardfile gets reloaded correctly. ([@mordaroso][])
|
||||
- [#119](https://github.com/guard/guard/pull/119): `Dsl.evaluate_guardfile` uses all groups if none specified. ([@ches][])
|
||||
- Pull request [#120](https://github.com/guard/guard/pull/120): remove `guardfile_contents` when re-evaluating so that the Guardfile gets reloaded correctly. ([@mordaroso][])
|
||||
- Pull request [#119](https://github.com/guard/guard/pull/119): `Dsl.evaluate_guardfile` uses all groups if none specified. ([@ches][])
|
||||
|
||||
## 0.6.0 - August 13, 2011
|
||||
|
||||
### Bug fixes
|
||||
### Bugs fixes:
|
||||
|
||||
- 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][])
|
||||
|
||||
### New feature
|
||||
### New features:
|
||||
|
||||
- Pull request [#112](https://github.com/guard/guard/pull/112): Add `list` command to CLI. ([@docwhat][])
|
||||
|
||||
### Improvements
|
||||
### Improvements:
|
||||
|
||||
- [#99](https://github.com/guard/guard/pull/99): [OS X] Switch from growl gem to growl_notify gem. ([@johnbintz][])
|
||||
- [#115](https://github.com/guard/guard/pull/115): [Linux] Add `:transient => true` to default libnotify options. ([@zonque][])
|
||||
- [#95](https://github.com/guard/guard/pull/95): Output system commands and options to be executed when in debug mode. ([@uk-ar][] and [@netzpirat][])
|
||||
- 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 [#95](https://github.com/guard/guard/pull/95): Output system commands and options to be executed when in debug mode. ([@uk-ar][] and [@netzpirat][])
|
||||
- `Guard::Dsl.revaluate_guardfile` has been renamed to `Guard::Dsl.reevaluate_guardfile`. ([@rymai][])
|
||||
- New CLI options: ([@nestegg][])
|
||||
- `watchdir`/`-w` to specify the directory in which Guard should watch for changes,
|
||||
- `guardfile`/`-G` to specify an alternate location for the Guardfile to use.
|
||||
- [#90](https://github.com/guard/guard/pull/90): Refactoring of color handling in the `Guard::UI`. ([@stereobooster][])
|
||||
- Pull request [#90](https://github.com/guard/guard/pull/90): Refactoring of color handling in the `Guard::UI`. ([@stereobooster][])
|
||||
|
||||
## 0.5.1 - July 2, 2011
|
||||
|
||||
### Bug fix
|
||||
### Bugs fixes:
|
||||
|
||||
- Fixed `guard show` command. ([@bronson][] & [@thibaudgg][])
|
||||
|
||||
## 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][])
|
||||
- [#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:
|
||||
|
||||
- [#98](https://github.com/guard/guard/issues/98): Multiple calls per watch event on linux with rb-inotify. ([@jeffutter][] & [@netzpirat][])
|
||||
- [#94](https://github.com/guard/guard/pull/94): Show backtrace in terminal when a problem with a watch action occurs. ([@capotej][])
|
||||
- [#88](https://github.com/guard/guard/pull/88): Write exception trace in the terminal when a supervised task fail. ([@mcmire][])
|
||||
- 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 [#88](https://github.com/guard/guard/pull/88): Write exception trace in the terminal when a supervised task fail. ([@mcmire][])
|
||||
- Color in red the "ERROR:" flag when using `UI.error`. ([@rymai][])
|
||||
- [#79](https://github.com/guard/guard/issues/79) and Pull request [#82](https://github.com/guard/guard/pull/82): Improve INotify support on Linux. ([@Gazer][] & [@yannlugrin][])
|
||||
- [#12](https://github.com/guard/guard/issues/12) and Pull request [#86](https://github.com/guard/guard/pull/86): Eventually exits with SystemStackError. ([@stereobooster][])
|
||||
- [#84](https://github.com/guard/guard/pull/84): Use RbConfig instead of obsolete and deprecated Config. ([@etehtsea][])
|
||||
- [#80](https://github.com/guard/guard/pull/80): Watching dotfile (hidden files under unix). (reported by [@chrisberkhout][], fixed by [@yannlugrin][])
|
||||
- Issue [#79](https://github.com/guard/guard/issues/79) and Pull request [#82](https://github.com/guard/guard/pull/82): Improve INotify support on Linux. ([@Gazer][] & [@yannlugrin][])
|
||||
- Issue [#12](https://github.com/guard/guard/issues/12) and Pull request [#86](https://github.com/guard/guard/pull/86): Eventually exits with SystemStackError. ([@stereobooster][])
|
||||
- Pull request [#84](https://github.com/guard/guard/pull/84): Use RbConfig instead of obsolete and deprecated Config. ([@etehtsea][])
|
||||
- Pull request [#80](https://github.com/guard/guard/pull/80): Watching dotfile (hidden files under unix). (reported by [@chrisberkhout][], fixed by [@yannlugrin][])
|
||||
- Clear the terminal on start when the `:clear` option is given. ([@rymai][])
|
||||
- Rename home directory Guardfile to `.Guardfile`. ([@tpope][])
|
||||
|
||||
## 0.4.2 - June 7, 2011
|
||||
|
||||
### Bug fixes
|
||||
### Bugs fixes:
|
||||
|
||||
- Fixed Guard::Version in ruby 1.8.7 ([@thibaudgg][])
|
||||
- Fix ([@mislav][]) link in CHANGELOG (Note: this is a recursive CHANGELOG item). ([@fnichol][])
|
||||
|
||||
## 0.4.1 - June 7, 2011
|
||||
|
||||
### Improvements
|
||||
### Improvements:
|
||||
|
||||
- [#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][])
|
||||
|
||||
## 0.4.0 - June 5, 2011
|
||||
|
||||
### Bug fix
|
||||
### Bugs fixes:
|
||||
|
||||
- In Ruby < 1.9, `Symbol#downcase` doesn't exist! ([@rymai][])
|
||||
|
||||
### New features
|
||||
### New features:
|
||||
|
||||
- [#73](https://github.com/guard/guard/pull/73): Allow DSL's `group` method to accept a Symbol as group name. ([@johnbintz][])
|
||||
- [#51](https://github.com/guard/guard/pull/51): Allow options (like `:priority`) to be passed through to the Notifier. ([@indirect][] & [@netzpirat][])
|
||||
- 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][])
|
||||
|
||||
### Improvement
|
||||
### Improvements:
|
||||
|
||||
- [#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][])
|
||||
|
||||
## 0.4.0.rc - May 28, 2011
|
||||
|
||||
### Bug fixes
|
||||
### Bugs fixes:
|
||||
|
||||
- [#69](https://github.com/guard/guard/pull/69): Fixed typo in README: `Ctr-/` => `Ctr-\`. ([@tinogomes][])
|
||||
- [#66](https://github.com/guard/guard/pull/66): Support for dashes in guard names. ([@johnbintz][])
|
||||
- Pull request [#69](https://github.com/guard/guard/pull/69): Fixed typo in README: `Ctr-/` => `Ctr-\`. ([@tinogomes][])
|
||||
- Pull request [#66](https://github.com/guard/guard/pull/66): Support for dashes in guard names. ([@johnbintz][])
|
||||
- Require `guard/ui` because `Guard::Notifier` can be required without full Guard. ([@yannlugrin][])
|
||||
- Handled quick file (<1s) modification. Avoid to catch modified files without content modification (sha1 checksum). ([@thibaudgg][] & [@netzpirat][])
|
||||
- Fixed `Guard::Notifier` (when growl/libnotify not present). ([@thibaudgg][])
|
||||
- Fixed Rubygems deprecation messages. ([@thibaudgg][])
|
||||
|
||||
### New features
|
||||
### New features:
|
||||
|
||||
- [#67](https://github.com/guard/guard/pull/67): Allow Guardfile in `$HOME` folder. ([@hashrocketeer][])
|
||||
- [#64](https://github.com/guard/guard/pull/64): Windows notifications support. ([@stereobooster][])
|
||||
- [#63](https://github.com/guard/guard/pull/63): Refactor listeners to work as a library. ([@niklas][])
|
||||
- Pull request [#67](https://github.com/guard/guard/pull/67): Allow Guardfile in `$HOME` folder. ([@hashrocketeer][])
|
||||
- Pull request [#64](https://github.com/guard/guard/pull/64): Windows notifications support. ([@stereobooster][])
|
||||
- Pull request [#63](https://github.com/guard/guard/pull/63): Refactor listeners to work as a library. ([@niklas][])
|
||||
- Use `ENV["GUARD_NOTIFY"]` to disable notifications. ([@thibaudgg][])
|
||||
- Cleaning up all specs. ([@netzpirat][])
|
||||
- [#60](https://github.com/guard/guard/pull/60): Added Windows support. ([@stereobooster][])
|
||||
- [#58](https://github.com/guard/guard/pull/58): Extract code from signal handlers into methods. ([@nicksieger][])
|
||||
- [#55](https://github.com/guard/guard/pull/55): It is now possible to pass `:guardfile` (a Guardfile path) or `:guardfile_contents` (the content of a Guardfile) to `Guard::Dsl.evaluate_guardfile`. Hence this allows the use of `Guard::Dsl.evaluate_guardfile` in a programmatic manner. ([@anithri][], improved by [@rymai][])
|
||||
- Pull request [#60](https://github.com/guard/guard/pull/60): Added Windows support. ([@stereobooster][])
|
||||
- Pull request [#58](https://github.com/guard/guard/pull/58): Extract code from signal handlers into methods. ([@nicksieger][])
|
||||
- Pull request [#55](https://github.com/guard/guard/pull/55): It is now possible to pass `:guardfile` (a Guardfile path) or `:guardfile_contents` (the content of a Guardfile) to `Guard::Dsl.evaluate_guardfile`. Hence this allows the use of `Guard::Dsl.evaluate_guardfile` in a programmatic manner. ([@anithri][], improved by [@rymai][])
|
||||
|
||||
|
||||
## 0.3.4 - April 24, 2011
|
||||
|
||||
### Bug fix
|
||||
### Bugs fixes:
|
||||
|
||||
- [#41](https://github.com/guard/guard/issues/41): Removed useless Bundler requirement. ([@thibaudgg][])
|
||||
- Issue [#41](https://github.com/guard/guard/issues/41): Removed useless Bundler requirement. ([@thibaudgg][])
|
||||
|
||||
### New features
|
||||
### New features:
|
||||
|
||||
- Changed CHANGELOG from RDOC to Markdown and cleaned it! Let's celebrate! ([@rymai][])
|
||||
- Changed README from RDOC to Markdown! Let's celebrate! ([@thibaudgg][])
|
||||
- [#48](https://github.com/guard/guard/issues/48): Adding support for inline Guard classes rather than requiring a gem. ([@jrsacks][])
|
||||
- Issue [#48](https://github.com/guard/guard/issues/48): Adding support for inline Guard classes rather than requiring a gem. ([@jrsacks][])
|
||||
|
||||
|
||||
## 0.3.3 - April 18, 2011
|
||||
|
||||
### Bug fix
|
||||
### Bugs fixes:
|
||||
|
||||
- Fixed `new_modified_files` rerun conditions on `Guard.run_on_change_for_all_guards`. ([@thibaudgg][])
|
||||
|
||||
|
||||
## 0.3.2 - April 17, 2011
|
||||
|
||||
### Bug fixe
|
||||
### Bugs fixes:
|
||||
|
||||
- Pull request [#43](https://github.com/guard/guard/pull/43): Fixed `guard init` command. ([@brainopia][])
|
||||
|
||||
- [#43](https://github.com/guard/guard/pull/43): Fixed `guard init` command. ([@brainopia][])
|
||||
|
||||
## 0.3.1 - April 14, 2011
|
||||
|
||||
### Bug fixes
|
||||
### Bugs fixes:
|
||||
|
||||
- Return unique filenames from Linux listener. (Marian Schubert)
|
||||
- `Guard.get_guard_class` return wrong class when loaded nested class. ([@koshigoe][])
|
||||
- [#35](https://github.com/guard/guard/issues/35): Fixed open-gem/gem_open dependency problem by using `gem which` to locate guards gem path. (reported by [@thierryhenrio][], fixed by [@thibaudgg][])
|
||||
- [#38](https://github.com/guard/guard/issues/38) & Pull request [#39](https://github.com/guard/guard/issues/39): Fixed an invalid ANSI escape code in `Guard::UI.reset_line`. ([@gix][])
|
||||
- Issue [#35](https://github.com/guard/guard/issues/35): Fixed open-gem/gem_open dependency problem by using `gem which` to locate guards gem path. (reported by [@thierryhenrio][], fixed by [@thibaudgg][])
|
||||
- Issue [#38](https://github.com/guard/guard/issues/38) & Pull request [#39](https://github.com/guard/guard/issues/39): Fixed an invalid ANSI escape code in `Guard::UI.reset_line`. ([@gix][])
|
||||
|
||||
### New feature
|
||||
### New features:
|
||||
|
||||
- Issue [#28](https://github.com/guard/guard/issues/28): New `-n` command line option to disable notifications (Growl / Libnotify). ([@thibaudgg][])
|
||||
|
||||
- [#28](https://github.com/guard/guard/issues/28): New `-n` command line option to disable notifications (Growl / Libnotify). ([@thibaudgg][])
|
||||
|
||||
## 0.3.0 - January 19, 2011
|
||||
|
||||
### Bug fix
|
||||
### Bugs fixes:
|
||||
|
||||
- Avoid launching `run_on_change` guards method when no files matched. `--clear` guard argument is now usable. ([@thibaudgg][])
|
||||
|
||||
### New features
|
||||
### New features:
|
||||
|
||||
- The whole directory is now watched during `run_on_change` to detect new files modifications. ([@thibaudgg][])
|
||||
- [#26](https://github.com/guard/guard/pull/26): New DSL method: `group` allows you to group several guards. New CLI option: `--group group_name` to specify certain groups of guards to start. ([@netzpirat][])
|
||||
- Pull request [#26](https://github.com/guard/guard/pull/26): New DSL method: `group` allows you to group several guards. New CLI option: `--group group_name` to specify certain groups of guards to start. ([@netzpirat][])
|
||||
- `watch` patterns are now more strict: strings are matched with `String#==`, `Regexp` are matched with `Regexp#match`. ([@rymai][])
|
||||
- A deprecation warning is displayed if your `Guardfile` contains `String` that look like `Regexp` (bad!). ([@rymai][])
|
||||
- It's now possible to return an `Enumerable` in the `watch` optional blocks in the `Guardfile`. ([@rymai][])
|
||||
|
||||
### New specs
|
||||
### New specs:
|
||||
|
||||
- `Guard::Watcher`. ([@rymai][])
|
||||
- [#13](https://github.com/guard/guard/pull/13): `Guard::Dsl`. ([@oliamb][])
|
||||
- Pull request [#13](https://github.com/guard/guard/pull/13): `Guard::Dsl`. ([@oliamb][])
|
||||
|
||||
|
||||
## 0.2.2 - October 25, 2010
|
||||
|
||||
### Bug fix
|
||||
### Bugs fixes:
|
||||
|
||||
- Issue [#5](https://github.com/guard/guard/issues/5): avoid creating new copy of `fsevent_watch` every time a file is changed. (reported by [@stouset][], fixed by [@thibaudgg][])
|
||||
|
||||
- [#5](https://github.com/guard/guard/issues/5): avoid creating new copy of `fsevent_watch` every time a file is changed. (reported by [@stouset][], fixed by [@thibaudgg][])
|
||||
|
||||
## 0.2.1 - October 24, 2010
|
||||
|
||||
### Bug fixes
|
||||
### Bugs fixes:
|
||||
|
||||
- Pull request [#7](https://github.com/guard/guard/pull/7): Fixes for Linux support. ([@yannlugrin][])
|
||||
- Pull request [#6](https://github.com/guard/guard/pull/6): Locate guard now chomp newline in result path. ([@yannlugrin][])
|
||||
|
||||
- [#7](https://github.com/guard/guard/pull/7): Fixes for Linux support. ([@yannlugrin][])
|
||||
- [#6](https://github.com/guard/guard/pull/6): Locate guard now chomp newline in result path. ([@yannlugrin][])
|
||||
|
||||
## 0.2.0 - October 21, 2010
|
||||
|
||||
### Bug fixes
|
||||
### Bugs fixes:
|
||||
|
||||
- [#3](https://github.com/guard/guard/issues/3): `guard init <guard-name>` no more need `Gemfile` but `open_gem` is required now. (reported by [@wereHamster][], fixed by [@thibaudgg][])
|
||||
- [#2](https://github.com/guard/guard/issues/2): 1.8.6 compatibility. (reported by [@veged][], fixed by [@thibaudgg][])
|
||||
- Issue [#3](https://github.com/guard/guard/issues/3): `guard init <guard-name>` no more need `Gemfile` but `open_gem` is required now. (reported by [@wereHamster][], fixed by [@thibaudgg][])
|
||||
- Issue [#2](https://github.com/guard/guard/issues/2): 1.8.6 compatibility. (reported by [@veged][], fixed by [@thibaudgg][])
|
||||
- Removes Growl & Libnotify dependencies. ([@thibaudgg][])
|
||||
|
||||
|
||||
## 0.2.0.beta.1 - October 17, 2010
|
||||
|
||||
### New features
|
||||
### New features:
|
||||
|
||||
- Improved listeners support (`rb-fsevent` & `rb-inotify`). ([@thibaudgg][])
|
||||
- Added polling listening fallback. ([@thibaudgg][])
|
||||
@ -303,15 +250,11 @@
|
||||
[@chrisberkhout]: https://github.com/chrisberkhout
|
||||
[@dnagir]: https://github.com/dnagir
|
||||
[@docwhat]: https://github.com/docwhat
|
||||
[@earlonrails]: https://github.com/earlonrails
|
||||
[@etehtsea]: https://github.com/etehtsea
|
||||
[@f1sherman]: https://github.com/f1sherman
|
||||
[@fabioyamate]: https://github.com/fabioyamate
|
||||
[@fnichol]: https://github.com/fnichol
|
||||
[@Gazer]: https://github.com/Gazer
|
||||
[@gix]: https://github.com/gix
|
||||
[@hron]: https://github.com/hron
|
||||
[@hardipe]: https://github.com/hardipe
|
||||
[@hashrocketeer]: https://github.com/hashrocketeer
|
||||
[@ianwhite]: https://github.com/ianwhite
|
||||
[@indirect]: https://github.com/indirect
|
||||
@ -319,7 +262,6 @@
|
||||
[@johnbintz]: https://github.com/johnbintz
|
||||
[@jrsacks]: https://github.com/jrsacks
|
||||
[@koshigoe]: https://github.com/koshigoe
|
||||
[@limeyd]: https://github.com/limeyd
|
||||
[@mcmire]: https://github.com/mcmire
|
||||
[@mislav]: https://github.com/mislav
|
||||
[@monocle]: https://github.com/monocle
|
||||
@ -330,12 +272,9 @@
|
||||
[@niklas]: https://github.com/niklas
|
||||
[@oliamb]: https://github.com/oliamb
|
||||
[@pcreux]: https://github.com/pcreux
|
||||
[@rmm5t]: https://github.com/rmm5t
|
||||
[@rymai]: https://github.com/rymai
|
||||
[@scottdavis]: https://github.com/scottdavis
|
||||
[@stereobooster]: https://github.com/stereobooster
|
||||
[@stouset]: https://github.com/stouset
|
||||
[@sunaku]: https://github.com/sunaku
|
||||
[@thibaudgg]: https://github.com/thibaudgg
|
||||
[@thierryhenrio]: https://github.com/thierryhenrio
|
||||
[@tinogomes]: https://github.com/tinogomes
|
||||
|
17
Guardfile
17
Guardfile
@ -1,16 +1,11 @@
|
||||
group :specs do
|
||||
guard :rspec, :all_on_start => false, :all_after_pass => false, :cli => '--fail-fast --format doc' do
|
||||
watch(%r{^spec/.+_spec\.rb$})
|
||||
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
||||
watch('spec/support/listener_helper.rb') { Dir.glob("spec/guard/listeners/*") }
|
||||
watch('spec/spec_helper.rb') { "spec" }
|
||||
end
|
||||
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{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
||||
watch('spec/spec_helper.rb') { "spec" }
|
||||
end
|
||||
|
||||
group :docs do
|
||||
guard :ronn do
|
||||
watch(%r{^man/.+\.ronn?$})
|
||||
end
|
||||
guard :ronn do
|
||||
watch(%r{^man/.+\.ronn?$})
|
||||
end
|
||||
|
||||
# require 'guard/guard'
|
||||
|
121
README.md
121
README.md
@ -19,12 +19,11 @@ Features
|
||||
Screencast
|
||||
----------
|
||||
|
||||
Ryan Bates made a Railscast on Guard, you can view it here: [http://railscasts.com/episodes/264-guard](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 the gem:
|
||||
|
||||
$ gem install guard
|
||||
@ -46,50 +45,32 @@ Also note that if a `.guard.rb` is found in your home directory, it will be appe
|
||||
|
||||
Add the guards you need to your Guardfile (see the existing guards below).
|
||||
|
||||
Now, be sure to read the particular instructions for your operating system: [Mac OS X](#mac) | [Linux](#linux) | [Windows](#win)
|
||||
|
||||
<a name="mac" />
|
||||
|
||||
### On Mac OS X
|
||||
|
||||
Install the rb-fsevent gem for [FSEvent](http://en.wikipedia.org/wiki/FSEvents) support:
|
||||
|
||||
$ gem install rb-fsevent
|
||||
|
||||
You have three possibilities for getting Growl support:
|
||||
You have two possibilities:
|
||||
|
||||
Use the [growl_notify gem](https://rubygems.org/gems/growl_notify):
|
||||
Use the [growl_notify gem](https://rubygems.org/gems/growl_notify) (recommended):
|
||||
|
||||
$ gem install growl_notify
|
||||
|
||||
The `growl_notify` gem is compatible with Growl >= 1.3 and uses AppleScript to send Growl notifications.
|
||||
The gem needs a native C extension to make use of AppleScript and does not run on JRuby and MacRuby.
|
||||
|
||||
Use the [ruby_gntp gem](https://github.com/snaka/ruby_gntp):
|
||||
|
||||
$ gem install ruby_gntp
|
||||
|
||||
The `ruby_gntp` gem is compatible with Growl >= 1.3 and uses the Growl Notification Transport Protocol to send Growl
|
||||
notifications. Guard supports multiple notification channels for customizing each notification type, but it's limited
|
||||
to the local host currently.
|
||||
|
||||
Use the [growl gem](https://rubygems.org/gems/growl):
|
||||
|
||||
$ gem install growl
|
||||
|
||||
The `growl` gem is compatible with all versions of Growl and uses a command line tool [growlnotify](http://growl.info/extras.php#growlnotify)
|
||||
that must be separately downloaded and installed. You can also install it with HomeBrew:
|
||||
Use the [growlnotify](http://growl.info/extras.php#growlnotify) (cli tool for growl) + the [growl gem](https://rubygems.org/gems/growl).
|
||||
|
||||
$ brew install growlnotify
|
||||
$ gem install growl
|
||||
|
||||
Finally you have to add your Growl library of choice to your Gemfile:
|
||||
And add them to your Gemfile:
|
||||
|
||||
gem 'rb-fsevent'
|
||||
gem 'growl_notify' # or gem 'ruby_gntp' or gem 'growl'
|
||||
gem 'growl_notify' # or gem 'growl'
|
||||
|
||||
Have a look at the [Guard Wiki](https://github.com/guard/guard/wiki/Which-Growl-library-should-I-use) for more information.
|
||||
|
||||
<a name="linux" />
|
||||
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
|
||||
|
||||
@ -106,8 +87,6 @@ And add them to your Gemfile:
|
||||
gem 'rb-inotify'
|
||||
gem 'libnotify'
|
||||
|
||||
<a name="win" />
|
||||
|
||||
### On Windows
|
||||
|
||||
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:
|
||||
@ -188,26 +167,10 @@ Guard can use a Guardfile not located in the current directory:
|
||||
$ guard --guardfile ~/.your_global_guardfile
|
||||
$ guard -G ~/.your_global_guardfile # shortcut
|
||||
|
||||
### `-A`/`--watch-all-modifications` option
|
||||
|
||||
Guard can optionally watch all file modifications like moves or deletions with:
|
||||
|
||||
$ guard start -A
|
||||
$ guard start --watch-all-modifications
|
||||
|
||||
### `-i`/`--no-interactions` option
|
||||
|
||||
Turn off completely any Guard terminal [interactions](#interactions) with:
|
||||
|
||||
$ guard start -A
|
||||
$ guard start --watch-all-modifications
|
||||
|
||||
An exhaustive list of options is available with:
|
||||
|
||||
$ guard help [TASK]
|
||||
|
||||
<a name="interactions" />
|
||||
|
||||
Interactions
|
||||
------------
|
||||
|
||||
@ -246,11 +209,11 @@ Guardfile DSL
|
||||
|
||||
The Guardfile DSL consists of the following methods:
|
||||
|
||||
* `#guard` - Allows you to add a guard with an optional hash of options.
|
||||
* `#watch` - Allows you to define which files are supervised by a 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.
|
||||
* `#group` - 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.
|
||||
* `#callback` - Allows you to execute arbitrary code before or after any of the `start`, `stop`, `reload`, `run_all` and `run_on_change` guards' method. You can even insert more hooks inside these methods. Please [checkout the Wiki page](https://github.com/guard/guard/wiki/Hooks-and-callbacks) for more details.
|
||||
* `#ignore_paths` - 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.
|
||||
* `#guard`: allows you to add a guard with an optional hash of options.
|
||||
* `#watch`: 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.
|
||||
* `#group`: 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.
|
||||
* `#callback`: allows you to execute arbitrary code before or after any of the `start`, `stop`, `reload`, `run_all` and `run_on_change` guards' method. You can even insert more hooks inside these methods. Please [checkout the Wiki page](https://github.com/guard/guard/wiki/Hooks-and-callbacks) for more details.
|
||||
* `#ignore_paths`: 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:
|
||||
|
||||
@ -356,9 +319,7 @@ Creating a new guard is very easy, just create a new gem (`bundle gem` if you us
|
||||
test/ # or spec/
|
||||
README.md
|
||||
|
||||
`Guard::GuardName` (in `lib/guard/guard-name.rb`) must inherit from
|
||||
[Guard::Guard](http://rubydoc.info/github/guard/guard/master/Guard/Guard) and should overwrite at least one of
|
||||
the basic `Guard::Guard` task methods.
|
||||
`Guard::GuardName` (in `lib/guard/guard-name.rb`) must inherit from `Guard::Guard` and should overwrite at least one of the five basic `Guard::Guard` instance methods.
|
||||
|
||||
Here is an example scaffold for `lib/guard/guard-name.rb`:
|
||||
|
||||
@ -368,52 +329,50 @@ Here is an example scaffold for `lib/guard/guard-name.rb`:
|
||||
module Guard
|
||||
class GuardName < Guard
|
||||
|
||||
# Initialize a Guard.
|
||||
# @param [Array<Guard::Watcher>] watchers the Guard file watchers
|
||||
# @param [Hash] options the custom Guard options
|
||||
def initialize(watchers = [], options = {})
|
||||
def initialize(watchers=[], options={})
|
||||
super
|
||||
# init stuff here, thx!
|
||||
end
|
||||
|
||||
# Call once when Guard starts. Please override initialize method to init stuff.
|
||||
# @raise [:task_has_failed] when start has failed
|
||||
# =================
|
||||
# = Guard methods =
|
||||
# =================
|
||||
|
||||
# If one of those methods raise an exception, the Guard::GuardName instance
|
||||
# will be removed from the active guards.
|
||||
|
||||
# Called once when Guard starts
|
||||
# Please override initialize method to init stuff
|
||||
def start
|
||||
true
|
||||
end
|
||||
|
||||
# Called when `stop|quit|exit|s|q|e + enter` is pressed (when Guard quits).
|
||||
# @raise [:task_has_failed] when stop has failed
|
||||
# Called when `stop|quit|exit|s|q|e + enter` is pressed (when Guard quits)
|
||||
def stop
|
||||
true
|
||||
end
|
||||
|
||||
# Called when `reload|r|z + enter` is pressed.
|
||||
# Called when `reload|r|z + enter` is pressed
|
||||
# This method should be mainly used for "reload" (really!) actions like reloading passenger/spork/bundler/...
|
||||
# @raise [:task_has_failed] when reload has failed
|
||||
def reload
|
||||
true
|
||||
end
|
||||
|
||||
# Called when just `enter` is pressed
|
||||
# This method should be principally used for long action like running all specs/tests/...
|
||||
# @raise [:task_has_failed] when run_all has failed
|
||||
def run_all
|
||||
true
|
||||
end
|
||||
|
||||
# Called on file(s) modifications that the Guard watches.
|
||||
# @param [Array<String>] paths the changes files or paths
|
||||
# @raise [:task_has_failed] when run_on_change has failed
|
||||
# Called on file(s) modifications
|
||||
def run_on_change(paths)
|
||||
end
|
||||
|
||||
# Called on file(s) deletions that the Guard watches.
|
||||
# @param [Array<String>] paths the deleted files or paths
|
||||
# @raise [:task_has_failed] when run_on_change has failed
|
||||
def run_on_deletion(paths)
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
Please take a look at the [existing guards' source code](https://github.com/guard/guard/wiki/List-of-available-Guards)
|
||||
for more concrete example and inspiration.
|
||||
Please take a look at the [existing guards' source code](https://github.com/guard/guard/wiki/List-of-available-Guards) for more concrete example and inspiration.
|
||||
|
||||
Alternatively, a new guard can be added inline to a Guardfile with this basic structure:
|
||||
|
||||
@ -422,14 +381,16 @@ Alternatively, a new guard can be added inline to a Guardfile with this basic st
|
||||
module ::Guard
|
||||
class InlineGuard < ::Guard::Guard
|
||||
def run_all
|
||||
true
|
||||
end
|
||||
|
||||
def run_on_change(paths)
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Here is a very cool example by [@avdi](https://github.com/avdi) : [http://avdi.org/devblog/2011/06/15/a-guardfile-for-redis](http://avdi.org/devblog/2011/06/15/a-guardfile-for-redis)
|
||||
Here is a very cool example by [@avdi](https://github.com/avdi) : http://avdi.org/devblog/2011/06/15/a-guardfile-for-redis
|
||||
|
||||
Development
|
||||
-----------
|
||||
@ -456,4 +417,4 @@ Author
|
||||
Contributors
|
||||
------------
|
||||
|
||||
[https://github.com/guard/guard/contributors](https://github.com/guard/guard/contributors)
|
||||
https://github.com/guard/guard/contributors
|
||||
|
@ -3,4 +3,4 @@
|
||||
require 'guard'
|
||||
require 'guard/cli'
|
||||
|
||||
Guard::CLI.start
|
||||
Guard::CLI.start
|
253
lib/guard.rb
253
lib/guard.rb
@ -1,5 +1,3 @@
|
||||
require 'thread'
|
||||
|
||||
# Guard is the main module for all Guard related modules and classes.
|
||||
# Also other Guard implementation should use this namespace.
|
||||
#
|
||||
@ -8,7 +6,6 @@ module Guard
|
||||
autoload :UI, 'guard/ui'
|
||||
autoload :Dsl, 'guard/dsl'
|
||||
autoload :DslDescriber, 'guard/dsl_describer'
|
||||
autoload :Group, 'guard/group'
|
||||
autoload :Interactor, 'guard/interactor'
|
||||
autoload :Listener, 'guard/listener'
|
||||
autoload :Watcher, 'guard/watcher'
|
||||
@ -16,109 +13,37 @@ module Guard
|
||||
autoload :Hook, 'guard/hook'
|
||||
|
||||
class << self
|
||||
attr_accessor :options, :interactor, :listener, :lock
|
||||
|
||||
# Creates the initial Guardfile template or add a Guard implementation
|
||||
# Guardfile template to an existing Guardfile.
|
||||
#
|
||||
# @see Guard::Guard.init
|
||||
#
|
||||
# @param [String] guard_name the name of the Guard to initialize
|
||||
#
|
||||
def initialize_template(guard_name = nil)
|
||||
if guard_name
|
||||
guard_class = ::Guard.get_guard_class(guard_name)
|
||||
guard_class.init(guard_name)
|
||||
else
|
||||
if !File.exist?('Guardfile')
|
||||
::Guard::UI.info "Writing new Guardfile to #{ Dir.pwd }/Guardfile"
|
||||
FileUtils.cp(File.expand_path('../templates/Guardfile', __FILE__), 'Guardfile')
|
||||
else
|
||||
::Guard::UI.error "Guardfile already exists at #{ Dir.pwd }/Guardfile"
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
end
|
||||
attr_accessor :options, :guards, :groups, :interactor, :listener
|
||||
|
||||
# Initialize the Guard singleton.
|
||||
#
|
||||
# @param [Hash] options the Guard options.
|
||||
# @option options [Boolean] clear if auto clear the UI should be done
|
||||
# @option options [Boolean] notify if system notifications should be shown
|
||||
# @option options [Boolean] debug if debug output should be shown
|
||||
# @option options [Array<String>] group the list of groups to start
|
||||
# @option options [String] watchdir the director to watch
|
||||
# @option options [String] guardfile the path to the Guardfile
|
||||
# @option options [Boolean] watch_all_modifications watches all file modifications if true
|
||||
#
|
||||
def setup(options = {})
|
||||
@lock = Mutex.new
|
||||
|
||||
@options = options
|
||||
@guards = []
|
||||
@groups = [Group.new(:default)]
|
||||
@interactor = Interactor.new unless @options[:no_interactions]
|
||||
@listener = Listener.select_and_init(@options[:watchdir] ? File.expand_path(@options[:watchdir]) : Dir.pwd, options)
|
||||
@groups = [{ :name => :default, :options => {} }]
|
||||
@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
|
||||
|
||||
UI.clear if @options[:clear]
|
||||
|
||||
debug_command_execution if @options[:debug]
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Smart accessor for retrieving a specific guard or several guards at once.
|
||||
#
|
||||
# @param [String, Symbol] filter return the guard with the given name, or nil if not found
|
||||
# @param [Regexp] filter returns all guards matching the Regexp, or [] if no guard found
|
||||
# @param [Hash] filter returns all guards matching the given Hash.
|
||||
# Example: `{ :name => 'rspec', :group => 'backend' }`, or [] if no guard found
|
||||
# @param [NilClass] filter returns all guards
|
||||
#
|
||||
# @see Guard.groups
|
||||
#
|
||||
def guards(filter = nil)
|
||||
case filter
|
||||
when String, Symbol
|
||||
@guards.find { |guard| guard.class.to_s.downcase.sub('guard::', '') == filter.to_s.downcase.gsub('-', '') }
|
||||
when Regexp
|
||||
@guards.find_all { |guard| guard.class.to_s.downcase.sub('guard::', '') =~ filter }
|
||||
when Hash
|
||||
filter.inject(@guards) do |matches, (k, v)|
|
||||
if k.to_sym == :name
|
||||
matches.find_all { |guard| guard.class.to_s.downcase.sub('guard::', '') == v.to_s.downcase.gsub('-', '') }
|
||||
else
|
||||
matches.find_all { |guard| guard.send(k).to_sym == v.to_sym }
|
||||
end
|
||||
end
|
||||
else
|
||||
@guards
|
||||
end
|
||||
end
|
||||
|
||||
# Smart accessor for retrieving a specific group or several groups at once.
|
||||
#
|
||||
# @param [NilClass] filter returns all groups
|
||||
# @param [String, Symbol] filter return the group with the given name, or nil if not found
|
||||
# @param [Regexp] filter returns all groups matching the Regexp, or [] if no group found
|
||||
#
|
||||
# @see Guard.guards
|
||||
#
|
||||
def groups(filter = nil)
|
||||
case filter
|
||||
when String, Symbol
|
||||
@groups.find { |group| group.name == filter.to_sym }
|
||||
when Regexp
|
||||
@groups.find_all { |group| group.name.to_s =~ filter }
|
||||
else
|
||||
@groups
|
||||
end
|
||||
end
|
||||
|
||||
# Start Guard by evaluate the `Guardfile`, initialize the declared Guards
|
||||
# and start the available file change listener.
|
||||
#
|
||||
# @param [Hash] options the Guard options.
|
||||
# @option options [Boolean] clear if auto clear the UI should be done
|
||||
# @option options [Boolean] notify if system notifications should be shown
|
||||
# @option options [Boolean] debug if debug output should be shown
|
||||
@ -138,9 +63,9 @@ module Guard
|
||||
|
||||
UI.info "Guard is now watching at '#{ listener.directory }'"
|
||||
|
||||
run_guard_task(:start)
|
||||
execute_supervised_task_for_all_guards(:start)
|
||||
|
||||
interactor.start if interactor
|
||||
interactor.start
|
||||
listener.start
|
||||
end
|
||||
|
||||
@ -148,10 +73,8 @@ module Guard
|
||||
#
|
||||
def stop
|
||||
UI.info 'Bye bye...', :reset => true
|
||||
|
||||
run_guard_task(:stop)
|
||||
|
||||
listener.stop
|
||||
execute_supervised_task_for_all_guards(:stop)
|
||||
abort
|
||||
end
|
||||
|
||||
@ -159,7 +82,7 @@ module Guard
|
||||
#
|
||||
def reload
|
||||
run do
|
||||
run_guard_task(:reload)
|
||||
execute_supervised_task_for_all_guards(:reload)
|
||||
end
|
||||
end
|
||||
|
||||
@ -167,20 +90,20 @@ module Guard
|
||||
#
|
||||
def run_all
|
||||
run do
|
||||
run_guard_task(:run_all)
|
||||
execute_supervised_task_for_all_guards(:run_all)
|
||||
end
|
||||
end
|
||||
|
||||
# Pause Guard listening to file changes.
|
||||
#
|
||||
def pause
|
||||
if listener.paused?
|
||||
if listener.locked
|
||||
UI.info 'Un-paused files modification listening', :reset => true
|
||||
listener.clear_changed_files
|
||||
listener.run
|
||||
listener.unlock
|
||||
else
|
||||
UI.info 'Paused files modification listening', :reset => true
|
||||
listener.pause
|
||||
listener.lock
|
||||
end
|
||||
end
|
||||
|
||||
@ -188,7 +111,7 @@ module Guard
|
||||
#
|
||||
def run_on_change(paths)
|
||||
run do
|
||||
run_guard_task(:run_on_change, paths)
|
||||
execute_supervised_task_for_all_guards(:run_on_change, paths)
|
||||
end
|
||||
end
|
||||
|
||||
@ -198,144 +121,70 @@ module Guard
|
||||
# @yield the block to run
|
||||
#
|
||||
def run
|
||||
listener.lock
|
||||
interactor.lock
|
||||
UI.clear if options[:clear]
|
||||
|
||||
lock.synchronize do
|
||||
begin
|
||||
interactor.stop_if_not_current if interactor
|
||||
yield
|
||||
rescue Interrupt
|
||||
end
|
||||
|
||||
interactor.start if interactor
|
||||
begin
|
||||
yield
|
||||
rescue Interrupt
|
||||
end
|
||||
interactor.unlock
|
||||
listener.unlock
|
||||
end
|
||||
|
||||
# Loop through all groups and run the given task for each Guard.
|
||||
#
|
||||
# Stop the task run for the all Guards within a group if one Guard
|
||||
# throws `:task_has_failed`.
|
||||
# Loop through all groups and execute the given task for each Guard in it,
|
||||
# but halt the task execution for the all Guards within a group if one Guard
|
||||
# throws `:task_has_failed` and the group has its `:halt_on_fail` option to `true`.
|
||||
#
|
||||
# @param [Symbol] task the task to run
|
||||
# @param [Array<String>] files the list of files to pass to the task
|
||||
# @param [Array] files the list of files to pass to the task
|
||||
#
|
||||
def run_guard_task(task, files = nil)
|
||||
groups.each do |group|
|
||||
catch :task_has_failed do
|
||||
guards(:group => group.name).each do |guard|
|
||||
def execute_supervised_task_for_all_guards(task, files = nil)
|
||||
groups.each do |group_hash|
|
||||
catch group_hash[:options][:halt_on_fail] == true ? :task_has_failed : :no_catch do
|
||||
guards.find_all { |guard| guard.group == group_hash[:name] }.each do |guard|
|
||||
if task == :run_on_change
|
||||
run_on_change_task(files, guard, task)
|
||||
paths = Watcher.match_files(guard, files)
|
||||
UI.debug "#{guard.class.name}##{task} with #{paths.inspect}"
|
||||
supervised_task(guard, task, paths)
|
||||
else
|
||||
run_supervised_task(guard, task)
|
||||
supervised_task(guard, task)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Run the `:run_on_change` task. When the option `:watch_all_modifications` is set,
|
||||
# the task is split to run changed paths on {Guard::Guard#run_on_change}, whereas
|
||||
# deleted paths run on {Guard::Guard#run_on_deletion}.
|
||||
#
|
||||
# @param [Array<String>] files the list of files to pass to the task
|
||||
# @param [Guard::Guard] guard the guard to run
|
||||
# @param [Symbol] task the task to run
|
||||
# @raise [:task_has_failed] when task has failed
|
||||
#
|
||||
def run_on_change_task(files, guard, task)
|
||||
paths = Watcher.match_files(guard, files)
|
||||
changes = changed_paths(paths)
|
||||
deletions = deleted_paths(paths)
|
||||
|
||||
unless changes.empty?
|
||||
UI.debug "#{ guard.class.name }##{ task } with #{ changes.inspect }"
|
||||
run_supervised_task(guard, task, changes)
|
||||
end
|
||||
|
||||
unless deletions.empty?
|
||||
UI.debug "#{ guard.class.name }#run_on_deletion with #{ deletions.inspect }"
|
||||
run_supervised_task(guard, :run_on_deletion, deletions)
|
||||
end
|
||||
end
|
||||
|
||||
# Detects the paths that have changed.
|
||||
#
|
||||
# Deleted paths are prefixed by an exclamation point.
|
||||
# @see Guard::Listener#modified_files
|
||||
#
|
||||
# @param [Array<String>] paths the watched paths
|
||||
# @return [Array<String>] the changed paths
|
||||
#
|
||||
def changed_paths(paths)
|
||||
paths.select { |f| !f.start_with?('!') }
|
||||
end
|
||||
|
||||
# Detects the paths that have been deleted.
|
||||
#
|
||||
# Deleted paths are prefixed by an exclamation point.
|
||||
# @see Guard::Listener#modified_files
|
||||
#
|
||||
# @param [Array<String>] paths the watched paths
|
||||
# @return [Array<String>] the deleted paths
|
||||
#
|
||||
def deleted_paths(paths)
|
||||
paths.select { |f| f.start_with?('!') }.map { |f| f.slice(1..-1) }
|
||||
end
|
||||
|
||||
# Run a Guard task, but remove the Guard when his work leads to a system failure.
|
||||
#
|
||||
# When the Group has `:halt_on_fail` disabled, we've to catch `:task_has_failed`
|
||||
# here in order to avoid an uncaught throw error.
|
||||
# Let a Guard execute its task, but fire it
|
||||
# if his work leads to a system failure.
|
||||
#
|
||||
# @param [Guard::Guard] guard the Guard to execute
|
||||
# @param [Symbol] task the task to run
|
||||
# @param [Symbol] task_to_supervise the task to run
|
||||
# @param [Array] args the arguments for the task
|
||||
# @raise [:task_has_failed] when task has failed
|
||||
# @return [Boolean, Exception] the result of the Guard
|
||||
#
|
||||
def run_supervised_task(guard, task, *args)
|
||||
catch guard_symbol(guard) do
|
||||
guard.hook("#{ task }_begin", *args)
|
||||
result = guard.send(task, *args)
|
||||
guard.hook("#{ task }_end", result)
|
||||
def supervised_task(guard, task_to_supervise, *args)
|
||||
guard.hook("#{ task_to_supervise }_begin", *args)
|
||||
result = guard.send(task_to_supervise, *args)
|
||||
guard.hook("#{ task_to_supervise }_end", result)
|
||||
|
||||
result
|
||||
end
|
||||
result
|
||||
|
||||
rescue Exception => ex
|
||||
UI.error("#{ guard.class.name } failed to achieve its <#{ task.to_s }>, exception was:" +
|
||||
UI.error("#{ guard.class.name } failed to achieve its <#{ task_to_supervise.to_s }>, exception was:" +
|
||||
"\n#{ ex.class }: #{ ex.message }\n#{ ex.backtrace.join("\n") }")
|
||||
|
||||
guards.delete guard
|
||||
UI.info("\n#{ guard.class.name } has just been fired")
|
||||
|
||||
ex
|
||||
end
|
||||
|
||||
# Get the symbol we have to catch when running a supervised task.
|
||||
# If we are within a Guard group that has the `:halt_on_fail`
|
||||
# option set, we do NOT catch it here, it will be catched at the
|
||||
# group level.
|
||||
#
|
||||
# @see .run_guard_task
|
||||
#
|
||||
# @param [Guard::Guard] guard the Guard to execute
|
||||
# @return [Symbol] the symbol to catch
|
||||
#
|
||||
def guard_symbol(guard)
|
||||
if guard.group.class == Symbol
|
||||
group = groups(guard.group)
|
||||
group.options[:halt_on_fail] ? :no_catch : :task_has_failed
|
||||
else
|
||||
:task_has_failed
|
||||
end
|
||||
end
|
||||
|
||||
# Add a Guard to use.
|
||||
#
|
||||
# @param [String] name the Guard name
|
||||
# @param [Array<Watcher>] watchers the list of declared watchers
|
||||
# @param [Array<Hash>] callbacks the list of callbacks
|
||||
# @param [Hash] options the Guard options (see the given Guard documentation)
|
||||
# @param [Hash] options the Guard options
|
||||
#
|
||||
def add_guard(name, watchers = [], callbacks = [], options = {})
|
||||
if name.to_sym == :ego
|
||||
@ -350,17 +199,11 @@ module Guard
|
||||
# Add a Guard group.
|
||||
#
|
||||
# @param [String] name the group name
|
||||
# @option options [Boolean] halt_on_fail if a task execution
|
||||
# should be halted for all Guards in this group if one Guard throws `:task_has_failed`
|
||||
# @return [Guard::Group] the group added (or retrieved from the `@groups` variable if already present)
|
||||
# @param [Hash] options the group options
|
||||
# @option options [Boolean] halt_on_fail if a task execution should be halted for all Guards in this group if one Guard throws `:task_has_failed`
|
||||
#
|
||||
def add_group(name, options = {})
|
||||
group = groups(name)
|
||||
if group.nil?
|
||||
group = Group.new(name, options)
|
||||
@groups << group
|
||||
end
|
||||
group
|
||||
@groups << { :name => name.to_sym, :options => options } unless name.nil? || @groups.find { |group| group[:name] == name }
|
||||
end
|
||||
|
||||
# Tries to load the Guard main class.
|
||||
|
@ -3,9 +3,8 @@ require 'guard/version'
|
||||
|
||||
module Guard
|
||||
|
||||
# Facade for the Guard command line interface managed by [Thor](https://github.com/wycats/thor).
|
||||
# Guard command line interface managed by [Thor](https://github.com/wycats/thor).
|
||||
# This is the main interface to Guard that is called by the Guard binary `bin/guard`.
|
||||
# Do not put any logic in here, create a class and delegate instead.
|
||||
#
|
||||
class CLI < Thor
|
||||
|
||||
@ -47,18 +46,6 @@ module Guard
|
||||
:aliases => '-G',
|
||||
:banner => 'Specify a Guardfile'
|
||||
|
||||
method_option :watch_all_modifications,
|
||||
:type => :boolean,
|
||||
:default => false,
|
||||
:aliases => '-A',
|
||||
:banner => 'Watch for all file modifications including moves and deletions'
|
||||
|
||||
method_option :no_interactions,
|
||||
:type => :boolean,
|
||||
:default => false,
|
||||
:aliases => '-i',
|
||||
:banner => 'Turn off completely any guard terminal interactions'
|
||||
|
||||
# Start Guard by initialize the defined Guards and watch the file system.
|
||||
# This is the default task, so calling `guard` is the same as calling `guard start`.
|
||||
#
|
||||
@ -73,10 +60,37 @@ module Guard
|
||||
# List the Guards that are available for use in your system and marks
|
||||
# those that are currently used in your `Guardfile`.
|
||||
#
|
||||
# @see Guard::DslDescriber.list
|
||||
# @example Guard list output
|
||||
#
|
||||
# Available guards:
|
||||
# bundler *
|
||||
# livereload
|
||||
# ronn
|
||||
# rspec *
|
||||
# spork
|
||||
#
|
||||
# See also https://github.com/guard/guard/wiki/List-of-available-Guards
|
||||
# * denotes ones already in your Guardfile
|
||||
#
|
||||
# @see Guard::DslDescriber
|
||||
#
|
||||
def list
|
||||
::Guard::DslDescriber.list(options)
|
||||
Guard::DslDescriber.evaluate_guardfile(options)
|
||||
|
||||
installed = Guard::DslDescriber.guardfile_structure.inject([]) do |installed, group|
|
||||
group[:guards].each { |guard| installed << guard[:name] } if group[:guards]
|
||||
installed
|
||||
end
|
||||
|
||||
Guard::UI.info 'Available guards:'
|
||||
|
||||
Guard::guard_gem_names.sort.uniq.each do |name|
|
||||
Guard::UI.info " #{ name } #{ installed.include?(name) ? '*' : '' }"
|
||||
end
|
||||
|
||||
Guard::UI.info ' '
|
||||
Guard::UI.info 'See also https://github.com/guard/guard/wiki/List-of-available-Guards'
|
||||
Guard::UI.info '* denotes ones already in your Guardfile'
|
||||
end
|
||||
|
||||
desc 'version', 'Show the Guard version'
|
||||
@ -87,7 +101,7 @@ module Guard
|
||||
# @see Guard::VERSION
|
||||
#
|
||||
def version
|
||||
::Guard::UI.info "Guard version #{ Guard::VERSION }"
|
||||
Guard::UI.info "Guard version #{ Guard::VERSION }"
|
||||
end
|
||||
|
||||
desc 'init [GUARD]', 'Generates a Guardfile at the current working directory, or insert the given GUARD to an existing Guardfile'
|
||||
@ -95,12 +109,22 @@ module Guard
|
||||
# Appends the Guard template to the `Guardfile`, or creates an initial
|
||||
# `Guardfile` when no Guard name is passed.
|
||||
#
|
||||
# @see Guard.initialize_template
|
||||
#
|
||||
# @param [String] guard_name the name of the Guard to initialize
|
||||
#
|
||||
def init(guard_name = nil)
|
||||
::Guard.initialize_template(guard_name)
|
||||
if guard_name
|
||||
guard_class = ::Guard.get_guard_class(guard_name)
|
||||
guard_class.init(guard_name)
|
||||
|
||||
else
|
||||
if File.exist?('Guardfile')
|
||||
puts 'Writing new Guardfile to #{Dir.pwd}/Guardfile'
|
||||
FileUtils.cp(File.expand_path('../templates/Guardfile', __FILE__), 'Guardfile')
|
||||
else
|
||||
Guard::UI.error "Guardfile already exists at #{ Dir.pwd }/Guardfile"
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc 'show', 'Show all defined Guards and their options'
|
||||
@ -109,10 +133,40 @@ module Guard
|
||||
# Shows all Guards and their options that are defined in
|
||||
# the `Guardfile`.
|
||||
#
|
||||
# @see Guard::DslDescriber.show
|
||||
# @example guard show output
|
||||
#
|
||||
# (global):
|
||||
# bundler
|
||||
# coffeescript: input => "app/assets/javascripts", noop => true
|
||||
# jasmine
|
||||
# rspec: cli => "--fail-fast --format Fuubar
|
||||
#
|
||||
# @see Guard::DslDescriber
|
||||
#
|
||||
def show
|
||||
::Guard::DslDescriber.show(options)
|
||||
Guard::DslDescriber.evaluate_guardfile(options)
|
||||
|
||||
Guard::DslDescriber.guardfile_structure.each do |group|
|
||||
unless group[:guards].empty?
|
||||
if group[:group]
|
||||
Guard::UI.info "Group #{ group[:group] }:"
|
||||
else
|
||||
Guard::UI.info '(global):'
|
||||
end
|
||||
|
||||
group[:guards].each do |guard|
|
||||
line = " #{ guard[:name] }"
|
||||
|
||||
unless guard[:options].empty?
|
||||
line += ": #{ guard[:options].collect { |k, v| "#{ k } => #{ v.inspect }" }.join(', ') }"
|
||||
end
|
||||
|
||||
Guard::UI.info line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Guard::UI.info ''
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -81,6 +81,7 @@ module Guard
|
||||
|
||||
# Evaluate the DSL methods in the `Guardfile`.
|
||||
#
|
||||
# @param [Hash] options the Guard options
|
||||
# @option options [Array<Symbol,String>] groups the groups to evaluate
|
||||
# @option options [String] guardfile the path to a valid Guardfile
|
||||
# @option options [String] guardfile_contents a string representing the content of a valid Guardfile
|
||||
|
@ -2,8 +2,6 @@ require 'guard/dsl'
|
||||
|
||||
module Guard
|
||||
|
||||
autoload :UI, 'guard/ui'
|
||||
|
||||
# The DslDescriber overrides methods to create an internal structure
|
||||
# of the Guardfile that is used in some inspection utility methods
|
||||
# like the CLI commands `show` and `list`.
|
||||
@ -13,97 +11,10 @@ module Guard
|
||||
#
|
||||
class DslDescriber < Dsl
|
||||
|
||||
@@guardfile_structure = [ { :guards => [] } ]
|
||||
|
||||
class << self
|
||||
|
||||
# Evaluate the DSL methods in the `Guardfile`.
|
||||
#
|
||||
# @option options [Array<Symbol,String>] groups the groups to evaluate
|
||||
# @option options [String] guardfile the path to a valid Guardfile
|
||||
# @option options [String] guardfile_contents a string representing the content of a valid Guardfile
|
||||
# @raise [ArgumentError] when options are not a Hash
|
||||
#
|
||||
def evaluate_guardfile(options = {})
|
||||
@@guardfile_structure = [{ :guards => [] }]
|
||||
super options
|
||||
end
|
||||
|
||||
# List the Guards that are available for use in your system and marks
|
||||
# those that are currently used in your `Guardfile`.
|
||||
#
|
||||
# @example Guard list output
|
||||
#
|
||||
# Available guards:
|
||||
# bundler *
|
||||
# livereload
|
||||
# ronn
|
||||
# rspec *
|
||||
# spork
|
||||
#
|
||||
# See also https://github.com/guard/guard/wiki/List-of-available-Guards
|
||||
# * denotes ones already in your Guardfile
|
||||
#
|
||||
# @param [Hash] options the Guard options
|
||||
#
|
||||
def list(options)
|
||||
evaluate_guardfile(options)
|
||||
|
||||
installed = guardfile_structure.inject([]) do |installed, group|
|
||||
group[:guards].each { |guard| installed << guard[:name] } if group[:guards]
|
||||
installed
|
||||
end
|
||||
|
||||
UI.info 'Available guards:'
|
||||
|
||||
::Guard.guard_gem_names.sort.uniq.each do |name|
|
||||
UI.info " #{ name }#{ installed.include?(name) ? '*' : '' }"
|
||||
end
|
||||
|
||||
UI.info ''
|
||||
UI.info 'See also https://github.com/guard/guard/wiki/List-of-available-Guards'
|
||||
UI.info '* denotes ones already in your Guardfile'
|
||||
end
|
||||
|
||||
# Shows all Guards and their options that are defined in
|
||||
# the `Guardfile`.
|
||||
#
|
||||
# @example guard show output
|
||||
#
|
||||
# (global):
|
||||
# bundler
|
||||
# coffeescript: input => "app/assets/javascripts", noop => true
|
||||
# jasmine
|
||||
# rspec: cli => "--fail-fast --format Fuubar
|
||||
#
|
||||
# @param [Hash] options the Guard options
|
||||
#
|
||||
def show(options)
|
||||
evaluate_guardfile(options)
|
||||
|
||||
guardfile_structure.each do |group|
|
||||
unless group[:guards].empty?
|
||||
if group[:group]
|
||||
UI.info "Group #{ group[:group] }:"
|
||||
else
|
||||
UI.info '(global):'
|
||||
end
|
||||
|
||||
group[:guards].each do |guard|
|
||||
line = " #{ guard[:name] }"
|
||||
|
||||
unless guard[:options].empty?
|
||||
line += ": #{ guard[:options].sort.collect { |k, v| "#{ k } => #{ v.inspect }" }.join(', ') }"
|
||||
end
|
||||
|
||||
UI.info line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
UI.info ''
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Get the Guardfile structure.
|
||||
#
|
||||
# @return [Array<Hash>] the structure
|
||||
@ -111,7 +22,6 @@ module Guard
|
||||
def guardfile_structure
|
||||
@@guardfile_structure
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
private
|
||||
@ -140,7 +50,7 @@ module Guard
|
||||
#
|
||||
# @see Guard::Dsl#guard
|
||||
#
|
||||
def guard(name, options = { })
|
||||
def guard(name, options = {})
|
||||
node = (@group ? @@guardfile_structure.last : @@guardfile_structure.first)
|
||||
|
||||
node[:guards] << { :name => name, :options => options }
|
||||
|
@ -1,37 +0,0 @@
|
||||
module Guard
|
||||
|
||||
# A group of Guards. There are two reasons why you want to group your guards:
|
||||
#
|
||||
# - You can start only certain Groups from the command line by passing the `--group` option.
|
||||
# - Abort task execution chain on failure within a group.
|
||||
#
|
||||
# @example Group that aborts on failure
|
||||
#
|
||||
# group :frontend, :halt_on_fail => true do
|
||||
# guard 'coffeescript', :input => 'spec/coffeescripts', :output => 'spec/javascripts'
|
||||
# guard 'jasmine-headless-webkit' do
|
||||
# watch(%r{^spec/javascripts/(.*)\..*}) { |m| newest_js_file("spec/javascripts/#{m[1]}_spec") }
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# @see Guard::CLI
|
||||
#
|
||||
class Group
|
||||
|
||||
attr_accessor :name, :options
|
||||
|
||||
# Initialize a Group.
|
||||
#
|
||||
# @param [String] name the name of the group
|
||||
# @param [Hash] options the group options
|
||||
# @option options [Boolean] halt_on_fail if a task execution
|
||||
# should be halted for all Guards in this group if one Guard throws `:task_has_failed`
|
||||
#
|
||||
def initialize(name, options = {})
|
||||
@name = name.to_sym
|
||||
@options = options
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
@ -2,37 +2,12 @@ module Guard
|
||||
|
||||
# Main class that every Guard implementation must subclass.
|
||||
#
|
||||
# Guard will trigger the `start`, `stop`, `reload`, `run_all`, `run_on_change` and
|
||||
# `run_on_deletion` task methods depending on user interaction and file modification.
|
||||
#
|
||||
# In each of these Guard task methods you have to implement some work when you want to
|
||||
# support this kind of task. The return value of each Guard task method is not evaluated
|
||||
# by Guard, but I'll be passed to the "_end" hook for further evaluation. You can
|
||||
# throw `:task_has_failed` to indicate that your Guard method was not successful,
|
||||
# and successive guard tasks will be aborted when the group has set the `:halt_on_fail`
|
||||
# option.
|
||||
#
|
||||
# @see Guard::Hook
|
||||
# @see Guard::Group
|
||||
#
|
||||
# @example Throw :task_has_failed
|
||||
#
|
||||
# def run_all
|
||||
# if !runner.run(['all'])
|
||||
# throw :task_has_failed
|
||||
# end
|
||||
# end
|
||||
# Guard will trigger the `start`, `stop`, `reload`, `run_all` and `run_on_change`
|
||||
# methods depending on user interaction and file modification.
|
||||
#
|
||||
# Each Guard should provide a template Guardfile located within the Gem
|
||||
# at `lib/guard/guard-name/templates/Guardfile`.
|
||||
#
|
||||
# By default all watchers for a Guard are returning strings of paths to the
|
||||
# Guard, but if your Guard want to allow any return value from a watcher,
|
||||
# you can set the `any_return` option to true.
|
||||
#
|
||||
# If one of those methods raise an exception other than `:task_has_failed`,
|
||||
# the Guard::GuardName instance will be removed from the active guards.
|
||||
#
|
||||
class Guard
|
||||
include Hook
|
||||
|
||||
@ -41,12 +16,10 @@ module Guard
|
||||
# Initialize a Guard.
|
||||
#
|
||||
# @param [Array<Guard::Watcher>] watchers the Guard file watchers
|
||||
# @param [Hash] options the custom Guard options
|
||||
# @options [Symbol] group the group this Guard belongs to
|
||||
# @options [Boolean] any_return allow any object to be returned from a watcher
|
||||
# @param [Hash] options the custom Guard options.
|
||||
#
|
||||
def initialize(watchers = [], options = {})
|
||||
@group = options[:group] ? options.delete(:group).to_sym : :default
|
||||
@group = options.delete(:group) || :default
|
||||
@watchers, @options = watchers, options
|
||||
end
|
||||
|
||||
@ -61,69 +34,55 @@ module Guard
|
||||
else
|
||||
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)
|
||||
end
|
||||
|
||||
::Guard::UI.info "#{ name } guard added to Guardfile, feel free to edit it"
|
||||
::Guard::UI.info "#{name} guard added to Guardfile, feel free to edit it"
|
||||
end
|
||||
end
|
||||
|
||||
# Call once when Guard starts. Please override initialize method to init stuff.
|
||||
#
|
||||
# @raise [:task_has_failed] when start has failed
|
||||
# @return [Object] the task result
|
||||
# @return [Boolean] Whether the start action was successful or not
|
||||
#
|
||||
def start
|
||||
true
|
||||
end
|
||||
|
||||
# Called when `stop|quit|exit|s|q|e + enter` is pressed (when Guard quits).
|
||||
# Call once when Guard quit.
|
||||
#
|
||||
# @raise [:task_has_failed] when stop has failed
|
||||
# @return [Object] the task result
|
||||
# @return [Boolean] Whether the stop action was successful or not
|
||||
#
|
||||
def stop
|
||||
true
|
||||
end
|
||||
|
||||
# Called when `reload|r|z + enter` is pressed.
|
||||
# This method should be mainly used for "reload" (really!) actions like reloading passenger/spork/bundler/...
|
||||
# Should be used for "reload" (really!) actions like reloading passenger/spork/bundler/...
|
||||
#
|
||||
# @raise [:task_has_failed] when reload has failed
|
||||
# @return [Object] the task result
|
||||
# @return [Boolean] Whether the reload action was successful or not
|
||||
#
|
||||
def reload
|
||||
true
|
||||
end
|
||||
|
||||
# Called when just `enter` is pressed
|
||||
# This method should be principally used for long action like running all specs/tests/...
|
||||
# Should be used for long action like running all specs/tests/...
|
||||
#
|
||||
# @raise [:task_has_failed] when run_all has failed
|
||||
# @return [Object] the task result
|
||||
# @return [Boolean] Whether the run_all action was successful or not
|
||||
#
|
||||
def run_all
|
||||
true
|
||||
end
|
||||
|
||||
# Called on file(s) modifications that the Guard watches.
|
||||
# Will be triggered when a file change matched a watcher.
|
||||
#
|
||||
# @param [Array<String>] paths the changes files or paths
|
||||
# @raise [:task_has_failed] when run_on_change has failed
|
||||
# @return [Object] the task result
|
||||
# @return [Boolean] Whether the run_all action was successful or not
|
||||
#
|
||||
def run_on_change(paths)
|
||||
end
|
||||
|
||||
# Called on file(s) deletions that the Guard watches.
|
||||
#
|
||||
# @param [Array<String>] paths the deleted files or paths
|
||||
# @raise [:task_has_failed] when run_on_change has failed
|
||||
# @return [Object] the task result
|
||||
#
|
||||
def run_on_deletion(paths)
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -11,34 +11,67 @@ module Guard
|
||||
# - Everything else => Run all
|
||||
#
|
||||
class Interactor
|
||||
|
||||
class LockException < Exception; end
|
||||
class UnlockException < Exception; end
|
||||
|
||||
attr_reader :locked
|
||||
|
||||
# Initialize the interactor in unlocked state.
|
||||
#
|
||||
def initialize
|
||||
@locked = false
|
||||
end
|
||||
|
||||
# Start the interactor in its own thread.
|
||||
#
|
||||
def start
|
||||
return if ENV["GUARD_ENV"] == 'test'
|
||||
|
||||
if !@thread || @thread.stop?
|
||||
@thread = Thread.new do
|
||||
while entry = $stdin.gets.chomp
|
||||
case entry
|
||||
when 'stop', 'quit', 'exit', 's', 'q', 'e'
|
||||
::Guard.stop
|
||||
when 'reload', 'r', 'z'
|
||||
::Guard::Dsl.reevaluate_guardfile
|
||||
::Guard.reload
|
||||
when 'pause', 'p'
|
||||
::Guard.pause
|
||||
else
|
||||
::Guard.run_all
|
||||
@thread = Thread.new do
|
||||
loop do
|
||||
begin
|
||||
if !@locked && (entry = $stdin.gets)
|
||||
entry.gsub! /\n/, ''
|
||||
case entry
|
||||
when 'stop', 'quit', 'exit', 's', 'q', 'e'
|
||||
::Guard.stop
|
||||
when 'reload', 'r', 'z'
|
||||
::Guard.reload
|
||||
when 'pause', 'p'
|
||||
::Guard.pause
|
||||
else
|
||||
::Guard.run_all
|
||||
end
|
||||
end
|
||||
rescue LockException
|
||||
lock
|
||||
rescue UnlockException
|
||||
unlock
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def stop_if_not_current
|
||||
unless Thread.current == @thread
|
||||
@thread.kill
|
||||
# Lock the interactor.
|
||||
#
|
||||
def lock
|
||||
if !@thread || @thread == Thread.current
|
||||
@locked = true
|
||||
else
|
||||
@thread.raise(LockException)
|
||||
end
|
||||
end
|
||||
|
||||
# Unlock the interactor.
|
||||
#
|
||||
def unlock
|
||||
if !@thread || @thread == Thread.current
|
||||
@locked = false
|
||||
else
|
||||
@thread.raise(UnlockException)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -19,11 +19,7 @@ module Guard
|
||||
DEFAULT_IGNORE_PATHS = %w[. .. .bundle .git log tmp vendor]
|
||||
|
||||
attr_accessor :changed_files
|
||||
attr_reader :directory, :ignore_paths
|
||||
|
||||
def paused?
|
||||
@paused
|
||||
end
|
||||
attr_reader :directory, :ignore_paths, :locked
|
||||
|
||||
# Select the appropriate listener implementation for the
|
||||
# current OS and initializes it.
|
||||
@ -47,19 +43,18 @@ module Guard
|
||||
# Initialize the listener.
|
||||
#
|
||||
# @param [String] directory the root directory to listen to
|
||||
# @param [Hash] options the listener options
|
||||
# @option options [Boolean] relativize_paths use only relative paths
|
||||
# @option options [Array<String>] ignore_paths the paths to ignore by the listener
|
||||
#
|
||||
def initialize(directory = Dir.pwd, options = {})
|
||||
@directory = directory.to_s
|
||||
@sha1_checksums_hash = {}
|
||||
@file_timestamp_hash = {}
|
||||
@relativize_paths = options.fetch(:relativize_paths, true)
|
||||
@changed_files = []
|
||||
@paused = false
|
||||
@ignore_paths = DEFAULT_IGNORE_PATHS
|
||||
@ignore_paths |= options[:ignore_paths] if options[:ignore_paths]
|
||||
@watch_all_modifications = options.fetch(:watch_all_modifications, false)
|
||||
@directory = directory.to_s
|
||||
@sha1_checksums_hash = { }
|
||||
@relativize_paths = options.fetch(:relativize_paths, true)
|
||||
@changed_files = []
|
||||
@locked = false
|
||||
@ignore_paths = DEFAULT_IGNORE_PATHS
|
||||
@ignore_paths |= options[:ignore_paths] if options[:ignore_paths]
|
||||
|
||||
update_last_event
|
||||
start_reactor
|
||||
@ -72,7 +67,7 @@ module Guard
|
||||
|
||||
Thread.new do
|
||||
loop do
|
||||
if @changed_files != [] && !@paused
|
||||
if @changed_files != [] && !@locked
|
||||
changed_files = @changed_files.dup
|
||||
clear_changed_files
|
||||
::Guard.run_on_change(changed_files)
|
||||
@ -87,7 +82,6 @@ module Guard
|
||||
#
|
||||
def start
|
||||
watch(@directory)
|
||||
timestamp_files
|
||||
end
|
||||
|
||||
# Stop listening for events.
|
||||
@ -95,16 +89,16 @@ module Guard
|
||||
def stop
|
||||
end
|
||||
|
||||
# Pause the listener to ignore change events.
|
||||
# Lock the listener to ignore change events.
|
||||
#
|
||||
def pause
|
||||
@paused = true
|
||||
def lock
|
||||
@locked = true
|
||||
end
|
||||
|
||||
# Unpause the listener to listen again to change events.
|
||||
# Unlock the listener to listen again to change events.
|
||||
#
|
||||
def run
|
||||
@paused = false
|
||||
def unlock
|
||||
@locked = false
|
||||
end
|
||||
|
||||
# Clear the list of changed files.
|
||||
@ -129,33 +123,13 @@ module Guard
|
||||
|
||||
# Get the modified files.
|
||||
#
|
||||
# If the `:watch_all_modifications` option is true, then moved and
|
||||
# deleted files are also reported, but prefixed by an exclamation point.
|
||||
#
|
||||
# @example Deleted or moved file
|
||||
# !/home/user/dir/file.rb
|
||||
#
|
||||
# @param [Array<String>] dirs the watched directories
|
||||
# @param [Hash] options the listener options
|
||||
# @option options [Symbol] all whether to files in sub directories
|
||||
# @return [Array<String>] paths of files that have been modified
|
||||
#
|
||||
def modified_files(dirs, options = {})
|
||||
last_event = @last_event
|
||||
files = []
|
||||
if @watch_all_modifications
|
||||
deleted_files = @file_timestamp_hash.collect do |path, ts|
|
||||
unless File.exists?(path)
|
||||
@sha1_checksums_hash.delete(path)
|
||||
@file_timestamp_hash.delete(path)
|
||||
"!#{path}"
|
||||
end
|
||||
end
|
||||
files.concat(deleted_files.compact)
|
||||
end
|
||||
update_last_event
|
||||
files.concat(potentially_modified_files(dirs, options).select { |path| file_modified?(path, last_event) })
|
||||
|
||||
files = potentially_modified_files(dirs, options).select { |path| file_modified?(path, last_event) }
|
||||
relativize_paths(files)
|
||||
end
|
||||
|
||||
@ -184,7 +158,7 @@ module Guard
|
||||
def relativize_paths(paths)
|
||||
return paths unless relativize_paths?
|
||||
paths.map do |path|
|
||||
path.gsub(%r{^(!)?#{ @directory }/},'\1')
|
||||
path.gsub(%r{^#{ @directory }/}, '')
|
||||
end
|
||||
end
|
||||
|
||||
@ -196,12 +170,6 @@ module Guard
|
||||
!!@relativize_paths
|
||||
end
|
||||
|
||||
# Populate initial timestamp file hash to watch for deleted or moved files.
|
||||
#
|
||||
def timestamp_files
|
||||
all_files.each {|path| set_file_timestamp_hash(path, file_timestamp(path)) } if @watch_all_modifications
|
||||
end
|
||||
|
||||
# Removes the ignored paths from the directory list.
|
||||
#
|
||||
# @param [Array<String>] dirs the directory to listen to
|
||||
@ -219,8 +187,8 @@ module Guard
|
||||
# Gets a list of files that are in the modified directories.
|
||||
#
|
||||
# @param [Array<String>] dirs the list of directories
|
||||
# @param [Hash] options the find file option
|
||||
# @option options [Symbol] all whether to files in sub directories
|
||||
# @param [Hash] options the options
|
||||
# @option options [Symbol] all whether to include all files
|
||||
#
|
||||
def potentially_modified_files(dirs, options = {})
|
||||
paths = exclude_ignored_paths(dirs)
|
||||
@ -258,12 +226,6 @@ module Guard
|
||||
elsif mtime > last_event.to_i
|
||||
set_sha1_checksums_hash(path, sha1_checksum(path))
|
||||
true
|
||||
elsif @watch_all_modifications
|
||||
ts = file_timestamp(path)
|
||||
if ts != @file_timestamp_hash[path]
|
||||
set_file_timestamp_hash(path, ts)
|
||||
true
|
||||
end
|
||||
else
|
||||
false
|
||||
end
|
||||
@ -286,15 +248,6 @@ module Guard
|
||||
end
|
||||
end
|
||||
|
||||
# Set save a files current timestamp
|
||||
#
|
||||
# @param [String] path the file path
|
||||
# @param [Int] file_timestamp the files modified timestamp
|
||||
#
|
||||
def set_file_timestamp_hash(path, file_timestamp)
|
||||
@file_timestamp_hash[path] = file_timestamp
|
||||
end
|
||||
|
||||
# Set the current checksum of a file.
|
||||
#
|
||||
# @param [String] path the file path
|
||||
@ -304,15 +257,6 @@ module Guard
|
||||
@sha1_checksums_hash[path] = sha1_checksum
|
||||
end
|
||||
|
||||
# Gets a files modified timestamp
|
||||
#
|
||||
# @path [String] path the file path
|
||||
# @return [Int] file modified timestamp
|
||||
#
|
||||
def file_timestamp(path)
|
||||
File.mtime(path).to_i
|
||||
end
|
||||
|
||||
# Calculates the SHA1 checksum of a file.
|
||||
#
|
||||
# @param [String] path the path to the file
|
||||
|
@ -26,6 +26,7 @@ module Guard
|
||||
def stop
|
||||
super
|
||||
@stop = true
|
||||
sleep(@latency)
|
||||
end
|
||||
|
||||
# Check if the listener is usable on the current OS.
|
||||
|
@ -15,276 +15,198 @@ module Guard
|
||||
# Application name as shown in the specific notification settings
|
||||
APPLICATION_NAME = "Guard"
|
||||
|
||||
class << self
|
||||
# Turn notifications off.
|
||||
#
|
||||
def self.turn_off
|
||||
ENV["GUARD_NOTIFY"] = 'false'
|
||||
end
|
||||
|
||||
attr_accessor :growl_library, :gntp
|
||||
|
||||
# Turn notifications off.
|
||||
#
|
||||
def turn_off
|
||||
ENV["GUARD_NOTIFY"] = 'false'
|
||||
# Turn notifications on. This tries to load the platform
|
||||
# specific notification library.
|
||||
#
|
||||
# @return [Boolean] whether the notification could be enabled.
|
||||
#
|
||||
def self.turn_on
|
||||
ENV["GUARD_NOTIFY"] = 'true'
|
||||
case RbConfig::CONFIG['target_os']
|
||||
when /darwin/i
|
||||
require_growl
|
||||
when /linux/i
|
||||
require_libnotify
|
||||
when /mswin|mingw/i
|
||||
require_rbnotifu
|
||||
end
|
||||
end
|
||||
|
||||
# Show a message with the system notification.
|
||||
#
|
||||
# @see .image_path
|
||||
#
|
||||
# @param [String] the message to show
|
||||
# @param [Hash] options the notification options
|
||||
# @option options [Symbol, String] image the image symbol or path to an image
|
||||
# @option options [String] title the notification title
|
||||
#
|
||||
def self.notify(message, options = {})
|
||||
if enabled?
|
||||
image = options.delete(:image) || :success
|
||||
title = options.delete(:title) || "Guard"
|
||||
|
||||
# Turn notifications on. This tries to load the platform
|
||||
# specific notification library.
|
||||
#
|
||||
# @return [Boolean] whether the notification could be enabled.
|
||||
#
|
||||
def turn_on
|
||||
ENV["GUARD_NOTIFY"] = 'true'
|
||||
case RbConfig::CONFIG['target_os']
|
||||
when /darwin/i
|
||||
require_growl
|
||||
when /linux/i
|
||||
require_libnotify
|
||||
when /mswin|mingw/i
|
||||
require_rbnotifu
|
||||
when /darwin/i
|
||||
notify_mac(title, message, image, options)
|
||||
when /linux/i
|
||||
notify_linux(title, message, image, options)
|
||||
when /mswin|mingw/i
|
||||
notify_windows(title, message, image, options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Show a message with the system notification.
|
||||
#
|
||||
# @see .image_path
|
||||
#
|
||||
# @param [String] the message to show
|
||||
# @option options [Symbol, String] image the image symbol or path to an image
|
||||
# @option options [String] title the notification title
|
||||
#
|
||||
def notify(message, options = { })
|
||||
if enabled?
|
||||
image = options.delete(:image) || :success
|
||||
title = options.delete(:title) || "Guard"
|
||||
# Test if the notifications are enabled and available.
|
||||
#
|
||||
# @return [Boolean] whether the notifications are available
|
||||
#
|
||||
def self.enabled?
|
||||
ENV["GUARD_NOTIFY"] == 'true'
|
||||
end
|
||||
|
||||
case RbConfig::CONFIG['target_os']
|
||||
when /darwin/i
|
||||
notify_mac(title, message, image, options)
|
||||
when /linux/i
|
||||
notify_linux(title, message, image, options)
|
||||
when /mswin|mingw/i
|
||||
notify_windows(title, message, image, options)
|
||||
end
|
||||
end
|
||||
private
|
||||
|
||||
# Send a message to Growl either with the `growl` gem or the `growl_notify` gem.
|
||||
#
|
||||
# @param [String] title the notification title
|
||||
# @param [String] message the message to show
|
||||
# @param [Symbol, String] the image to user
|
||||
# @param [Hash] options the growl options
|
||||
#
|
||||
def self.notify_mac(title, message, image, options)
|
||||
require_growl # need for guard-rspec formatter that is called out of guard scope
|
||||
|
||||
default_options = { :title => title, :icon => image_path(image), :name => APPLICATION_NAME }
|
||||
default_options.merge!(options)
|
||||
|
||||
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
|
||||
|
||||
# Test if the notifications are enabled and available.
|
||||
#
|
||||
# @return [Boolean] whether the notifications are available
|
||||
#
|
||||
def enabled?
|
||||
ENV["GUARD_NOTIFY"] == 'true'
|
||||
# Send a message to libnotify.
|
||||
#
|
||||
# @param [String] title the notification title
|
||||
# @param [String] message the message to show
|
||||
# @param [Symbol, String] the image to user
|
||||
# @param [Hash] options the libnotify options
|
||||
#
|
||||
def self.notify_linux(title, message, image, options)
|
||||
require_libnotify # need for guard-rspec formatter that is called out of guard scope
|
||||
default_options = { :body => message, :summary => title, :icon_path => image_path(image), :transient => true }
|
||||
Libnotify.show default_options.merge(options) if enabled?
|
||||
end
|
||||
|
||||
# Send a message to notifu.
|
||||
#
|
||||
# @param [String] title the notification title
|
||||
# @param [String] message the message to show
|
||||
# @param [Symbol, String] the image to user
|
||||
# @param [Hash] options the notifu options
|
||||
#
|
||||
def self.notify_windows(title, message, image, options)
|
||||
require_rbnotifu # need for guard-rspec formatter that is called out of guard scope
|
||||
default_options = { :message => message, :title => title, :type => image_level(image), :time => 3 }
|
||||
Notifu.show default_options.merge(options) if enabled?
|
||||
end
|
||||
|
||||
# Get the image path for an image symbol.
|
||||
#
|
||||
# Known symbols are:
|
||||
#
|
||||
# - failed
|
||||
# - pending
|
||||
# - success
|
||||
#
|
||||
# @param [Symbol] image the image name
|
||||
# @return [String] the image path
|
||||
#
|
||||
def self.image_path(image)
|
||||
images_path = Pathname.new(File.dirname(__FILE__)).join('../../images')
|
||||
case image
|
||||
when :failed
|
||||
images_path.join("failed.png").to_s
|
||||
when :pending
|
||||
images_path.join("pending.png").to_s
|
||||
when :success
|
||||
images_path.join("success.png").to_s
|
||||
else
|
||||
# path given
|
||||
image
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Send a message to Growl either with the `growl` gem or the `growl_notify` gem.
|
||||
#
|
||||
# @param [String] title the notification title
|
||||
# @param [String] message the message to show
|
||||
# @param [Symbol, String] the image to user
|
||||
# @param [Hash] options the growl options
|
||||
#
|
||||
def notify_mac(title, message, image, options = { })
|
||||
require_growl # need for guard-rspec formatter that is called out of guard scope
|
||||
|
||||
notification = { :title => title, :icon => image_path(image) }.merge(options)
|
||||
|
||||
case self.growl_library
|
||||
when :growl_notify
|
||||
notification.delete(:name)
|
||||
|
||||
GrowlNotify.send_notification({
|
||||
:description => message,
|
||||
:application_name => APPLICATION_NAME
|
||||
}.merge(notification))
|
||||
|
||||
when :ruby_gntp
|
||||
icon = "file://#{ notification.delete(:icon) }"
|
||||
|
||||
self.gntp.notify({
|
||||
:name => [:pending, :success, :failed].include?(image) ? image.to_s : 'notify',
|
||||
:text => message,
|
||||
:icon => icon
|
||||
}.merge(notification))
|
||||
|
||||
when :growl
|
||||
Growl.notify(message, {
|
||||
:name => APPLICATION_NAME
|
||||
}.merge(notification))
|
||||
end
|
||||
# The notification level type for the given image.
|
||||
#
|
||||
# @param [Symbol] image the image
|
||||
# @return [Symbol] the level
|
||||
#
|
||||
def self.image_level(image)
|
||||
case image
|
||||
when :failed
|
||||
:error
|
||||
when :pending
|
||||
:warn
|
||||
when :success
|
||||
:info
|
||||
else
|
||||
:info
|
||||
end
|
||||
end
|
||||
|
||||
# Send a message to libnotify.
|
||||
#
|
||||
# @param [String] title the notification title
|
||||
# @param [String] message the message to show
|
||||
# @param [Symbol, String] the image to user
|
||||
# @param [Hash] options the libnotify options
|
||||
#
|
||||
def notify_linux(title, message, image, options = { })
|
||||
require_libnotify # need for guard-rspec formatter that is called out of guard scope
|
||||
|
||||
notification = { :body => message, :summary => title, :icon_path => image_path(image), :transient => true }
|
||||
Libnotify.show notification.merge(options)
|
||||
end
|
||||
|
||||
# Send a message to notifu.
|
||||
#
|
||||
# @param [String] title the notification title
|
||||
# @param [String] message the message to show
|
||||
# @param [Symbol, String] the image to user
|
||||
# @param [Hash] options the notifu options
|
||||
#
|
||||
def notify_windows(title, message, image, options = { })
|
||||
require_rbnotifu # need for guard-rspec formatter that is called out of guard scope
|
||||
|
||||
notification = { :message => message, :title => title, :type => image_level(image), :time => 3 }
|
||||
Notifu.show notification.merge(options)
|
||||
end
|
||||
|
||||
# Get the image path for an image symbol.
|
||||
#
|
||||
# Known symbols are:
|
||||
#
|
||||
# - failed
|
||||
# - pending
|
||||
# - success
|
||||
#
|
||||
# @param [Symbol] image the image name
|
||||
# @return [String] the image path
|
||||
#
|
||||
def image_path(image)
|
||||
images_path = Pathname.new(File.dirname(__FILE__)).join('../../images')
|
||||
case image
|
||||
when :failed
|
||||
images_path.join("failed.png").to_s
|
||||
when :pending
|
||||
images_path.join("pending.png").to_s
|
||||
when :success
|
||||
images_path.join("success.png").to_s
|
||||
else
|
||||
# path given
|
||||
image
|
||||
end
|
||||
end
|
||||
|
||||
# The notification level type for the given image.
|
||||
#
|
||||
# @param [Symbol] image the image
|
||||
# @return [Symbol] the level
|
||||
#
|
||||
def image_level(image)
|
||||
case image
|
||||
when :failed
|
||||
:error
|
||||
when :pending
|
||||
:warn
|
||||
when :success
|
||||
:info
|
||||
else
|
||||
:info
|
||||
end
|
||||
end
|
||||
|
||||
# Try to safely load growl and turns notifications off on load failure.
|
||||
# The Guard notifier knows three different library to handle sending
|
||||
# Growl messages and tries to loading them in the given order:
|
||||
#
|
||||
# - [Growl Notify](https://github.com/scottdavis/growl_notify)
|
||||
# - [Ruby GNTP](https://github.com/snaka/ruby_gntp)
|
||||
# - [Growl](https://github.com/visionmedia/growl)
|
||||
#
|
||||
# On successful loading of any of the libraries, the active library name is
|
||||
# accessible through `.growl_library`.
|
||||
#
|
||||
def require_growl
|
||||
self.growl_library = try_growl_notify || try_ruby_gntp || try_growl
|
||||
|
||||
unless self.growl_library
|
||||
turn_off
|
||||
UI.info "Please install growl_notify or growl gem for Mac OS X notification support and add it to your Gemfile"
|
||||
end
|
||||
end
|
||||
|
||||
# Try to load the `growl_notify` gem.
|
||||
#
|
||||
# @return [Symbol, nil] A symbol with the name of the loaded library
|
||||
#
|
||||
def try_growl_notify
|
||||
# Try to safely load growl and turns notifications
|
||||
# off on load failure.
|
||||
#
|
||||
def self.require_growl
|
||||
begin
|
||||
require 'growl_notify'
|
||||
|
||||
begin
|
||||
if GrowlNotify.application_name != APPLICATION_NAME
|
||||
GrowlNotify.config do |c|
|
||||
c.notifications = c.default_notifications = [APPLICATION_NAME]
|
||||
c.application_name = c.notifications.first
|
||||
end
|
||||
if GrowlNotify.application_name != APPLICATION_NAME
|
||||
GrowlNotify.config do |c|
|
||||
c.notifications = c.default_notifications = [ APPLICATION_NAME ]
|
||||
c.application_name = c.notifications.first
|
||||
end
|
||||
|
||||
rescue ::GrowlNotify::GrowlNotFound
|
||||
turn_off
|
||||
UI.info "Please install Growl from http://growl.info"
|
||||
end
|
||||
|
||||
:growl_notify
|
||||
|
||||
rescue LoadError
|
||||
end
|
||||
|
||||
# Try to load the `ruby_gntp` gem and register the available
|
||||
# notification channels.
|
||||
#
|
||||
# @return [Symbol, nil] A symbol with the name of the loaded library
|
||||
#
|
||||
def try_ruby_gntp
|
||||
require 'ruby_gntp'
|
||||
|
||||
self.gntp = GNTP.new(APPLICATION_NAME)
|
||||
self.gntp.register(:notifications => [
|
||||
{ :name => 'notify', :enabled => true },
|
||||
{ :name => 'failed', :enabled => true },
|
||||
{ :name => 'pending', :enabled => true },
|
||||
{ :name => 'success', :enabled => true }
|
||||
])
|
||||
|
||||
:ruby_gntp
|
||||
|
||||
rescue LoadError
|
||||
end
|
||||
|
||||
# Try to load the `growl_notify` gem.
|
||||
#
|
||||
# @return [Symbol, nil] A symbol with the name of the loaded library
|
||||
#
|
||||
def try_growl
|
||||
require 'growl'
|
||||
|
||||
:growl
|
||||
|
||||
rescue LoadError
|
||||
end
|
||||
|
||||
# Try to safely load libnotify and turns notifications
|
||||
# off on load failure.
|
||||
#
|
||||
def require_libnotify
|
||||
require 'libnotify'
|
||||
|
||||
rescue LoadError
|
||||
turn_off
|
||||
UI.info "Please install libnotify gem for Linux notification support and add it to your Gemfile"
|
||||
end
|
||||
|
||||
# Try to safely load rb-notifu and turns notifications
|
||||
# off on load failure.
|
||||
#
|
||||
def require_rbnotifu
|
||||
require 'rb-notifu'
|
||||
|
||||
rescue LoadError
|
||||
turn_off
|
||||
UI.info "Please install rb-notifu gem for Windows notification support and add it to your Gemfile"
|
||||
end
|
||||
|
||||
rescue LoadError
|
||||
turn_off
|
||||
UI.info "Please install growl_notify or growl gem for Mac OS X notification support and add it to your Gemfile"
|
||||
end
|
||||
|
||||
# Try to safely load libnotify and turns notifications
|
||||
# off on load failure.
|
||||
#
|
||||
def self.require_libnotify
|
||||
require 'libnotify'
|
||||
rescue LoadError
|
||||
turn_off
|
||||
UI.info "Please install libnotify gem for Linux notification support and add it to your Gemfile"
|
||||
end
|
||||
|
||||
# Try to safely load rb-notifu and turns notifications
|
||||
# off on load failure.
|
||||
#
|
||||
def self.require_rbnotifu
|
||||
require 'rb-notifu'
|
||||
rescue LoadError
|
||||
turn_off
|
||||
UI.info "Please install rb-notifu gem for Windows notification support and add it to your Gemfile"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -1,11 +1,6 @@
|
||||
module Guard
|
||||
|
||||
# The UI class helps to format messages for the user. Everything that is logged
|
||||
# through this class is considered either as an error message or a diagnostic
|
||||
# message and is written to standard error (STDERR).
|
||||
#
|
||||
# If your Guard does some output that is piped into another process for further
|
||||
# processing, please just write it to STDOUT with `puts`.
|
||||
# The UI class helps to format messages for the user.
|
||||
#
|
||||
module UI
|
||||
class << self
|
||||
@ -15,55 +10,59 @@ module Guard
|
||||
# Show an info message.
|
||||
#
|
||||
# @param [String] message the message to show
|
||||
# @param [Hash] options the options
|
||||
# @option options [Boolean] reset whether to clean the output before
|
||||
#
|
||||
def info(message, options = { })
|
||||
unless ENV['GUARD_ENV'] == 'test'
|
||||
reset_line if options[:reset]
|
||||
STDERR.puts color(message) if message != ''
|
||||
puts color(message) if message != ''
|
||||
end
|
||||
end
|
||||
|
||||
# Show a red error message that is prefixed with ERROR.
|
||||
#
|
||||
# @param [String] message the message to show
|
||||
# @param [Hash] options the options
|
||||
# @option options [Boolean] reset whether to clean the output before
|
||||
#
|
||||
def error(message, options = { })
|
||||
unless ENV['GUARD_ENV'] == 'test'
|
||||
reset_line if options[:reset]
|
||||
STDERR.puts color('ERROR: ', :red) + message
|
||||
puts color('ERROR: ', :red) + message
|
||||
end
|
||||
end
|
||||
|
||||
# Show a red deprecation message that is prefixed with DEPRECATION.
|
||||
#
|
||||
# @param [String] message the message to show
|
||||
# @param [Hash] options the options
|
||||
# @option options [Boolean] reset whether to clean the output before
|
||||
#
|
||||
def deprecation(message, options = { })
|
||||
unless ENV['GUARD_ENV'] == 'test'
|
||||
reset_line if options[:reset]
|
||||
STDERR.puts color('DEPRECATION: ', :red) + message
|
||||
puts color('DEPRECATION: ', :red) + message
|
||||
end
|
||||
end
|
||||
|
||||
# Show a debug message that is prefixed with DEBUG and a timestamp.
|
||||
#
|
||||
# @param [String] message the message to show
|
||||
# @param [Hash] options the options
|
||||
# @option options [Boolean] reset whether to clean the output before
|
||||
#
|
||||
def debug(message, options = { })
|
||||
unless ENV['GUARD_ENV'] == 'test'
|
||||
reset_line if options[:reset]
|
||||
STDERR.puts color("DEBUG (#{Time.now.strftime('%T')}): ", :yellow) + message if ::Guard.options && ::Guard.options[:debug]
|
||||
puts color("DEBUG (#{Time.now.strftime('%T')}): ", :yellow) + message if ::Guard.options && ::Guard.options[:debug]
|
||||
end
|
||||
end
|
||||
|
||||
# Reset a line.
|
||||
#
|
||||
def reset_line
|
||||
STDERR.print(color_enabled? ? "\r\e[0m" : "\r\n")
|
||||
print(color_enabled? ? "\r\e[0m" : "\r\n")
|
||||
end
|
||||
|
||||
# Clear the output.
|
||||
|
@ -1,6 +1,6 @@
|
||||
module Guard
|
||||
unless defined? Guard::VERSION
|
||||
# The current gem version of Guard
|
||||
VERSION = '0.8.4'
|
||||
VERSION = '0.7.0'
|
||||
end
|
||||
end
|
||||
|
@ -38,7 +38,7 @@ module Guard
|
||||
#
|
||||
# @param [Guard::Guard] guard the guard which watchers are used
|
||||
# @param [Array<String>] files the changed files
|
||||
# @return [Array<Object>] the matched watcher response
|
||||
# @return [Array<String>] the matched files
|
||||
#
|
||||
def self.match_files(guard, files)
|
||||
guard.watchers.inject([]) do |paths, watcher|
|
||||
@ -46,18 +46,14 @@ module Guard
|
||||
if matches = watcher.match_file?(file)
|
||||
if watcher.action
|
||||
result = watcher.call_action(matches)
|
||||
if guard.options[:any_return]
|
||||
paths << result
|
||||
elsif result.respond_to?(:empty?) && !result.empty?
|
||||
paths << Array(result)
|
||||
end
|
||||
paths << Array(result) if result.respond_to?(:empty?) && !result.empty?
|
||||
else
|
||||
paths << matches[0]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
guard.options[:any_return] ? paths : paths.flatten.map { |p| p.to_s }
|
||||
|
||||
paths.flatten.map { |p| p.to_s }
|
||||
end
|
||||
end
|
||||
|
||||
|
502
man/guard.html
Normal file
502
man/guard.html
Normal file
@ -0,0 +1,502 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv='content-type' value='text/html;charset=utf8'>
|
||||
<meta name='generator' value='Ronn/v0.7.3 (http://github.com/rtomayko/ronn/tree/0.7.3)'>
|
||||
<title>guard</title>
|
||||
<style type='text/css' media='all'>
|
||||
/* style: man */
|
||||
body#manpage {margin:0}
|
||||
.mp {max-width:100ex;padding:0 9ex 1ex 4ex}
|
||||
.mp p,.mp pre,.mp ul,.mp ol,.mp dl {margin:0 0 20px 0}
|
||||
.mp h2 {margin:10px 0 0 0}
|
||||
.mp > p,.mp > pre,.mp > ul,.mp > ol,.mp > dl {margin-left:8ex}
|
||||
.mp h3 {margin:0 0 0 4ex}
|
||||
.mp dt {margin:0;clear:left}
|
||||
.mp dt.flush {float:left;width:8ex}
|
||||
.mp dd {margin:0 0 0 9ex}
|
||||
.mp h1,.mp h2,.mp h3,.mp h4 {clear:left}
|
||||
.mp pre {margin-bottom:20px}
|
||||
.mp pre+h2,.mp pre+h3 {margin-top:22px}
|
||||
.mp h2+pre,.mp h3+pre {margin-top:5px}
|
||||
.mp img {display:block;margin:auto}
|
||||
.mp h1.man-title {display:none}
|
||||
.mp,.mp code,.mp pre,.mp tt,.mp kbd,.mp samp,.mp h3,.mp h4 {font-family:monospace;font-size:14px;line-height:1.42857142857143}
|
||||
.mp h2 {font-size:16px;line-height:1.25}
|
||||
.mp h1 {font-size:20px;line-height:2}
|
||||
.mp {text-align:justify;background:#fff}
|
||||
.mp,.mp code,.mp pre,.mp pre code,.mp tt,.mp kbd,.mp samp {color:#131211}
|
||||
.mp h1,.mp h2,.mp h3,.mp h4 {color:#030201}
|
||||
.mp u {text-decoration:underline}
|
||||
.mp code,.mp strong,.mp b {font-weight:bold;color:#131211}
|
||||
.mp em,.mp var {font-style:italic;color:#232221;text-decoration:none}
|
||||
.mp a,.mp a:link,.mp a:hover,.mp a code,.mp a pre,.mp a tt,.mp a kbd,.mp a samp {color:#0000ff}
|
||||
.mp b.man-ref {font-weight:normal;color:#434241}
|
||||
.mp pre {padding:0 4ex}
|
||||
.mp pre code {font-weight:normal;color:#434241}
|
||||
.mp h2+pre,h3+pre {padding-left:0}
|
||||
ol.man-decor,ol.man-decor li {margin:3px 0 10px 0;padding:0;float:left;width:33%;list-style-type:none;text-transform:uppercase;color:#999;letter-spacing:1px}
|
||||
ol.man-decor {width:100%}
|
||||
ol.man-decor li.tl {text-align:left}
|
||||
ol.man-decor li.tc {text-align:center;letter-spacing:4px}
|
||||
ol.man-decor li.tr {text-align:right;float:right}
|
||||
</style>
|
||||
</head>
|
||||
<!--
|
||||
The following styles are deprecated and will be removed at some point:
|
||||
div#man, div#man ol.man, div#man ol.head, div#man ol.man.
|
||||
|
||||
The .man-page, .man-decor, .man-head, .man-foot, .man-title, and
|
||||
.man-navigation should be used instead.
|
||||
-->
|
||||
<body id='manpage'>
|
||||
<div class='mp' id='man'>
|
||||
|
||||
<div class='man-navigation' style='display:none'>
|
||||
<a href="#NAME">NAME</a>
|
||||
<a href="#NAME">NAME</a>
|
||||
<a href="#NAME">NAME</a>
|
||||
</div>
|
||||
|
||||
<ol class='man-decor man-head man head'>
|
||||
<li class='tl'>guard</li>
|
||||
<li class='tc'></li>
|
||||
<li class='tr'>guard</li>
|
||||
</ol>
|
||||
|
||||
<h2 id="NAME">NAME</h2>
|
||||
<p class="man-name">
|
||||
<code>guard</code>
|
||||
</p>
|
||||
<p><var>!DOCTYPE html</var>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" value="text/html;charset=utf8" />
|
||||
<meta name="generator" value="Ronn/v0.7.3 (http://github.com/rtomayko/ronn/tree/0.7.3)" />
|
||||
<title>guard</title>
|
||||
<style type="text/css" media="all">
|
||||
/<em> style: man </em>/
|
||||
body#manpage {margin:0}
|
||||
.mp {max-width:100ex;padding:0 9ex 1ex 4ex}
|
||||
.mp p,.mp pre,.mp ul,.mp ol,.mp dl {margin:0 0 20px 0}
|
||||
.mp h2 {margin:10px 0 0 0}
|
||||
.mp > p,.mp > pre,.mp > ul,.mp > ol,.mp > dl {margin-left:8ex}
|
||||
.mp h3 {margin:0 0 0 4ex}
|
||||
.mp dt {margin:0;clear:left}
|
||||
.mp dt.flush {float:left;width:8ex}
|
||||
.mp dd {margin:0 0 0 9ex}
|
||||
.mp h1,.mp h2,.mp h3,.mp h4 {clear:left}
|
||||
.mp pre {margin-bottom:20px}
|
||||
.mp pre+h2,.mp pre+h3 {margin-top:22px}
|
||||
.mp h2+pre,.mp h3+pre {margin-top:5px}
|
||||
.mp img {display:block;margin:auto}
|
||||
.mp h1.man-title {display:none}
|
||||
.mp,.mp code,.mp pre,.mp tt,.mp kbd,.mp samp,.mp h3,.mp h4 {font-family:monospace;font-size:14px;line-height:1.42857142857143}
|
||||
.mp h2 {font-size:16px;line-height:1.25}
|
||||
.mp h1 {font-size:20px;line-height:2}
|
||||
.mp {text-align:justify;background:#fff}
|
||||
.mp,.mp code,.mp pre,.mp pre code,.mp tt,.mp kbd,.mp samp {color:#131211}
|
||||
.mp h1,.mp h2,.mp h3,.mp h4 {color:#030201}
|
||||
.mp u {text-decoration:underline}
|
||||
.mp code,.mp strong,.mp b {font-weight:bold;color:#131211}
|
||||
.mp em,.mp var {font-style:italic;color:#232221;text-decoration:none}
|
||||
.mp a,.mp a:link,.mp a:hover,.mp a code,.mp a pre,.mp a tt,.mp a kbd,.mp a samp {color:#0000ff}
|
||||
.mp b.man-ref {font-weight:normal;color:#434241}
|
||||
.mp pre {padding:0 4ex}
|
||||
.mp pre code {font-weight:normal;color:#434241}
|
||||
.mp h2+pre,h3+pre {padding-left:0}
|
||||
ol.man-decor,ol.man-decor li {margin:3px 0 10px 0;padding:0;float:left;width:33%;list-style-type:none;text-transform:uppercase;color:#999;letter-spacing:1px}
|
||||
ol.man-decor {width:100%}
|
||||
ol.man-decor li.tl {text-align:left}
|
||||
ol.man-decor li.tc {text-align:center;letter-spacing:4px}
|
||||
ol.man-decor li.tr {text-align:right;float:right}
|
||||
</style>
|
||||
</head></html></p>
|
||||
|
||||
<!--
|
||||
The following styles are deprecated and will be removed at some point:
|
||||
div#man, div#man ol.man, div#man ol.head, div#man ol.man.
|
||||
|
||||
The .man-page, .man-decor, .man-head, .man-foot, .man-title, and
|
||||
.man-navigation should be used instead.
|
||||
-->
|
||||
|
||||
|
||||
<p><body id="manpage">
|
||||
<div class="mp" id="man" /></body></p>
|
||||
|
||||
<p> <div class="man-navigation" style="display:none" /></p>
|
||||
|
||||
<pre><code><a href="#NAME">NAME</a>
|
||||
<a href="#NAME">NAME</a>
|
||||
</code></pre>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p> <ol class="man-decor man-head man head" /></p>
|
||||
|
||||
<pre><code><li class='tl'>guard</li>
|
||||
<li class='tc'></li>
|
||||
<li class='tr'>guard</li>
|
||||
</code></pre>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p> <h2 id="NAME">NAME</h2></p>
|
||||
|
||||
<p class="man-name">
|
||||
<code>guard</code>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p><p<var>!DOCTYPE html</var>
|
||||
<html>
|
||||
<head>
|
||||
<meta value="text/html;charset=utf8" http-equiv="content-type" />
|
||||
<meta name="generator" value="Ronn/v0.7.3 (http://github.com/rtomayko/ronn/tree/0.7.3)" />
|
||||
<title>guard</title>
|
||||
<style media="all" type="text/css">
|
||||
/<em> style: man </em>/
|
||||
body#manpage {margin:0}
|
||||
.mp {max-width:100ex;padding:0 9ex 1ex 4ex}
|
||||
.mp p,.mp pre,.mp ul,.mp ol,.mp dl {margin:0 0 20px 0}
|
||||
.mp h2 {margin:10px 0 0 0}
|
||||
.mp > p,.mp > pre,.mp > ul,.mp > ol,.mp > dl {margin-left:8ex}
|
||||
.mp h3 {margin:0 0 0 4ex}
|
||||
.mp dt {margin:0;clear:left}
|
||||
.mp dt.flush {float:left;width:8ex}
|
||||
.mp dd {margin:0 0 0 9ex}
|
||||
.mp h1,.mp h2,.mp h3,.mp h4 {clear:left}
|
||||
.mp pre {margin-bottom:20px}
|
||||
.mp pre+h2,.mp pre+h3 {margin-top:22px}
|
||||
.mp h2+pre,.mp h3+pre {margin-top:5px}
|
||||
.mp img {display:block;margin:auto}
|
||||
.mp h1.man-title {display:none}
|
||||
.mp,.mp code,.mp pre,.mp tt,.mp kbd,.mp samp,.mp h3,.mp h4 {font-family:monospace;font-size:14px;line-height:1.42857142857143}
|
||||
.mp h2 {font-size:16px;line-height:1.25}
|
||||
.mp h1 {font-size:20px;line-height:2}
|
||||
.mp {text-align:justify;background:#fff}
|
||||
.mp,.mp code,.mp pre,.mp pre code,.mp tt,.mp kbd,.mp samp {color:#131211}
|
||||
.mp h1,.mp h2,.mp h3,.mp h4 {color:#030201}
|
||||
.mp u {text-decoration:underline}
|
||||
.mp code,.mp strong,.mp b {font-weight:bold;color:#131211}
|
||||
.mp em,.mp var {font-style:italic;color:#232221;text-decoration:none}
|
||||
.mp a,.mp a:link,.mp a:hover,.mp a code,.mp a pre,.mp a tt,.mp a kbd,.mp a samp {color:#0000ff}
|
||||
.mp b.man-ref {font-weight:normal;color:#434241}
|
||||
.mp pre {padding:0 4ex}
|
||||
.mp pre code {font-weight:normal;color:#434241}
|
||||
.mp h2+pre,h3+pre {padding-left:0}
|
||||
ol.man-decor,ol.man-decor li {margin:3px 0 10px 0;padding:0;float:left;width:33%;list-style-type:none;text-transform:uppercase;color:#999;letter-spacing:1px}
|
||||
ol.man-decor {width:100%}
|
||||
ol.man-decor li.tl {text-align:left}
|
||||
ol.man-decor li.tc {text-align:center;letter-spacing:4px}
|
||||
ol.man-decor li.tr {text-align:right;float:right}
|
||||
</style>
|
||||
</head></html></p>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
The following styles are deprecated and will be removed at some point:
|
||||
div#man, div#man ol.man, div#man ol.head, div#man ol.man.
|
||||
|
||||
The .man-page, .man-decor, .man-head, .man-foot, .man-title, and
|
||||
.man-navigation should be used instead.
|
||||
-->
|
||||
|
||||
|
||||
|
||||
|
||||
<p><body id="manpage">
|
||||
<div class="mp" id="man" /></body></p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p> <div class="man-navigation" style="display:none" /></p>
|
||||
|
||||
|
||||
|
||||
|
||||
<pre><code><a href="#NAME">NAME</a>
|
||||
</code></pre>
|
||||
|
||||
|
||||
|
||||
|
||||
<p> </p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p> <ol class="man-decor man-head man head" /></p>
|
||||
|
||||
|
||||
|
||||
|
||||
<pre><code><li class='tl'>guard</li>
|
||||
<li class='tc'></li>
|
||||
<li class='tr'>guard</li>
|
||||
</code></pre>
|
||||
|
||||
|
||||
|
||||
|
||||
<p> </p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p> <h2 id="NAME">NAME</h2></p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p class="man-name">
|
||||
<code>guard</code>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<blockquote><blockquote><blockquote><blockquote><blockquote><blockquote><blockquote><p>master</p></blockquote></blockquote></blockquote></blockquote></blockquote></blockquote></blockquote>
|
||||
|
||||
|
||||
|
||||
|
||||
<p>.\" generated with Ronn/v0.7.3
|
||||
.\" http://github.com/rtomayko/ronn/tree/0.7.3
|
||||
.
|
||||
.TH "GUARD" "1" "August 2011" "" ""
|
||||
.
|
||||
.SH "NAME"
|
||||
\fBguard\fR - Guard keeps an eye on your file modifications.
|
||||
.
|
||||
.SH "DESCRIPTION"
|
||||
Guard is a command line tool that easily handle events on files modifications.
|
||||
.
|
||||
.SH "SYNOPSIS"
|
||||
\fBguard <var>COMMAND</var> <var>OPTIONS</var>\fR
|
||||
.
|
||||
.SH "COMMANDS"
|
||||
.
|
||||
.SS "start"
|
||||
Starts Guard. This is the default command if none is provided.
|
||||
.
|
||||
.P
|
||||
The following options are available:
|
||||
.
|
||||
.P
|
||||
\fB-c\fR, \fB--clear\fR Clears the Shell after each change.
|
||||
.
|
||||
.P
|
||||
\fB-n\fR, \fB--notify\fR \fIFLAG\fR Disable notifications (Growl or Libnotify depending on your system). Notifications can be disabled globally by setting a GUARD_NOTIFY environment variable to false. FLAG can be \fBtrue\fR/\fBfalse\fR or \fBt\fR/\fBf\fR.
|
||||
.
|
||||
.P
|
||||
\fB-d\fR, \fB--debug\fR Runs Guard in debug mode.
|
||||
.
|
||||
.P
|
||||
\fB-g\fR, \fB--group\fR \fIGROUP1\fR \fIGROUP2\fR... Runs only the groups specified by GROUP1, GROUP2 etc. Groups name should be separated by spaces. Guards that don\'t belong to a group are considered global and are always run.
|
||||
.
|
||||
.P
|
||||
\fB-w\fR, \fB--watchdir\fR \fIPATH\fR
|
||||
.
|
||||
.P
|
||||
Tells Guard to watch PATH instead of \fB./\fR.
|
||||
.
|
||||
.P
|
||||
\fB-G\fR, \fB--guardfile\fR \fIFILE\fR Tells Guard to use FILE as its Guardfile instead of \fB./Guardfile\fR or \fB~/.Guardfile\fR.
|
||||
.
|
||||
.SS "init [GUARD]"
|
||||
If no Guardfile is present in the current directory, creates an empty Guardfile.
|
||||
.
|
||||
.P
|
||||
If \fIGUARD\fR is present, add its default Guardfile configuration to the current Guardfile. Note that \fIGUARD\fR is the guard\'s name without the \fBguard-\fR prefix. For instance to initialize guard-rspec, run \fBguard init rspec\fR.
|
||||
.
|
||||
.SS "list"
|
||||
Lists guards that can be used with the \fBinit\fR command.
|
||||
.
|
||||
.SS "-T, show"
|
||||
List defined groups and guards for the current Guardfile.
|
||||
.
|
||||
.SS "-h, help [COMMAND]"
|
||||
List all of Guard\'s available commands.
|
||||
.
|
||||
.P
|
||||
If \fICOMMAND\fR is given, displays a specific help for \fITASK\fR.
|
||||
.
|
||||
.SH "EXAMPLES"
|
||||
Initialize Guard and a specific guard at the same time:
|
||||
.
|
||||
.P
|
||||
\fB[bundle exec] guard init [rspec]\fR
|
||||
.
|
||||
.P
|
||||
Run Guard:
|
||||
.
|
||||
.P
|
||||
\fB[bundle exec] guard [start] --watchdir ~/dev --guardfile ~/env/Guardfile --clear --group backend frontend --notify false --debug\fR
|
||||
.
|
||||
.P
|
||||
or in a more concise way:
|
||||
.
|
||||
.P
|
||||
\fB[bundle exec] guard [start] -w ~/dev -G ~/env/Guardfile -c -g backend frontend -n f -d\fR
|
||||
.
|
||||
.SH "AUTHORS / CONTRIBUTORS"
|
||||
Thibaud Guillaume-Gentil is the main author.
|
||||
.
|
||||
.P
|
||||
A list of contributors based on all commits can be found here: https://github.com/guard/guard/contributors
|
||||
.
|
||||
.P
|
||||
For an exhaustive list of all the contributors, please see the CHANGELOG: https://github.com/guard/guard/blob/master/CHANGELOG.md
|
||||
.
|
||||
.P
|
||||
This manual has been written by Remy Coutable.
|
||||
.
|
||||
.SH "WWW"
|
||||
https://github.com/guard/guard</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p> <ol class="man-decor man-foot man foot" /></p>
|
||||
|
||||
|
||||
|
||||
|
||||
<pre><code><li class='tl'></li>
|
||||
<li class='tc'>September 2011</li>
|
||||
<li class='tr'>guard</li>
|
||||
</code></pre>
|
||||
|
||||
|
||||
|
||||
|
||||
<p> </p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p><var><<<<<< HEAD</var></p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p><p <ol class="man-decor man-foot man foot" /></p>
|
||||
|
||||
|
||||
|
||||
|
||||
<pre><code><li class='tl'></li>
|
||||
<li class='tc'>September 2011</li>
|
||||
<li class='tr'>guard</li>
|
||||
</code></pre>
|
||||
|
||||
|
||||
|
||||
|
||||
<p> </p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p>=======</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<blockquote><blockquote><blockquote><blockquote><blockquote><blockquote><blockquote><p>master</p></blockquote></blockquote></blockquote></blockquote></blockquote></blockquote></blockquote>
|
||||
|
||||
|
||||
|
||||
|
||||
<p> <ol class="man-decor man-foot man foot" /></p>
|
||||
|
||||
|
||||
|
||||
|
||||
<pre><code><li class='tl'></li>
|
||||
<li class='tc'>September 2011</li>
|
||||
<li class='tr'>guard</li>
|
||||
</code></pre>
|
||||
|
||||
|
||||
|
||||
|
||||
<p> </p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p> <ol class="man-decor man-foot man foot" /></p>
|
||||
|
||||
|
||||
|
||||
|
||||
<pre><code><li class='tl'></li>
|
||||
<li class='tc'>September 2011</li>
|
||||
<li class='tr'>guard</li>
|
||||
</code></pre>
|
||||
|
||||
|
||||
|
||||
|
||||
<p> </p>
|
||||
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
<p> <ol class="man-decor man-foot man foot" /></p>
|
||||
|
||||
<pre><code><li class='tl'></li>
|
||||
<li class='tc'>September 2011</li>
|
||||
<li class='tr'>guard</li>
|
||||
</code></pre>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p>
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
<ol class='man-decor man-foot man foot'>
|
||||
<li class='tl'></li>
|
||||
<li class='tc'>September 2011</li>
|
||||
<li class='tr'>guard</li>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
0
spec/fixtures/folder1/file1.txt
vendored
Executable file → Normal file
0
spec/fixtures/folder1/file1.txt
vendored
Executable file → Normal file
@ -1,70 +1,40 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Guard::DslDescriber do
|
||||
|
||||
let(:describer) { ::Guard::DslDescriber }
|
||||
|
||||
let(:guardfile) do
|
||||
<<-GUARD
|
||||
guard 'test', :a => :b do
|
||||
watch('c')
|
||||
end
|
||||
|
||||
group :a do
|
||||
guard 'test', :x => 1 do
|
||||
watch('c')
|
||||
end
|
||||
end
|
||||
|
||||
group "b" do
|
||||
guard 'another' do
|
||||
watch('c')
|
||||
end
|
||||
end
|
||||
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 }
|
||||
|
||||
before do
|
||||
@output = ''
|
||||
Guard::UI.stub(:info) { |msg| @output << msg + "\n" }
|
||||
end
|
||||
|
||||
after do
|
||||
Guard::UI.unstub(:info)
|
||||
end
|
||||
|
||||
describe '.list' do
|
||||
it 'lists the available Guards' do
|
||||
Guard.stub(:guard_gem_names).and_return ['test', 'another', 'even', 'more']
|
||||
describer.list(:guardfile_contents => guardfile)
|
||||
@output.should eql <<OUTPUT
|
||||
Using inline Guardfile.
|
||||
Available guards:
|
||||
another*
|
||||
even
|
||||
more
|
||||
test*
|
||||
|
||||
See also https://github.com/guard/guard/wiki/List-of-available-Guards
|
||||
* denotes ones already in your Guardfile
|
||||
OUTPUT
|
||||
end
|
||||
end
|
||||
|
||||
describe '.show' do
|
||||
it 'shows the Guards and their options' do
|
||||
describer.show(:guardfile_contents => guardfile)
|
||||
@output.should eql <<OUTPUT
|
||||
Using inline Guardfile.
|
||||
(global):
|
||||
test: a => :b
|
||||
Group a:
|
||||
test: x => 1
|
||||
Group b:
|
||||
another
|
||||
|
||||
OUTPUT
|
||||
end
|
||||
end
|
||||
|
||||
it 'should evaluate a Guardfile and create the right structure' do
|
||||
mixed_guardfile_string = <<-GUARD
|
||||
guard 'test', :a => :b do
|
||||
watch('c')
|
||||
end
|
||||
|
||||
group :a do
|
||||
guard 'test' do
|
||||
watch('c')
|
||||
end
|
||||
end
|
||||
|
||||
group "b" do
|
||||
guard 'another' do
|
||||
watch('c')
|
||||
end
|
||||
end
|
||||
GUARD
|
||||
|
||||
subject.evaluate_guardfile(:guardfile_contents => mixed_guardfile_string)
|
||||
|
||||
subject.guardfile_structure.should == [
|
||||
{ :guards => [ { :name => 'test', :options => { :a => :b } } ] },
|
||||
{ :group => :a, :guards => [ { :name => 'test', :options => {} } ] },
|
||||
{ :group => :b, :guards => [ { :name => 'another', :options => {} } ] }
|
||||
]
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -2,7 +2,7 @@ require 'spec_helper'
|
||||
require 'guard/guard'
|
||||
|
||||
describe Guard::Dsl do
|
||||
|
||||
subject { described_class }
|
||||
class Guard::Dummy < Guard::Guard; end
|
||||
|
||||
before(:each) do
|
||||
@ -24,24 +24,24 @@ describe Guard::Dsl do
|
||||
|
||||
it "should use a string for initializing" do
|
||||
Guard::UI.should_not_receive(:error)
|
||||
lambda { described_class.evaluate_guardfile(:guardfile_contents => valid_guardfile_string) }.should_not raise_error
|
||||
described_class.guardfile_contents.should == valid_guardfile_string
|
||||
lambda { subject.evaluate_guardfile(:guardfile_contents => valid_guardfile_string) }.should_not raise_error
|
||||
subject.guardfile_contents.should == valid_guardfile_string
|
||||
end
|
||||
|
||||
it "should use a given file over the default loc" do
|
||||
fake_guardfile('/abc/Guardfile', "guard :foo")
|
||||
|
||||
Guard::UI.should_not_receive(:error)
|
||||
lambda { described_class.evaluate_guardfile(:guardfile => '/abc/Guardfile') }.should_not raise_error
|
||||
described_class.guardfile_contents.should == "guard :foo"
|
||||
lambda { subject.evaluate_guardfile(:guardfile => '/abc/Guardfile') }.should_not raise_error
|
||||
subject.guardfile_contents.should == "guard :foo"
|
||||
end
|
||||
|
||||
it "should use a default file if no other options are given" do
|
||||
fake_guardfile(@local_guardfile_path, "guard :bar")
|
||||
|
||||
Guard::UI.should_not_receive(:error)
|
||||
lambda { described_class.evaluate_guardfile }.should_not raise_error
|
||||
described_class.guardfile_contents.should == "guard :bar"
|
||||
lambda { subject.evaluate_guardfile }.should_not raise_error
|
||||
subject.guardfile_contents.should == "guard :bar"
|
||||
end
|
||||
|
||||
it "should use a string over any other method" do
|
||||
@ -49,8 +49,8 @@ describe Guard::Dsl do
|
||||
fake_guardfile(@local_guardfile_path, "guard :bar")
|
||||
|
||||
Guard::UI.should_not_receive(:error)
|
||||
lambda { described_class.evaluate_guardfile(:guardfile_contents => valid_guardfile_string) }.should_not raise_error
|
||||
described_class.guardfile_contents.should == valid_guardfile_string
|
||||
lambda { subject.evaluate_guardfile(:guardfile_contents => valid_guardfile_string) }.should_not raise_error
|
||||
subject.guardfile_contents.should == valid_guardfile_string
|
||||
end
|
||||
|
||||
it "should use the given Guardfile over default Guardfile" do
|
||||
@ -58,31 +58,31 @@ describe Guard::Dsl do
|
||||
fake_guardfile(@local_guardfile_path, "guard :bar")
|
||||
|
||||
Guard::UI.should_not_receive(:error)
|
||||
lambda { described_class.evaluate_guardfile(:guardfile => '/abc/Guardfile') }.should_not raise_error
|
||||
described_class.guardfile_contents.should == "guard :foo"
|
||||
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 { described_class.evaluate_guardfile(:guardfile => '/abc/Guardfile') }.should_not raise_error
|
||||
described_class.guardfile_contents_with_user_config.should == "guard :foo\nguard :bar"
|
||||
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
|
||||
described_class.stub(:guardfile_default_path).and_return("no_guardfile_here")
|
||||
subject.stub(:guardfile_default_path).and_return("no_guardfile_here")
|
||||
Guard::UI.should_receive(:error).with("No Guardfile found, please create one with `guard init`.")
|
||||
lambda { described_class.evaluate_guardfile }.should raise_error
|
||||
lambda { subject.evaluate_guardfile }.should raise_error
|
||||
end
|
||||
|
||||
it "displays an error message when no guard are defined in Guardfile" do
|
||||
::Guard::Dsl.stub!(:instance_eval_guardfile)
|
||||
::Guard.stub!(:guards).and_return([])
|
||||
Guard::UI.should_receive(:error)
|
||||
described_class.evaluate_guardfile(:guardfile_contents => valid_guardfile_string)
|
||||
subject.evaluate_guardfile(:guardfile_contents => valid_guardfile_string)
|
||||
end
|
||||
|
||||
describe "correctly reads data from its valid data source" do
|
||||
@ -90,22 +90,22 @@ describe Guard::Dsl do
|
||||
disable_user_config
|
||||
|
||||
it "reads correctly from a string" do
|
||||
lambda { described_class.evaluate_guardfile(:guardfile_contents => valid_guardfile_string) }.should_not raise_error
|
||||
described_class.guardfile_contents.should == valid_guardfile_string
|
||||
lambda { subject.evaluate_guardfile(:guardfile_contents => valid_guardfile_string) }.should_not raise_error
|
||||
subject.guardfile_contents.should == valid_guardfile_string
|
||||
end
|
||||
|
||||
it "reads correctly from a Guardfile" do
|
||||
fake_guardfile('/abc/Guardfile', "guard :foo" )
|
||||
|
||||
lambda { described_class.evaluate_guardfile(:guardfile => '/abc/Guardfile') }.should_not raise_error
|
||||
described_class.guardfile_contents.should == "guard :foo"
|
||||
lambda { subject.evaluate_guardfile(:guardfile => '/abc/Guardfile') }.should_not raise_error
|
||||
subject.guardfile_contents.should == "guard :foo"
|
||||
end
|
||||
|
||||
it "reads correctly from a Guardfile" do
|
||||
fake_guardfile(File.join(Dir.pwd, 'Guardfile'), valid_guardfile_string)
|
||||
|
||||
lambda { described_class.evaluate_guardfile }.should_not raise_error
|
||||
described_class.guardfile_contents.should == valid_guardfile_string
|
||||
lambda { subject.evaluate_guardfile }.should_not raise_error
|
||||
subject.guardfile_contents.should == valid_guardfile_string
|
||||
end
|
||||
end
|
||||
|
||||
@ -117,14 +117,14 @@ describe Guard::Dsl do
|
||||
File.stub!(:read).with('/def/Guardfile') { raise Errno::EACCES.new("permission error") }
|
||||
|
||||
Guard::UI.should_receive(:error).with(/^Error reading file/)
|
||||
lambda { described_class.evaluate_guardfile(:guardfile => '/def/Guardfile') }.should raise_error
|
||||
lambda { subject.evaluate_guardfile(:guardfile => '/def/Guardfile') }.should raise_error
|
||||
end
|
||||
|
||||
it "raises error when given Guardfile doesn't exist" do
|
||||
File.stub!(:exist?).with('/def/Guardfile') { false }
|
||||
|
||||
Guard::UI.should_receive(:error).with(/No Guardfile exists at/)
|
||||
lambda { described_class.evaluate_guardfile(:guardfile => '/def/Guardfile') }.should raise_error
|
||||
lambda { subject.evaluate_guardfile(:guardfile => '/def/Guardfile') }.should raise_error
|
||||
end
|
||||
|
||||
it "raises error when resorting to use default, finds no default" do
|
||||
@ -132,24 +132,24 @@ describe Guard::Dsl do
|
||||
File.stub!(:exist?).with(@home_guardfile_path) { false }
|
||||
|
||||
Guard::UI.should_receive(:error).with("No Guardfile found, please create one with `guard init`.")
|
||||
lambda { described_class.evaluate_guardfile }.should raise_error
|
||||
lambda { subject.evaluate_guardfile }.should raise_error
|
||||
end
|
||||
|
||||
it "raises error when guardfile_content ends up empty or nil" do
|
||||
Guard::UI.should_receive(:error).with(/The command file/)
|
||||
lambda { described_class.evaluate_guardfile(:guardfile_contents => "") }.should raise_error
|
||||
lambda { subject.evaluate_guardfile(:guardfile_contents => "") }.should raise_error
|
||||
end
|
||||
|
||||
it "doesn't raise error when guardfile_content is nil (skipped)" do
|
||||
Guard::UI.should_not_receive(:error)
|
||||
lambda { described_class.evaluate_guardfile(:guardfile_contents => nil) }.should_not raise_error
|
||||
lambda { subject.evaluate_guardfile(:guardfile_contents => nil) }.should_not raise_error
|
||||
end
|
||||
end
|
||||
|
||||
it "displays an error message when Guardfile is not valid" do
|
||||
Guard::UI.should_receive(:error).with(/Invalid Guardfile, original error is:/)
|
||||
|
||||
lambda { described_class.evaluate_guardfile(:guardfile_contents => invalid_guardfile_string ) }.should raise_error
|
||||
lambda { subject.evaluate_guardfile(:guardfile_contents => invalid_guardfile_string ) }.should raise_error
|
||||
end
|
||||
|
||||
describe ".reevaluate_guardfile" do
|
||||
@ -157,10 +157,10 @@ describe Guard::Dsl do
|
||||
|
||||
it "resets already definded guards before calling evaluate_guardfile" do
|
||||
Guard::Notifier.turn_off
|
||||
described_class.evaluate_guardfile(:guardfile_contents => invalid_guardfile_string)
|
||||
subject.evaluate_guardfile(:guardfile_contents => invalid_guardfile_string)
|
||||
::Guard.guards.should_not be_empty
|
||||
::Guard::Dsl.should_receive(:evaluate_guardfile)
|
||||
described_class.reevaluate_guardfile
|
||||
subject.reevaluate_guardfile
|
||||
::Guard.guards.should be_empty
|
||||
end
|
||||
end
|
||||
@ -173,14 +173,14 @@ describe Guard::Dsl do
|
||||
context "when there is a local Guardfile" do
|
||||
it "returns the path to the local Guardfile" do
|
||||
File.stub(:exist?).with(local_path).and_return(true)
|
||||
described_class.guardfile_default_path.should == local_path
|
||||
subject.guardfile_default_path.should == local_path
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a Guardfile in the user's home directory" do
|
||||
it "returns the path to the user Guardfile" do
|
||||
File.stub(:exist?).with(user_path).and_return(true)
|
||||
described_class.guardfile_default_path.should == user_path
|
||||
subject.guardfile_default_path.should == user_path
|
||||
end
|
||||
end
|
||||
|
||||
@ -188,34 +188,34 @@ describe Guard::Dsl do
|
||||
it "returns the path to the local Guardfile" do
|
||||
File.stub(:exist?).with(local_path).and_return(true)
|
||||
File.stub(:exist?).with(user_path).and_return(true)
|
||||
described_class.guardfile_default_path.should == local_path
|
||||
subject.guardfile_default_path.should == local_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".guardfile_include?" do
|
||||
it "detects a guard specified by a string with double quotes" do
|
||||
described_class.stub(:guardfile_contents => 'guard "test" {watch("c")}')
|
||||
subject.stub(:guardfile_contents => 'guard "test" {watch("c")}')
|
||||
|
||||
described_class.guardfile_include?('test').should be_true
|
||||
subject.guardfile_include?('test').should be_true
|
||||
end
|
||||
|
||||
it "detects a guard specified by a string with single quote" do
|
||||
described_class.stub(:guardfile_contents => 'guard \'test\' {watch("c")}')
|
||||
subject.stub(:guardfile_contents => 'guard \'test\' {watch("c")}')
|
||||
|
||||
described_class.guardfile_include?('test').should be_true
|
||||
subject.guardfile_include?('test').should be_true
|
||||
end
|
||||
|
||||
it "detects a guard specified by a symbol" do
|
||||
described_class.stub(:guardfile_contents => 'guard :test {watch("c")}')
|
||||
subject.stub(:guardfile_contents => 'guard :test {watch("c")}')
|
||||
|
||||
described_class.guardfile_include?('test').should be_true
|
||||
subject.guardfile_include?('test').should be_true
|
||||
end
|
||||
|
||||
it "detects a guard wrapped in parentheses" do
|
||||
described_class.stub(:guardfile_contents => 'guard(:test) {watch("c")}')
|
||||
subject.stub(:guardfile_contents => 'guard(:test) {watch("c")}')
|
||||
|
||||
described_class.guardfile_include?('test').should be_true
|
||||
subject.guardfile_include?('test').should be_true
|
||||
end
|
||||
end
|
||||
|
||||
@ -226,7 +226,7 @@ describe Guard::Dsl do
|
||||
::Guard.stub!(:listener).and_return(mock('Listener'))
|
||||
::Guard.listener.should_receive(:ignore_paths).and_return(ignore_paths = ['faz'])
|
||||
|
||||
described_class.evaluate_guardfile(:guardfile_contents => "ignore_paths 'foo', 'bar'")
|
||||
subject.evaluate_guardfile(:guardfile_contents => "ignore_paths 'foo', 'bar'")
|
||||
ignore_paths.should == ['faz', 'foo', 'bar']
|
||||
end
|
||||
end
|
||||
@ -238,14 +238,18 @@ describe Guard::Dsl do
|
||||
::Guard.should_receive(:add_guard).with('pow', [], [], { :group => :default })
|
||||
::Guard.should_receive(:add_guard).with('test', [], [], { :group => :w })
|
||||
|
||||
described_class.evaluate_guardfile(:guardfile_contents => valid_guardfile_string, :group => [:w])
|
||||
subject.evaluate_guardfile(:guardfile_contents => valid_guardfile_string, :group => [:w])
|
||||
|
||||
::Guard.groups.should eql [{ :name => :default, :options => {} }, { :name => :w, :options => {} }]
|
||||
end
|
||||
|
||||
it "evaluates only the specified symbol group" do
|
||||
::Guard.should_receive(:add_guard).with('pow', [], [], { :group => :default })
|
||||
::Guard.should_receive(:add_guard).with('test', [], [], { :group => :w })
|
||||
|
||||
described_class.evaluate_guardfile(:guardfile_contents => valid_guardfile_string, :group => [:w])
|
||||
subject.evaluate_guardfile(:guardfile_contents => valid_guardfile_string, :group => [:w])
|
||||
|
||||
::Guard.groups.should eql [{ :name => :default, :options => {} }, { :name => :w, :options => {} }]
|
||||
end
|
||||
|
||||
it "evaluates only the specified groups (with their options)" do
|
||||
@ -254,14 +258,18 @@ describe Guard::Dsl do
|
||||
::Guard.should_receive(:add_guard).with('ronn', [], [], { :group => :x })
|
||||
::Guard.should_receive(:add_guard).with('less', [], [], { :group => :y })
|
||||
|
||||
described_class.evaluate_guardfile(:guardfile_contents => valid_guardfile_string, :group => [:x, :y])
|
||||
subject.evaluate_guardfile(:guardfile_contents => valid_guardfile_string, :group => [:x, :y])
|
||||
|
||||
::Guard.groups.should eql [{ :name => :default, :options => {} }, { :name => :x, :options => { :halt_on_fail => true } }, { :name => :y, :options => {} }]
|
||||
end
|
||||
|
||||
it "evaluates always guard outside any group (even when a group is given)" do
|
||||
::Guard.should_receive(:add_guard).with('pow', [], [], { :group => :default })
|
||||
::Guard.should_receive(:add_guard).with('test', [], [], { :group => :w })
|
||||
|
||||
described_class.evaluate_guardfile(:guardfile_contents => valid_guardfile_string, :group => [:w])
|
||||
subject.evaluate_guardfile(:guardfile_contents => valid_guardfile_string, :group => [:w])
|
||||
|
||||
::Guard.groups.should eql [{ :name => :default, :options => {} }, { :name => :w, :options => {} }]
|
||||
end
|
||||
|
||||
it "evaluates all groups when no group option is specified (with their options)" do
|
||||
@ -271,7 +279,10 @@ describe Guard::Dsl do
|
||||
::Guard.should_receive(:add_guard).with('ronn', [], [], { :group => :x })
|
||||
::Guard.should_receive(:add_guard).with('less', [], [], { :group => :y })
|
||||
|
||||
described_class.evaluate_guardfile(:guardfile_contents => valid_guardfile_string)
|
||||
subject.evaluate_guardfile(:guardfile_contents => valid_guardfile_string)
|
||||
|
||||
::Guard.groups.should eql [{ :name => :default, :options => {} }, { :name => :w, :options => {} }, { :name => :x, :options => { :halt_on_fail => true } }, { :name => :y, :options => {} }]
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@ -281,31 +292,31 @@ describe Guard::Dsl do
|
||||
it "loads a guard specified as a quoted string from the DSL" do
|
||||
::Guard.should_receive(:add_guard).with('test', [], [], { :group => :default })
|
||||
|
||||
described_class.evaluate_guardfile(:guardfile_contents => "guard 'test'")
|
||||
subject.evaluate_guardfile(:guardfile_contents => "guard 'test'")
|
||||
end
|
||||
|
||||
it "loads a guard specified as a double quoted string from the DSL" do
|
||||
::Guard.should_receive(:add_guard).with('test', [], [], { :group => :default })
|
||||
|
||||
described_class.evaluate_guardfile(:guardfile_contents => 'guard "test"')
|
||||
subject.evaluate_guardfile(:guardfile_contents => 'guard "test"')
|
||||
end
|
||||
|
||||
it "loads a guard specified as a symbol from the DSL" do
|
||||
::Guard.should_receive(:add_guard).with('test', [], [], { :group => :default })
|
||||
|
||||
described_class.evaluate_guardfile(:guardfile_contents => "guard :test")
|
||||
subject.evaluate_guardfile(:guardfile_contents => "guard :test")
|
||||
end
|
||||
|
||||
it "loads a guard specified as a symbol and called with parens from the DSL" do
|
||||
::Guard.should_receive(:add_guard).with('test', [], [], { :group => :default })
|
||||
|
||||
described_class.evaluate_guardfile(:guardfile_contents => "guard(:test)")
|
||||
subject.evaluate_guardfile(:guardfile_contents => "guard(:test)")
|
||||
end
|
||||
|
||||
it "receives options when specified, from normal arg" do
|
||||
::Guard.should_receive(:add_guard).with('test', [], [], { :opt_a => 1, :opt_b => 'fancy', :group => :default })
|
||||
|
||||
described_class.evaluate_guardfile(:guardfile_contents => "guard 'test', :opt_a => 1, :opt_b => 'fancy'")
|
||||
subject.evaluate_guardfile(:guardfile_contents => "guard 'test', :opt_a => 1, :opt_b => 'fancy'")
|
||||
end
|
||||
end
|
||||
|
||||
@ -320,7 +331,7 @@ describe Guard::Dsl do
|
||||
watchers[1].pattern.should == 'c'
|
||||
watchers[1].action.should == nil
|
||||
end
|
||||
described_class.evaluate_guardfile(:guardfile_contents => "
|
||||
subject.evaluate_guardfile(:guardfile_contents => "
|
||||
guard :dummy do
|
||||
watch('a') { 'b' }
|
||||
watch('c')
|
||||
@ -343,7 +354,7 @@ describe Guard::Dsl do
|
||||
callbacks[1][:events].should == [:start_begin, :run_all_begin]
|
||||
callbacks[1][:listener].should == MyCustomCallback
|
||||
end
|
||||
described_class.evaluate_guardfile(:guardfile_contents => '
|
||||
subject.evaluate_guardfile(:guardfile_contents => '
|
||||
guard :dummy do
|
||||
callback(:start_end) { |guard_class, event, args| "#{guard_class} executed \'#{event}\' hook with #{args}!" }
|
||||
callback(MyCustomCallback, [:start_begin, :run_all_begin])
|
||||
|
@ -1,19 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Guard::Group do
|
||||
|
||||
describe ".initialize" do
|
||||
it "accepts a name as a string and provides an accessor for it (returning a symbol)" do
|
||||
described_class.new('foo').name.should eql :foo
|
||||
end
|
||||
|
||||
it "accepts a name as a symbol and provides an accessor for it (returning a symbol)" do
|
||||
described_class.new(:foo).name.should eql :foo
|
||||
end
|
||||
|
||||
it "accepts options and provides an accessor for it" do
|
||||
described_class.new('foo', :halt_on_fail => true).options.should == { :halt_on_fail => true }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@ -1,60 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Guard::Guard do
|
||||
|
||||
describe '#initialize' do
|
||||
|
||||
it 'assigns the defined watchers' do
|
||||
watchers = [ Guard::Watcher.new('*') ]
|
||||
guard = Guard::Guard.new(watchers)
|
||||
guard.watchers.should eql watchers
|
||||
end
|
||||
|
||||
it 'assigns the defined options' do
|
||||
options = { :a => 1, :b => 2 }
|
||||
guard = Guard::Guard.new([], options)
|
||||
guard.options.should eql options
|
||||
end
|
||||
|
||||
context 'with a group in the options' do
|
||||
it 'assigns the given group' do
|
||||
options = { :group => :test }
|
||||
guard = Guard::Guard.new([], options)
|
||||
guard.group.should eql :test
|
||||
end
|
||||
end
|
||||
|
||||
context 'without a group in the options' do
|
||||
it 'assigns a default group' do
|
||||
options = { }
|
||||
guard = Guard::Guard.new([], options)
|
||||
guard.group.should eql :default
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#init' do
|
||||
context 'when the Guard is already in the Guardfile' do
|
||||
before { ::Guard::Dsl.stub(:guardfile_include?).and_return true }
|
||||
|
||||
it 'shows an info message' do
|
||||
::Guard::UI.should_receive(:info).with 'Guardfile already includes myguard guard'
|
||||
Guard::Guard.init('myguard')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the Guard is not in the Guardfile' do
|
||||
before { ::Guard::Dsl.stub(:guardfile_include?).and_return false }
|
||||
|
||||
it 'appends the template to the Guardfile' do
|
||||
File.should_receive(:read).with('Guardfile').and_return 'Guardfile content'
|
||||
::Guard.should_receive(:locate_guard).with('myguard').and_return '/Users/me/projects/guard-myguard'
|
||||
File.should_receive(:read).with('/Users/me/projects/guard-myguard/lib/guard/myguard/templates/Guardfile').and_return('Template content')
|
||||
io = StringIO.new
|
||||
File.should_receive(:open).with('Guardfile', 'wb').and_yield io
|
||||
Guard::Guard.init('myguard')
|
||||
io.string.should eql "Guardfile content\n\nTemplate content\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -2,47 +2,48 @@ require 'spec_helper'
|
||||
require 'guard/guard'
|
||||
|
||||
describe Guard::Hook do
|
||||
subject { Guard::Hook }
|
||||
|
||||
class Guard::Dummy < Guard::Guard; end
|
||||
|
||||
let(:guard_class) { ::Guard::Dummy }
|
||||
let(:listener) { double('listener').as_null_object }
|
||||
|
||||
after { described_class.reset_callbacks! }
|
||||
after { subject.reset_callbacks! }
|
||||
|
||||
describe "--module methods--" do
|
||||
before { described_class.add_callback(listener, guard_class, :start_begin) }
|
||||
context "--module methods--" do
|
||||
before { subject.add_callback(listener, guard_class, :start_begin) }
|
||||
|
||||
describe ".add_callback" do
|
||||
it "can add a single callback" do
|
||||
described_class.has_callback?(listener, guard_class, :start_begin).should be_true
|
||||
subject.has_callback?(listener, guard_class, :start_begin).should be_true
|
||||
end
|
||||
|
||||
it "can add multiple callbacks" do
|
||||
described_class.add_callback(listener, guard_class, [:event1, :event2])
|
||||
described_class.has_callback?(listener, guard_class, :event1).should be_true
|
||||
described_class.has_callback?(listener, guard_class, :event2).should be_true
|
||||
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
|
||||
it "sends :call to the given Guard class's callbacks" do
|
||||
listener.should_receive(:call).with(guard_class, :start_begin, "args")
|
||||
described_class.notify(guard_class, :start_begin, "args")
|
||||
subject.notify(guard_class, :start_begin, "args")
|
||||
end
|
||||
|
||||
it "runs only the given callbacks" do
|
||||
listener2 = double('listener2')
|
||||
described_class.add_callback(listener2, guard_class, :start_end)
|
||||
subject.add_callback(listener2, guard_class, :start_end)
|
||||
listener2.should_not_receive(:call).with(guard_class, :start_end)
|
||||
described_class.notify(guard_class, :start_begin)
|
||||
subject.notify(guard_class, :start_begin)
|
||||
end
|
||||
|
||||
it "runs callbacks only for the guard given" do
|
||||
guard2_class = double('Guard::Dummy2').class
|
||||
described_class.add_callback(listener, guard2_class, :start_begin)
|
||||
subject.add_callback(listener, guard2_class, :start_begin)
|
||||
listener.should_not_receive(:call).with(guard2_class, :start_begin)
|
||||
described_class.notify(guard_class, :start_begin)
|
||||
subject.notify(guard_class, :start_begin)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -3,4 +3,26 @@ require 'spec_helper'
|
||||
describe Guard::Interactor do
|
||||
subject { Guard::Interactor.new }
|
||||
|
||||
describe "#initialize" do
|
||||
it "unlocks the interactor by default" do
|
||||
subject.locked.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#lock" do
|
||||
it "locks the interactor" do
|
||||
subject.start
|
||||
subject.lock
|
||||
subject.locked.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#unlock" do
|
||||
it "unlocks the interactor" do
|
||||
subject.start
|
||||
subject.unlock
|
||||
subject.locked.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,291 +1,200 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Guard::Listener do
|
||||
subject { Guard::Listener }
|
||||
|
||||
describe '.select_and_init' do
|
||||
describe ".select_and_init" do
|
||||
before(:each) { @target_os = RbConfig::CONFIG['target_os'] }
|
||||
after(:each) { RbConfig::CONFIG['target_os'] = @target_os }
|
||||
|
||||
it 'uses the Darwin listener on Mac OS X' do
|
||||
it "uses the Darwin listener on Mac OS X" do
|
||||
RbConfig::CONFIG['target_os'] = 'darwin10.4.0'
|
||||
Guard::Darwin.stub(:usable?).and_return(true)
|
||||
Guard::Darwin.should_receive(:new)
|
||||
described_class.select_and_init
|
||||
subject.select_and_init
|
||||
end
|
||||
|
||||
it 'uses the Windows listener on Windows' do
|
||||
it "uses the Windows listener on Windows" do
|
||||
RbConfig::CONFIG['target_os'] = 'mingw'
|
||||
Guard::Windows.stub(:usable?).and_return(true)
|
||||
Guard::Windows.should_receive(:new)
|
||||
described_class.select_and_init
|
||||
subject.select_and_init
|
||||
end
|
||||
|
||||
it 'uses the Linux listener on Linux' do
|
||||
it "uses the Linux listener on Linux" do
|
||||
RbConfig::CONFIG['target_os'] = 'linux'
|
||||
Guard::Linux.stub(:usable?).and_return(true)
|
||||
Guard::Linux.should_receive(:new)
|
||||
described_class.select_and_init
|
||||
subject.select_and_init
|
||||
end
|
||||
|
||||
it 'forwards its arguments to the constructor' do
|
||||
described_class.stub!(:mac?).and_return(true)
|
||||
it "forwards its arguments to the constructor" do
|
||||
subject.stub!(:mac?).and_return(true)
|
||||
Guard::Darwin.stub!(:usable?).and_return(true)
|
||||
|
||||
path, opts = 'path', { :foo => 23 }
|
||||
Guard::Darwin.should_receive(:new).with(path, opts).and_return(true)
|
||||
described_class.select_and_init(path, opts)
|
||||
subject.select_and_init(path, opts)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#all_files' do
|
||||
describe "#all_files" do
|
||||
subject { described_class.new(@fixture_path) }
|
||||
|
||||
it 'should return all files' do
|
||||
subject.all_files.should =~
|
||||
Dir.glob("#{ @fixture_path }/**/*", File::FNM_DOTMATCH).select { |file| File.file?(file) }
|
||||
it "should return all files" do
|
||||
subject.all_files.should =~ Dir.glob("#{@fixture_path}/**/*", File::FNM_DOTMATCH).select { |file| File.file?(file) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#relativize_paths' do
|
||||
describe "#relativize_paths" do
|
||||
subject { described_class.new('/tmp') }
|
||||
|
||||
let(:paths) { %w( /tmp/a /tmp/a/b /tmp/a.b/c.d ) }
|
||||
|
||||
it 'should relativize paths to the configured directory' do
|
||||
subject.relativize_paths(paths).should =~ %w( a a/b a.b/c.d )
|
||||
before :each do
|
||||
@paths = %w( /tmp/a /tmp/a/b /tmp/a.b/c.d )
|
||||
end
|
||||
|
||||
context 'when set to false' do
|
||||
it "should relativize paths to the configured directory" do
|
||||
subject.relativize_paths(@paths).should =~ %w( a a/b a.b/c.d )
|
||||
end
|
||||
|
||||
context "when set to false" do
|
||||
subject { described_class.new('/tmp', :relativize_paths => false) }
|
||||
|
||||
it 'can be disabled' do
|
||||
subject.relativize_paths(paths).should eql paths
|
||||
it "can be disabled" do
|
||||
subject.relativize_paths(@paths).should eql @paths
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update_last_event' do
|
||||
describe "#update_last_event" do
|
||||
subject { described_class.new }
|
||||
|
||||
it 'updates the last event to the current time' do
|
||||
it "updates the last event to the current time" do
|
||||
time = Time.now
|
||||
subject.update_last_event
|
||||
subject.instance_variable_get(:@last_event).to_i.should >= time.to_i
|
||||
end
|
||||
end
|
||||
|
||||
describe '#modified_files' do
|
||||
describe "#modified_files" do
|
||||
subject { described_class.new }
|
||||
|
||||
let(:file1) { fixture('folder1', 'file1.txt') }
|
||||
let(:file2) { fixture('folder1', 'folder2', 'file2.txt') }
|
||||
let(:file3) { fixture('folder1', 'deletedfile1.txt') }
|
||||
let(:file4) { fixture('folder1', 'movedfile1.txt') }
|
||||
let(:file5) { fixture('folder1', 'folder2', 'movedfile1.txt') }
|
||||
let(:file1) { @fixture_path.join("folder1", "file1.txt") }
|
||||
let(:file2) { @fixture_path.join("folder1", "folder2", "file2.txt") }
|
||||
let(:file3) { @fixture_path.join("folder1", "deletedfile1.txt") }
|
||||
|
||||
before { listen_to subject }
|
||||
before do
|
||||
@listener = subject
|
||||
end
|
||||
|
||||
context 'without the :all option' do
|
||||
it 'finds modified files only in the directory supplied' do
|
||||
watch do
|
||||
FileUtils.touch([file1, file2, file3])
|
||||
subject.modified_files([fixture('folder1')], {}).should =~
|
||||
['spec/fixtures/folder1/deletedfile1.txt', 'spec/fixtures/folder1/file1.txt']
|
||||
end
|
||||
context "without the :all option" do
|
||||
it "finds modified files only in the directory supplied" do
|
||||
start
|
||||
FileUtils.touch([file1, file2, file3])
|
||||
subject.modified_files([@fixture_path.join("folder1")], {}).should =~ ["spec/fixtures/folder1/deletedfile1.txt", "spec/fixtures/folder1/file1.txt"]
|
||||
stop
|
||||
end
|
||||
end
|
||||
|
||||
context 'with the :all options' do
|
||||
it 'finds modified files within subdirectories' do
|
||||
watch do
|
||||
FileUtils.touch([file1, file2, file3])
|
||||
subject.modified_files([fixture('folder1')], { :all => true }).should =~
|
||||
['spec/fixtures/folder1/deletedfile1.txt',
|
||||
'spec/fixtures/folder1/file1.txt',
|
||||
'spec/fixtures/folder1/folder2/file2.txt']
|
||||
end
|
||||
context "with the :all options" do
|
||||
it "finds modified files within subdirectories" do
|
||||
start
|
||||
FileUtils.touch([file1, file2, file3])
|
||||
subject.modified_files([@fixture_path.join("folder1")], { :all => true }).should =~ ["spec/fixtures/folder1/deletedfile1.txt", "spec/fixtures/folder1/file1.txt", "spec/fixtures/folder1/folder2/file2.txt"]
|
||||
stop
|
||||
end
|
||||
end
|
||||
|
||||
context 'without updating the content' do
|
||||
it 'ignores the files for the second time' do
|
||||
watch do
|
||||
FileUtils.touch([file1, file2, file3])
|
||||
subject.modified_files([fixture('folder1')], {}).should =~
|
||||
['spec/fixtures/folder1/deletedfile1.txt', 'spec/fixtures/folder1/file1.txt']
|
||||
|
||||
subject.update_last_event
|
||||
|
||||
FileUtils.touch([file1, file2, file3])
|
||||
subject.modified_files([fixture('folder1')], {}).should be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with content that has changed' do
|
||||
after { File.open(file1, 'w') { |f| f.write('') } }
|
||||
|
||||
it 'identifies the files for the second time' do
|
||||
watch do
|
||||
FileUtils.touch([file1, file2, file3])
|
||||
subject.modified_files([fixture('folder1')], {}).should =~
|
||||
['spec/fixtures/folder1/deletedfile1.txt', 'spec/fixtures/folder1/file1.txt']
|
||||
|
||||
subject.update_last_event
|
||||
|
||||
FileUtils.touch([file2, file3])
|
||||
File.open(file1, 'w') { |f| f.write('changed content') }
|
||||
subject.modified_files([fixture('folder1')], {}).should =~
|
||||
['spec/fixtures/folder1/file1.txt']
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without the :watch_all_modifications option' do
|
||||
after { FileUtils.touch(file3) }
|
||||
|
||||
it 'defaults to false' do
|
||||
subject.instance_variable_get(:@watch_all_modifications).should eql false
|
||||
end
|
||||
|
||||
context 'for a deleted file' do
|
||||
after { FileUtils.touch(file3) }
|
||||
|
||||
it 'does not catch the deletion' do
|
||||
File.exists?(file3).should be_true
|
||||
|
||||
watch do
|
||||
FileUtils.remove_file(file3)
|
||||
end
|
||||
|
||||
subject.modified_files([fixture('folder1')], {}).should =~ []
|
||||
end
|
||||
end
|
||||
|
||||
context 'for a moved file' do
|
||||
after { FileUtils.move(file4, file1) }
|
||||
|
||||
it 'does not catch the move' do
|
||||
File.exists?(file1).should be_true
|
||||
File.exists?(file4).should be_false
|
||||
|
||||
watch do
|
||||
FileUtils.move(file1, file4)
|
||||
end
|
||||
|
||||
subject.modified_files([@fixture_path.join('folder1')], {}).should =~ []
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with the :watch_all_modifications option' do
|
||||
subject { described_class.new(Dir.pwd, :watch_all_modifications => true) }
|
||||
|
||||
before do
|
||||
subject.timestamp_files
|
||||
context "without updating the content" do
|
||||
it "ignores the files for the second time" do
|
||||
start
|
||||
FileUtils.touch([file1, file2, file3])
|
||||
subject.modified_files([@fixture_path.join("folder1")], {}).should =~ ["spec/fixtures/folder1/deletedfile1.txt", "spec/fixtures/folder1/file1.txt"]
|
||||
subject.update_last_event
|
||||
FileUtils.touch([file1, file2, file3])
|
||||
subject.modified_files([@fixture_path.join("folder1")], {}).should be_empty
|
||||
stop
|
||||
end
|
||||
end
|
||||
|
||||
it 'should be true when set' do
|
||||
subject.instance_variable_get(:@watch_all_modifications).should eql true
|
||||
end
|
||||
context "with content that has changed" do
|
||||
after { File.open(file1, "w") { |f| f.write("") } }
|
||||
|
||||
context 'for a deleted file' do
|
||||
after { FileUtils.touch(file3) }
|
||||
|
||||
it 'catches the deletion' do
|
||||
File.exists?(file3).should be_true
|
||||
|
||||
watch do
|
||||
FileUtils.remove_file(file3)
|
||||
end
|
||||
|
||||
subject.modified_files([fixture('folder1')], {}).should =~
|
||||
['!spec/fixtures/folder1/deletedfile1.txt']
|
||||
end
|
||||
end
|
||||
|
||||
context 'for a moved file' do
|
||||
after { FileUtils.move(file4, file1) }
|
||||
|
||||
it 'catches the move' do
|
||||
File.exists?(file1).should be_true
|
||||
File.exists?(file4).should be_false
|
||||
|
||||
watch do
|
||||
FileUtils.move(file1, file4)
|
||||
end
|
||||
|
||||
subject.modified_files([@fixture_path.join('folder1')], {}).should =~
|
||||
['!spec/fixtures/folder1/file1.txt', 'spec/fixtures/folder1/movedfile1.txt']
|
||||
end
|
||||
it "identifies the files for the second time" do
|
||||
start
|
||||
FileUtils.touch([file1, file2, file3])
|
||||
subject.modified_files([@fixture_path.join("folder1")], {}).should =~ ["spec/fixtures/folder1/deletedfile1.txt", "spec/fixtures/folder1/file1.txt"]
|
||||
subject.update_last_event
|
||||
FileUtils.touch([file2, file3])
|
||||
File.open(file1, "w") { |f| f.write("changed content") }
|
||||
subject.modified_files([@fixture_path.join("folder1")], {}).should =~ ["spec/fixtures/folder1/file1.txt"]
|
||||
stop
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'working directory' do
|
||||
context 'unspecified' do
|
||||
describe "working directory" do
|
||||
context "unspecified" do
|
||||
subject { described_class.new }
|
||||
|
||||
it 'defaults to Dir.pwd' do
|
||||
it "defaults to Dir.pwd" do
|
||||
subject.instance_variable_get(:@directory).should eql Dir.pwd
|
||||
end
|
||||
|
||||
it 'can be not changed' do
|
||||
it "can be not changed" do
|
||||
subject.should_not respond_to(:directory=)
|
||||
end
|
||||
end
|
||||
|
||||
context 'specified as first argument to ::new' do
|
||||
let(:working_directory) { fixture('folder1') }
|
||||
context "specified as first argument to ::new" do
|
||||
subject { described_class.new @wd }
|
||||
|
||||
subject { described_class.new working_directory }
|
||||
|
||||
before { listen_to subject }
|
||||
|
||||
it 'can be inspected' do
|
||||
subject.instance_variable_get(:@directory).should eql working_directory.to_s
|
||||
before do
|
||||
@wd = @fixture_path.join("folder1")
|
||||
@listener = subject
|
||||
end
|
||||
|
||||
it 'can be not changed' do
|
||||
it "can be inspected" do
|
||||
subject.instance_variable_get(:@directory).should eql @wd.to_s
|
||||
end
|
||||
|
||||
it "can be not changed" do
|
||||
subject.should_not respond_to(:directory=)
|
||||
end
|
||||
|
||||
it 'will be used to watch' do
|
||||
subject.should_receive(:watch).with(working_directory.to_s)
|
||||
it "will be used to watch" do
|
||||
subject.should_receive(:watch).with(@wd.to_s)
|
||||
start
|
||||
stop
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#ignore_paths' do
|
||||
it 'defaults to the default ignore paths' do
|
||||
described_class.new.ignore_paths.should == Guard::Listener::DEFAULT_IGNORE_PATHS
|
||||
describe "#ignore_paths" do
|
||||
it "defaults to the default ignore paths" do
|
||||
subject.new.ignore_paths.should == Guard::Listener::DEFAULT_IGNORE_PATHS
|
||||
end
|
||||
|
||||
it 'can be added to via :ignore_paths option' do
|
||||
listener = described_class.new 'path', :ignore_paths => ['foo', 'bar']
|
||||
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
|
||||
describe "#exclude_ignored_paths [<dirs>]" do
|
||||
let(:ignore_paths) { nil }
|
||||
subject { described_class.new(@fixture_path, { :ignore_paths => ignore_paths }) }
|
||||
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']
|
||||
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
|
||||
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']
|
||||
it "excludes the ignored paths" do
|
||||
subject.exclude_ignored_paths(["spec/fixtures"]).should =~ ["spec/fixtures/folder1"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -2,26 +2,26 @@ require 'spec_helper'
|
||||
require 'guard/listeners/darwin'
|
||||
|
||||
describe Guard::Darwin do
|
||||
subject { Guard::Darwin }
|
||||
|
||||
if windows?
|
||||
it "isn't usable on windows" do
|
||||
described_class.should_not be_usable
|
||||
subject.should_not be_usable
|
||||
end
|
||||
end
|
||||
|
||||
if linux?
|
||||
it "isn't usable on linux" do
|
||||
described_class.should_not be_usable
|
||||
subject.should_not be_usable
|
||||
end
|
||||
end
|
||||
|
||||
if mac? && Guard::Darwin.usable?
|
||||
it "is usable on 10.6" do
|
||||
described_class.should be_usable
|
||||
subject.should be_usable
|
||||
end
|
||||
|
||||
it_should_behave_like "a listener that reacts to #on_change"
|
||||
it_should_behave_like "a listener scoped to a specific directory"
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -3,22 +3,23 @@ require 'fileutils'
|
||||
require 'guard/listeners/linux'
|
||||
|
||||
describe Guard::Linux do
|
||||
subject { Guard::Linux }
|
||||
|
||||
if mac?
|
||||
it "isn't usable on 10.6" do
|
||||
described_class.should_not be_usable
|
||||
subject.should_not be_usable
|
||||
end
|
||||
end
|
||||
|
||||
if windows?
|
||||
it "isn't usable on windows" do
|
||||
described_class.should_not be_usable
|
||||
subject.should_not be_usable
|
||||
end
|
||||
end
|
||||
|
||||
if linux? && Guard::Linux.usable?
|
||||
it "is usable on linux" do
|
||||
described_class.should be_usable
|
||||
subject.should be_usable
|
||||
end
|
||||
|
||||
describe "#start", :long_running => true do
|
||||
@ -71,6 +72,6 @@ describe Guard::Linux do
|
||||
stop
|
||||
File.open(file, 'w') {|f| f.write('') }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -2,8 +2,8 @@ require 'spec_helper'
|
||||
require 'guard/listeners/polling'
|
||||
|
||||
describe Guard::Polling do
|
||||
subject { Guard::Polling }
|
||||
|
||||
it_should_behave_like "a listener that reacts to #on_change"
|
||||
it_should_behave_like "a listener scoped to a specific directory"
|
||||
|
||||
end
|
||||
|
@ -2,26 +2,27 @@ require 'spec_helper'
|
||||
require 'guard/listeners/windows'
|
||||
|
||||
describe Guard::Windows do
|
||||
subject { Guard::Windows }
|
||||
|
||||
if linux?
|
||||
it "isn't usable on linux" do
|
||||
described_class.should_not be_usable
|
||||
subject.should_not be_usable
|
||||
end
|
||||
end
|
||||
|
||||
if mac?
|
||||
it "isn't usable on Mac" do
|
||||
described_class.should_not be_usable
|
||||
subject.should_not be_usable
|
||||
end
|
||||
end
|
||||
|
||||
if windows?
|
||||
it "is usable on Windows 2000 and later" do
|
||||
described_class.should be_usable
|
||||
subject.should be_usable
|
||||
end
|
||||
|
||||
it_should_behave_like "a listener that reacts to #on_change"
|
||||
it_should_behave_like "a listener scoped to a specific directory"
|
||||
end
|
||||
it_should_behave_like "a listener that reacts to #on_change"
|
||||
it_should_behave_like "a listener scoped to a specific directory"
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -1,11 +1,12 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Guard::Notifier do
|
||||
subject { Guard::Notifier }
|
||||
|
||||
describe ".turn_off" do
|
||||
before do
|
||||
ENV["GUARD_NOTIFY"] = 'true'
|
||||
described_class.turn_off
|
||||
subject.turn_off
|
||||
end
|
||||
|
||||
it "disables the notifications" do
|
||||
@ -21,27 +22,16 @@ describe Guard::Notifier do
|
||||
|
||||
context "with the GrowlNotify library available" do
|
||||
before do
|
||||
class ::GrowlNotify
|
||||
class GrowlNotFound < Exception; end
|
||||
module ::GrowlNotify
|
||||
def self.config ; end
|
||||
end
|
||||
end
|
||||
|
||||
it "loads the library and enables the notifications" do
|
||||
described_class.should_receive(:require).with('growl_notify').and_return true
|
||||
subject.should_receive(:require).with('growl_notify').and_return true
|
||||
GrowlNotify.should_receive(:application_name).and_return ''
|
||||
described_class.turn_on
|
||||
described_class.should be_enabled
|
||||
end
|
||||
|
||||
it "should respond properly to a GrowlNotify exception" do
|
||||
::GrowlNotify.should_receive(:config).and_raise ::GrowlNotify::GrowlNotFound
|
||||
::GrowlNotify.should_receive(:application_name).and_return ''
|
||||
::Guard::UI.should_receive(:info)
|
||||
described_class.should_receive(:require).with('growl_notify').and_return true
|
||||
described_class.turn_on
|
||||
described_class.should_not be_enabled
|
||||
described_class.growl_library.should eql :growl_notify
|
||||
subject.turn_on
|
||||
subject.should be_enabled
|
||||
end
|
||||
|
||||
after do
|
||||
@ -49,46 +39,21 @@ describe Guard::Notifier do
|
||||
end
|
||||
end
|
||||
|
||||
context "with the GNTP library available" do
|
||||
before do
|
||||
class ::GNTP
|
||||
def initialize(app); end
|
||||
def register(config) ; end
|
||||
end
|
||||
end
|
||||
|
||||
it "loads the library and enables the notifications" do
|
||||
described_class.should_receive(:require).with('growl_notify').and_raise LoadError
|
||||
described_class.should_receive(:require).with('ruby_gntp').and_return true
|
||||
described_class.turn_on
|
||||
described_class.should be_enabled
|
||||
described_class.growl_library.should eql :ruby_gntp
|
||||
end
|
||||
|
||||
after do
|
||||
Object.send(:remove_const, :GNTP)
|
||||
end
|
||||
end
|
||||
|
||||
context "with the Growl library available" do
|
||||
it "loads the library and enables the notifications" do
|
||||
described_class.should_receive(:require).with('growl_notify').and_raise LoadError
|
||||
described_class.should_receive(:require).with('ruby_gntp').and_raise LoadError
|
||||
described_class.should_receive(:require).with('growl').and_return true
|
||||
described_class.turn_on
|
||||
described_class.should be_enabled
|
||||
described_class.growl_library.should eql :growl
|
||||
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 a Growl library available" do
|
||||
context "without the Growl library available" do
|
||||
it "disables the notifications" do
|
||||
described_class.should_receive(:require).with('growl_notify').and_raise LoadError
|
||||
described_class.should_receive(:require).with('ruby_gntp').and_raise LoadError
|
||||
described_class.should_receive(:require).with('growl').and_raise LoadError
|
||||
described_class.turn_on
|
||||
described_class.should_not be_enabled
|
||||
described_class.growl_library.should be nil
|
||||
subject.should_receive(:require).with('growl_notify').and_raise LoadError
|
||||
subject.should_receive(:require).with('growl').and_raise LoadError
|
||||
subject.turn_on
|
||||
subject.should_not be_enabled
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -100,17 +65,17 @@ describe Guard::Notifier do
|
||||
|
||||
context "with the Libnotify library available" do
|
||||
it "loads the library and enables the notifications" do
|
||||
described_class.should_receive(:require).with('libnotify').and_return true
|
||||
described_class.turn_on
|
||||
described_class.should be_enabled
|
||||
subject.should_receive(:require).with('libnotify').and_return true
|
||||
subject.turn_on
|
||||
subject.should be_enabled
|
||||
end
|
||||
end
|
||||
|
||||
context "without the Libnotify library available" do
|
||||
it "disables the notifications" do
|
||||
described_class.should_receive(:require).with('libnotify').and_raise LoadError
|
||||
described_class.turn_on
|
||||
described_class.should_not be_enabled
|
||||
subject.should_receive(:require).with('libnotify').and_raise LoadError
|
||||
subject.turn_on
|
||||
subject.should_not be_enabled
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -122,36 +87,35 @@ describe Guard::Notifier do
|
||||
|
||||
context "with the rb-notifu library available" do
|
||||
it "loads the library and enables the notifications" do
|
||||
described_class.should_receive(:require).with('rb-notifu').and_return true
|
||||
described_class.turn_on
|
||||
described_class.should be_enabled
|
||||
subject.should_receive(:require).with('rb-notifu').and_return true
|
||||
subject.turn_on
|
||||
subject.should be_enabled
|
||||
end
|
||||
end
|
||||
|
||||
context "without the rb-notify library available" do
|
||||
it "disables the notifications" do
|
||||
described_class.should_receive(:require).with('rb-notifu').and_raise LoadError
|
||||
described_class.turn_on
|
||||
described_class.should_not be_enabled
|
||||
subject.should_receive(:require).with('rb-notifu').and_raise LoadError
|
||||
subject.turn_on
|
||||
subject.should_not be_enabled
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".notify" do
|
||||
before { described_class.stub(:enabled?).and_return(true) }
|
||||
before { subject.stub(:enabled?).and_return(true) }
|
||||
|
||||
context "on Mac OS" do
|
||||
before do
|
||||
RbConfig::CONFIG.stub(:[]).and_return 'darwin'
|
||||
described_class.stub(:require_growl)
|
||||
RbConfig::CONFIG.should_receive(:[]).with('target_os').and_return 'darwin'
|
||||
subject.stub(:require_growl)
|
||||
end
|
||||
|
||||
context 'with growl gem' do
|
||||
before do
|
||||
Object.send(:remove_const, :Growl) if defined?(Growl)
|
||||
Growl = Object.new
|
||||
described_class.growl_library = :growl
|
||||
end
|
||||
|
||||
after do
|
||||
@ -164,14 +128,13 @@ describe Guard::Notifier do
|
||||
:icon => Pathname.new(File.dirname(__FILE__)).join('../../images/success.png').to_s,
|
||||
:name => "Guard"
|
||||
)
|
||||
described_class.notify 'great', :title => '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)
|
||||
described_class.growl_library = nil
|
||||
described_class.should_receive(:enabled?).and_return(false)
|
||||
described_class.notify 'great', :title => 'Guard'
|
||||
subject.should_receive(:enabled?).and_return(true, false)
|
||||
subject.notify 'great', :title => 'Guard'
|
||||
end
|
||||
|
||||
it "allows additional notification options" do
|
||||
@ -181,7 +144,7 @@ describe Guard::Notifier do
|
||||
:name => "Guard",
|
||||
:priority => 1
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard', :priority => 1
|
||||
subject.notify 'great', :title => 'Guard', :priority => 1
|
||||
end
|
||||
|
||||
it "allows to overwrite a default notification option" do
|
||||
@ -190,7 +153,7 @@ describe Guard::Notifier do
|
||||
:icon => Pathname.new(File.dirname(__FILE__)).join('../../images/success.png').to_s,
|
||||
:name => "Guard-Cucumber"
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard', :name => "Guard-Cucumber"
|
||||
subject.notify 'great', :title => 'Guard', :name => "Guard-Cucumber"
|
||||
end
|
||||
end
|
||||
|
||||
@ -198,7 +161,6 @@ describe Guard::Notifier do
|
||||
before do
|
||||
Object.send(:remove_const, :GrowlNotify) if defined?(GrowlNotify)
|
||||
GrowlNotify = Object.new
|
||||
described_class.growl_library = :growl_notify
|
||||
end
|
||||
|
||||
after do
|
||||
@ -212,14 +174,13 @@ describe Guard::Notifier do
|
||||
:application_name => "Guard",
|
||||
:description => 'great'
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard'
|
||||
subject.notify 'great', :title => 'Guard'
|
||||
end
|
||||
|
||||
it "don't passes the notification to Growl if library is not available" do
|
||||
GrowlNotify.should_not_receive(:send_notification)
|
||||
described_class.growl_library = nil
|
||||
described_class.should_receive(:enabled?).and_return(false)
|
||||
described_class.notify 'great', :title => 'Guard'
|
||||
subject.should_receive(:enabled?).and_return(true, false)
|
||||
subject.notify 'great', :title => 'Guard'
|
||||
end
|
||||
|
||||
it "allows additional notification options" do
|
||||
@ -230,7 +191,7 @@ describe Guard::Notifier do
|
||||
:description => 'great',
|
||||
:priority => 1
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard', :priority => 1
|
||||
subject.notify 'great', :title => 'Guard', :priority => 1
|
||||
end
|
||||
|
||||
it "throws out the application name since Guard should only use one Growl App Name while running" do
|
||||
@ -240,80 +201,15 @@ describe Guard::Notifier do
|
||||
:application_name => "Guard",
|
||||
:description => 'great'
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard', :name => "Guard-Cucumber"
|
||||
end
|
||||
end
|
||||
|
||||
context 'with ruby_gntp gem' do
|
||||
before do
|
||||
described_class.growl_library = :ruby_gntp
|
||||
described_class.gntp = Object.new
|
||||
end
|
||||
|
||||
it "passes a success notification to Ruby GNTP" do
|
||||
described_class.gntp.should_receive(:notify).with(
|
||||
:name => "success",
|
||||
:text => 'great',
|
||||
:title => "Guard",
|
||||
:icon => 'file://' + Pathname.new(File.dirname(__FILE__)).join('../../images/success.png').to_s
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard'
|
||||
end
|
||||
|
||||
it "passes a pending notification to Ruby GNTP" do
|
||||
described_class.gntp.should_receive(:notify).with(
|
||||
:name => "pending",
|
||||
:text => 'great',
|
||||
:title => "Guard",
|
||||
:icon => 'file://' + Pathname.new(File.dirname(__FILE__)).join('../../images/pending.png').to_s
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard', :image => :pending
|
||||
end
|
||||
|
||||
it "passes a failure notification to Ruby GNTP" do
|
||||
described_class.gntp.should_receive(:notify).with(
|
||||
:name => "failed",
|
||||
:text => 'great',
|
||||
:title => "Guard",
|
||||
:icon => 'file://' + Pathname.new(File.dirname(__FILE__)).join('../../images/failed.png').to_s
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard', :image => :failed
|
||||
end
|
||||
|
||||
it "passes a general notification to Ruby GNTP" do
|
||||
described_class.gntp.should_receive(:notify).with(
|
||||
:name => "notify",
|
||||
:text => 'great',
|
||||
:title => "Guard",
|
||||
:icon => 'file:///path/to/custom.png'
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard', :image => '/path/to/custom.png'
|
||||
end
|
||||
|
||||
it "don't passes the notification to Ruby GNTP if library is not available" do
|
||||
described_class.gntp.should_not_receive(:notify)
|
||||
described_class.growl_library = nil
|
||||
described_class.should_receive(:enabled?).and_return(false)
|
||||
described_class.notify 'great', :title => 'Guard'
|
||||
end
|
||||
|
||||
it "allows additional notification options" do
|
||||
described_class.gntp.should_receive(:notify).with(
|
||||
:name => "success",
|
||||
:text => 'great',
|
||||
:title => "Guard",
|
||||
:icon => 'file://' + Pathname.new(File.dirname(__FILE__)).join('../../images/success.png').to_s,
|
||||
:sticky => true
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard', :sticky => true
|
||||
subject.notify 'great', :title => 'Guard', :name => "Guard-Cucumber"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
context "on Linux" do
|
||||
before do
|
||||
RbConfig::CONFIG.stub(:[]).and_return 'linux'
|
||||
described_class.stub(:require_libnotify)
|
||||
RbConfig::CONFIG.should_receive(:[]).with('target_os').and_return 'linux'
|
||||
subject.stub(:require_libnotify)
|
||||
Object.send(:remove_const, :Libnotify) if defined?(Libnotify)
|
||||
Libnotify = Object.new
|
||||
end
|
||||
@ -329,13 +225,13 @@ describe Guard::Notifier do
|
||||
:icon_path => Pathname.new(File.dirname(__FILE__)).join('../../images/success.png').to_s,
|
||||
:transient => true
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard'
|
||||
subject.notify 'great', :title => 'Guard'
|
||||
end
|
||||
|
||||
it "don't passes the notification to Libnotify if library is not available" do
|
||||
Libnotify.should_not_receive(:show)
|
||||
described_class.should_receive(:enabled?).and_return(false)
|
||||
described_class.notify 'great', :title => 'Guard'
|
||||
subject.should_receive(:enabled?).and_return(true, false)
|
||||
subject.notify 'great', :title => 'Guard'
|
||||
end
|
||||
|
||||
it "allows additional notification options" do
|
||||
@ -346,7 +242,7 @@ describe Guard::Notifier do
|
||||
:transient => true,
|
||||
:urgency => :critical
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard', :urgency => :critical
|
||||
subject.notify 'great', :title => 'Guard', :urgency => :critical
|
||||
end
|
||||
|
||||
it "allows to overwrite a default notification option" do
|
||||
@ -356,14 +252,14 @@ describe Guard::Notifier do
|
||||
:icon_path => '~/.guard/success.png',
|
||||
:transient => true
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard', :icon_path => '~/.guard/success.png'
|
||||
subject.notify 'great', :title => 'Guard', :icon_path => '~/.guard/success.png'
|
||||
end
|
||||
end
|
||||
|
||||
context "on Windows" do
|
||||
before do
|
||||
RbConfig::CONFIG.stub(:[]).and_return 'mswin'
|
||||
described_class.stub(:require_rbnotifu)
|
||||
RbConfig::CONFIG.should_receive(:[]).with('target_os').and_return 'mswin'
|
||||
subject.stub(:require_rbnotifu)
|
||||
Object.send(:remove_const, :Notifu) if defined?(Notifu)
|
||||
Notifu = Object.new
|
||||
end
|
||||
@ -379,13 +275,13 @@ describe Guard::Notifier do
|
||||
:type => :info,
|
||||
:time => 3
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard'
|
||||
subject.notify 'great', :title => 'Guard'
|
||||
end
|
||||
|
||||
it "don't passes the notification to rb-notifu if library is not available" do
|
||||
Notifu.should_not_receive(:show)
|
||||
described_class.should_receive(:enabled?).and_return(false)
|
||||
described_class.notify 'great', :title => 'Guard'
|
||||
subject.should_receive(:enabled?).and_return(true, false)
|
||||
subject.notify 'great', :title => 'Guard'
|
||||
end
|
||||
|
||||
it "allows additional notification options" do
|
||||
@ -396,7 +292,7 @@ describe Guard::Notifier do
|
||||
:time => 3,
|
||||
:nosound => true
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard', :nosound => true
|
||||
subject.notify 'great', :title => 'Guard', :nosound => true
|
||||
end
|
||||
|
||||
it "allows to overwrite a default notification option" do
|
||||
@ -406,7 +302,7 @@ describe Guard::Notifier do
|
||||
:type => :info,
|
||||
:time => 10
|
||||
)
|
||||
described_class.notify 'great', :title => 'Guard', :time => 10
|
||||
subject.notify 'great', :title => 'Guard', :time => 10
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -424,5 +320,4 @@ describe Guard::Notifier do
|
||||
it { should_not be_enabled }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -5,19 +5,19 @@ describe Guard::Watcher do
|
||||
|
||||
describe "#initialize" do
|
||||
it "requires a pattern parameter" do
|
||||
expect { described_class.new }.to raise_error(ArgumentError)
|
||||
expect { Guard::Watcher.new }.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
context "with a pattern parameter" do
|
||||
context "that is a string" do
|
||||
it "keeps the string pattern unmodified" do
|
||||
described_class.new('spec_helper.rb').pattern.should == 'spec_helper.rb'
|
||||
Guard::Watcher.new('spec_helper.rb').pattern.should == 'spec_helper.rb'
|
||||
end
|
||||
end
|
||||
|
||||
context "that is a regexp" do
|
||||
it "keeps the regex pattern unmodified" do
|
||||
described_class.new(/spec_helper\.rb/).pattern.should == /spec_helper\.rb/
|
||||
Guard::Watcher.new(/spec_helper\.rb/).pattern.should == /spec_helper\.rb/
|
||||
end
|
||||
end
|
||||
|
||||
@ -25,10 +25,10 @@ describe Guard::Watcher do
|
||||
before(:each) { Guard::UI.should_receive(:info).any_number_of_times }
|
||||
|
||||
it "converts the string automatically to a regex" do
|
||||
described_class.new('^spec_helper.rb').pattern.should == /^spec_helper.rb/
|
||||
described_class.new('spec_helper.rb$').pattern.should == /spec_helper.rb$/
|
||||
described_class.new('spec_helper\.rb').pattern.should == /spec_helper\.rb/
|
||||
described_class.new('.*_spec.rb').pattern.should == /.*_spec.rb/
|
||||
Guard::Watcher.new('^spec_helper.rb').pattern.should == /^spec_helper.rb/
|
||||
Guard::Watcher.new('spec_helper.rb$').pattern.should == /spec_helper.rb$/
|
||||
Guard::Watcher.new('spec_helper\.rb').pattern.should == /spec_helper\.rb/
|
||||
Guard::Watcher.new('.*_spec.rb').pattern.should == /.*_spec.rb/
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -36,228 +36,144 @@ describe Guard::Watcher do
|
||||
|
||||
describe "#action" do
|
||||
it "sets the action to nothing by default" do
|
||||
described_class.new(/spec_helper\.rb/).action.should be_nil
|
||||
Guard::Watcher.new(/spec_helper\.rb/).action.should be_nil
|
||||
end
|
||||
|
||||
it "sets the action to the supplied block" do
|
||||
action = lambda { |m| "spec/#{m[1]}_spec.rb" }
|
||||
described_class.new(%r{^lib/(.*).rb}, action).action.should == action
|
||||
Guard::Watcher.new(%r{^lib/(.*).rb}, action).action.should == action
|
||||
end
|
||||
end
|
||||
|
||||
describe ".match_files" do
|
||||
before(:all) do
|
||||
@guard = Guard::Guard.new
|
||||
@guard_any_return = Guard::Guard.new
|
||||
@guard_any_return.options[:any_return] = true
|
||||
end
|
||||
before(:all) { @guard = Guard::Guard.new }
|
||||
|
||||
context "with a watcher without action" do
|
||||
context "that is a regex pattern" do
|
||||
before(:all) { @guard.watchers = [described_class.new(/.*_spec\.rb/)] }
|
||||
before(:all) { @guard.watchers = [Guard::Watcher.new(/.*_spec\.rb/)] }
|
||||
|
||||
it "returns the paths that matches the regex" do
|
||||
described_class.match_files(@guard, ['guard_rocks_spec.rb', 'guard_rocks.rb']).should == ['guard_rocks_spec.rb']
|
||||
Guard::Watcher.match_files(@guard, ['guard_rocks_spec.rb', 'guard_rocks.rb']).should == ['guard_rocks_spec.rb']
|
||||
end
|
||||
end
|
||||
|
||||
context "that is a string pattern" do
|
||||
before(:all) { @guard.watchers = [described_class.new('guard_rocks_spec.rb')] }
|
||||
before(:all) { @guard.watchers = [Guard::Watcher.new('guard_rocks_spec.rb')] }
|
||||
|
||||
it "returns the path that matches the string" do
|
||||
described_class.match_files(@guard, ['guard_rocks_spec.rb', 'guard_rocks.rb']).should == ['guard_rocks_spec.rb']
|
||||
Guard::Watcher.match_files(@guard, ['guard_rocks_spec.rb', 'guard_rocks.rb']).should == ['guard_rocks_spec.rb']
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with a watcher action without parameter" do
|
||||
context "for a watcher that matches file strings" do
|
||||
before(:all) do
|
||||
@guard.watchers = [
|
||||
described_class.new('spec_helper.rb', lambda { 'spec' }),
|
||||
described_class.new('addition.rb', lambda { 1 + 1 }),
|
||||
described_class.new('hash.rb', lambda { Hash[:foo, 'bar'] }),
|
||||
described_class.new('array.rb', lambda { ['foo', 'bar'] }),
|
||||
described_class.new('blank.rb', lambda { '' }),
|
||||
described_class.new(/^uptime\.rb/, lambda { `uptime > /dev/null` })
|
||||
]
|
||||
end
|
||||
|
||||
it "returns a single file specified within the action" do
|
||||
described_class.match_files(@guard, ['spec_helper.rb']).should == ['spec']
|
||||
end
|
||||
|
||||
it "returns multiple files specified within the action" do
|
||||
described_class.match_files(@guard, ['hash.rb']).should == ['foo', 'bar']
|
||||
end
|
||||
|
||||
it "returns multiple files by combining the results of different actions" do
|
||||
described_class.match_files(@guard, ['spec_helper.rb', 'array.rb']).should == ['spec', 'foo', 'bar']
|
||||
end
|
||||
|
||||
it "returns nothing if the action returns something other than a string or an array of strings" do
|
||||
described_class.match_files(@guard, ['addition.rb']).should == []
|
||||
end
|
||||
|
||||
it "returns nothing if the action response is empty" do
|
||||
described_class.match_files(@guard, ['blank.rb']).should == []
|
||||
end
|
||||
|
||||
it "returns nothing if the action returns nothing" do
|
||||
described_class.match_files(@guard, ['uptime.rb']).should == []
|
||||
end
|
||||
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
|
||||
|
||||
context 'for a watcher that matches information objects' do
|
||||
before(:all) do
|
||||
@guard_any_return.watchers = [
|
||||
described_class.new('spec_helper.rb', lambda { 'spec' }),
|
||||
described_class.new('addition.rb', lambda { 1 + 1 }),
|
||||
described_class.new('hash.rb', lambda { Hash[:foo, 'bar'] }),
|
||||
described_class.new('array.rb', lambda { ['foo', 'bar'] }),
|
||||
described_class.new('blank.rb', lambda { '' }),
|
||||
described_class.new(/^uptime\.rb/, lambda { `uptime > /dev/null` })
|
||||
]
|
||||
end
|
||||
it "returns a single file specified within the action" do
|
||||
Guard::Watcher.match_files(@guard, ['spec_helper.rb']).should == ['spec']
|
||||
end
|
||||
|
||||
it "returns a single file specified within the action" do
|
||||
described_class.match_files(@guard_any_return, ['spec_helper.rb']).class.should == Array
|
||||
described_class.match_files(@guard_any_return, ['spec_helper.rb']).empty?.should == false
|
||||
end
|
||||
it "returns multiple files specified within the action" do
|
||||
Guard::Watcher.match_files(@guard, ['hash.rb']).should == ['foo', 'bar']
|
||||
end
|
||||
|
||||
it "returns multiple files specified within the action" do
|
||||
described_class.match_files(@guard_any_return, ['hash.rb']).should == [{:foo => 'bar'}]
|
||||
end
|
||||
it "returns multiple files by combining the results of different actions" do
|
||||
Guard::Watcher.match_files(@guard, ['spec_helper.rb', 'array.rb']).should == ['spec', 'foo', 'bar']
|
||||
end
|
||||
|
||||
it "returns multiple files by combining the results of different actions" do
|
||||
described_class.match_files(@guard_any_return, ['spec_helper.rb', 'array.rb']).should == ['spec', ['foo', 'bar']]
|
||||
end
|
||||
it "returns nothing if the action returns something other than a string or an array of strings" do
|
||||
Guard::Watcher.match_files(@guard, ['addition.rb']).should == []
|
||||
end
|
||||
|
||||
it "returns the evaluated addition argument in an array" do
|
||||
described_class.match_files(@guard_any_return, ['addition.rb']).class.should == Array
|
||||
described_class.match_files(@guard_any_return, ['addition.rb'])[0].should == 2
|
||||
end
|
||||
it "returns nothing if the action response is empty" do
|
||||
Guard::Watcher.match_files(@guard, ['blank.rb']).should == []
|
||||
end
|
||||
|
||||
it "returns nothing if the action response is empty string" do
|
||||
described_class.match_files(@guard_any_return, ['blank.rb']).should == ['']
|
||||
end
|
||||
|
||||
it "returns nothing if the action returns empty string" do
|
||||
described_class.match_files(@guard_any_return, ['uptime.rb']).should == ['']
|
||||
end
|
||||
it "returns nothing if the action returns nothing" do
|
||||
Guard::Watcher.match_files(@guard, ['uptime.rb']).should == []
|
||||
end
|
||||
end
|
||||
|
||||
context "with a watcher action that takes a parameter" do
|
||||
context "for a watcher that matches file strings" do
|
||||
before(:all) do
|
||||
@guard.watchers = [
|
||||
described_class.new(%r{lib/(.*)\.rb}, lambda { |m| "spec/#{m[1]}_spec.rb" }),
|
||||
described_class.new(/addition(.*)\.rb/, lambda { |m| 1 + 1 }),
|
||||
described_class.new('hash.rb', lambda { |m| Hash[:foo, 'bar'] }),
|
||||
described_class.new(/array(.*)\.rb/, lambda { |m| ['foo', 'bar'] }),
|
||||
described_class.new(/blank(.*)\.rb/, lambda { |m| '' }),
|
||||
described_class.new(/uptime(.*)\.rb/, lambda { |m| `uptime > /dev/null` })
|
||||
]
|
||||
end
|
||||
|
||||
it "returns a substituted single file specified within the action" do
|
||||
described_class.match_files(@guard, ['lib/my_wonderful_lib.rb']).should == ['spec/my_wonderful_lib_spec.rb']
|
||||
end
|
||||
|
||||
it "returns multiple files specified within the action" do
|
||||
described_class.match_files(@guard, ['hash.rb']).should == ['foo', 'bar']
|
||||
end
|
||||
|
||||
it "returns multiple files by combining the results of different actions" do
|
||||
described_class.match_files(@guard, ['lib/my_wonderful_lib.rb', 'array.rb']).should == ['spec/my_wonderful_lib_spec.rb', 'foo', 'bar']
|
||||
end
|
||||
|
||||
it "returns nothing if the action returns something other than a string or an array of strings" do
|
||||
described_class.match_files(@guard, ['addition.rb']).should == []
|
||||
end
|
||||
|
||||
it "returns nothing if the action response is empty" do
|
||||
described_class.match_files(@guard, ['blank.rb']).should == []
|
||||
end
|
||||
|
||||
it "returns nothing if the action returns nothing" do
|
||||
described_class.match_files(@guard, ['uptime.rb']).should == []
|
||||
end
|
||||
before(:all) do
|
||||
@guard.watchers = [
|
||||
Guard::Watcher.new(%r{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
|
||||
|
||||
context "for a watcher that matches information objects" do
|
||||
before(:all) do
|
||||
@guard_any_return.watchers = [
|
||||
described_class.new(%r{lib/(.*)\.rb}, lambda { |m| "spec/#{m[1]}_spec.rb" }),
|
||||
described_class.new(/addition(.*)\.rb/, lambda { |m| (1 + 1).to_s + m[0] }),
|
||||
described_class.new('hash.rb', lambda { |m| Hash[:foo, 'bar', :file_name, m[0]] }),
|
||||
described_class.new(/array(.*)\.rb/, lambda { |m| ['foo', 'bar', m[0]] }),
|
||||
described_class.new(/blank(.*)\.rb/, lambda { |m| '' }),
|
||||
described_class.new(/uptime(.*)\.rb/, lambda { |m| `uptime > /dev/null` })
|
||||
]
|
||||
end
|
||||
it "returns a substituted single file specified within the action" do
|
||||
Guard::Watcher.match_files(@guard, ['lib/my_wonderful_lib.rb']).should == ['spec/my_wonderful_lib_spec.rb']
|
||||
end
|
||||
|
||||
it "returns a substituted single file specified within the action" do
|
||||
described_class.match_files(@guard_any_return, ['lib/my_wonderful_lib.rb']).should == ['spec/my_wonderful_lib_spec.rb']
|
||||
end
|
||||
it "returns multiple files specified within the action" do
|
||||
Guard::Watcher.match_files(@guard, ['hash.rb']).should == ['foo', 'bar']
|
||||
end
|
||||
|
||||
it "returns a hash specified within the action" do
|
||||
described_class.match_files(@guard_any_return, ['hash.rb']).should == [{:foo => 'bar', :file_name => 'hash.rb'}]
|
||||
end
|
||||
it "returns multiple files by combining the results of different actions" do
|
||||
Guard::Watcher.match_files(@guard, ['lib/my_wonderful_lib.rb', 'array.rb']).should == ['spec/my_wonderful_lib_spec.rb', 'foo', 'bar']
|
||||
end
|
||||
|
||||
it "returns multiple files by combining the results of different actions" do
|
||||
described_class.match_files(@guard_any_return, ['lib/my_wonderful_lib.rb', 'array.rb']).should == ['spec/my_wonderful_lib_spec.rb', ['foo', 'bar', "array.rb"]]
|
||||
end
|
||||
it "returns nothing if the action returns something other than a string or an array of strings" do
|
||||
Guard::Watcher.match_files(@guard, ['addition.rb']).should == []
|
||||
end
|
||||
|
||||
it "returns the evaluated addition argument + the path" do
|
||||
described_class.match_files(@guard_any_return, ['addition.rb']).should == ["2addition.rb"]
|
||||
end
|
||||
it "returns nothing if the action response is empty" do
|
||||
Guard::Watcher.match_files(@guard, ['blank.rb']).should == []
|
||||
end
|
||||
|
||||
it "returns nothing if the action response is empty string" do
|
||||
described_class.match_files(@guard_any_return, ['blank.rb']).should == ['']
|
||||
end
|
||||
|
||||
it "returns nothing if the action returns empty string" do
|
||||
described_class.match_files(@guard_any_return, ['uptime.rb']).should == ['']
|
||||
end
|
||||
it "returns nothing if the action returns nothing" do
|
||||
Guard::Watcher.match_files(@guard, ['uptime.rb']).should == []
|
||||
end
|
||||
end
|
||||
|
||||
context "with an exception that is raised" do
|
||||
before(:all) { @guard.watchers = [described_class.new('evil.rb', lambda { raise "EVIL" })] }
|
||||
before(:all) { @guard.watchers = [Guard::Watcher.new('evil.rb', lambda { raise "EVIL" })] }
|
||||
|
||||
it "displays the error and backtrace" do
|
||||
Guard::UI.should_receive(:error) do |msg|
|
||||
msg.should include("Problem with watch action!")
|
||||
msg.should include("EVIL")
|
||||
end
|
||||
it "displays the error and backtrace" do
|
||||
Guard::UI.should_receive(:error) { |msg|
|
||||
msg.should include("Problem with watch action!")
|
||||
msg.should include("EVIL")
|
||||
}
|
||||
|
||||
described_class.match_files(@guard, ['evil.rb'])
|
||||
end
|
||||
end
|
||||
end
|
||||
Guard::Watcher.match_files(@guard, ['evil.rb'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".match_files?" do
|
||||
before(:all) do
|
||||
@guard1 = Guard::Guard.new([described_class.new(/.*_spec\.rb/)])
|
||||
@guard2 = Guard::Guard.new([described_class.new('spec_helper.rb', 'spec')])
|
||||
@guard1 = Guard::Guard.new([Guard::Watcher.new(/.*_spec\.rb/)])
|
||||
@guard2 = Guard::Guard.new([Guard::Watcher.new('spec_helper.rb', 'spec')])
|
||||
@guards = [@guard1, @guard2]
|
||||
end
|
||||
|
||||
context "with a watcher that matches a file" do
|
||||
specify { described_class.match_files?(@guards, ['lib/my_wonderful_lib.rb', 'guard_rocks_spec.rb']).should be_true }
|
||||
specify { Guard::Watcher.match_files?(@guards, ['lib/my_wonderful_lib.rb', 'guard_rocks_spec.rb']).should be_true }
|
||||
end
|
||||
|
||||
context "with no watcher that matches a file" do
|
||||
specify { described_class.match_files?(@guards, ['lib/my_wonderful_lib.rb']).should be_false }
|
||||
specify { Guard::Watcher.match_files?(@guards, ['lib/my_wonderful_lib.rb']).should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
describe "#match_file?" do
|
||||
context "with a string pattern" do
|
||||
context "that is a normal string" do
|
||||
subject { described_class.new('guard_rocks_spec.rb') }
|
||||
subject { Guard::Watcher.new('guard_rocks_spec.rb') }
|
||||
|
||||
context "with a watcher that matches a file" do
|
||||
specify { subject.match_file?('guard_rocks_spec.rb').should be_true }
|
||||
@ -269,7 +185,7 @@ describe Guard::Watcher do
|
||||
end
|
||||
|
||||
context "that is a string representing a regexp (deprecated)" do
|
||||
subject { described_class.new('^guard_rocks_spec\.rb$') }
|
||||
subject { Guard::Watcher.new('^guard_rocks_spec\.rb$') }
|
||||
|
||||
context "with a watcher that matches a file" do
|
||||
specify { subject.match_file?('guard_rocks_spec.rb').should be_true }
|
||||
@ -282,7 +198,7 @@ describe Guard::Watcher do
|
||||
end
|
||||
|
||||
context "that is a regexp pattern" do
|
||||
subject { described_class.new(/.*_spec\.rb/) }
|
||||
subject { Guard::Watcher.new(/.*_spec\.rb/) }
|
||||
|
||||
context "with a watcher that matches a file" do
|
||||
specify { subject.match_file?('guard_rocks_spec.rb').should be_true }
|
||||
@ -298,11 +214,11 @@ describe Guard::Watcher do
|
||||
before(:all) { Guard::Dsl.stub(:guardfile_path) { Dir.pwd + '/Guardfile' } }
|
||||
|
||||
context "with files that match the Guardfile" do
|
||||
specify { described_class.match_guardfile?(['Guardfile', 'guard_rocks_spec.rb']).should be_true }
|
||||
specify { Guard::Watcher.match_guardfile?(['Guardfile', 'guard_rocks_spec.rb']).should be_true }
|
||||
end
|
||||
|
||||
context "with no files that match the Guardfile" do
|
||||
specify { described_class.match_guardfile?(['guard_rocks.rb', 'guard_rocks_spec.rb']).should be_false }
|
||||
specify { Guard::Watcher.match_guardfile?(['guard_rocks.rb', 'guard_rocks_spec.rb']).should be_false }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -3,45 +3,6 @@ require 'guard/guard'
|
||||
|
||||
describe Guard do
|
||||
|
||||
describe ".initialize_template" do
|
||||
context "with a Guard name" do
|
||||
it "initializes a the Guard" do
|
||||
class Guard::TestGuard < Guard::Guard
|
||||
end
|
||||
Guard::TestGuard.should_receive(:init)
|
||||
Guard.initialize_template('test-guard')
|
||||
end
|
||||
end
|
||||
|
||||
context "without a Guard name" do
|
||||
context "with an existing Guardfile" do
|
||||
before do
|
||||
File.stub(:exist?).and_return true
|
||||
Dir.stub(:pwd).and_return "/home/user"
|
||||
end
|
||||
|
||||
it "shows an error" do
|
||||
Guard.should_receive(:exit).with 1
|
||||
::Guard::UI.should_receive(:error).with("Guardfile already exists at /home/user/Guardfile")
|
||||
Guard.initialize_template()
|
||||
end
|
||||
end
|
||||
|
||||
context "without an existing Guardfile" do
|
||||
before do
|
||||
File.stub(:exist?).and_return false
|
||||
Dir.stub(:pwd).and_return "/home/user"
|
||||
end
|
||||
|
||||
it "copies the Guardfile template" do
|
||||
::Guard::UI.should_receive(:info).with("Writing new Guardfile to /home/user/Guardfile")
|
||||
FileUtils.should_receive(:cp).with(an_instance_of(String), 'Guardfile')
|
||||
Guard.initialize_template()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".setup" do
|
||||
subject { ::Guard.setup }
|
||||
|
||||
@ -54,8 +15,7 @@ describe Guard do
|
||||
end
|
||||
|
||||
it "initializes @groups" do
|
||||
described_class.groups[0].name.should eql :default
|
||||
described_class.groups[0].options.should == {}
|
||||
Guard.groups.should eql [{ :name => :default, :options => {} }]
|
||||
end
|
||||
|
||||
it "initializes the options" do
|
||||
@ -93,129 +53,6 @@ describe Guard do
|
||||
::Guard.should_receive(:debug_command_execution)
|
||||
::Guard.setup(:debug => true)
|
||||
end
|
||||
|
||||
it "initializes the interactor" do
|
||||
::Guard.setup
|
||||
::Guard.interactor.should be_kind_of(Guard::Interactor)
|
||||
end
|
||||
|
||||
it "skips the interactor initalization if no-interactions is true" do
|
||||
::Guard.interactor = nil
|
||||
::Guard.setup(:no_interactions => true)
|
||||
::Guard.interactor.should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe ".guards" do
|
||||
|
||||
class Guard::FooBar < Guard::Guard; end
|
||||
class Guard::FooBaz < Guard::Guard; end
|
||||
|
||||
subject do
|
||||
guard = ::Guard.setup
|
||||
@guard_foo_bar_backend = Guard::FooBar.new([], { :group => 'backend' })
|
||||
@guard_foo_bar_frontend = Guard::FooBar.new([], { :group => 'frontend' })
|
||||
@guard_foo_baz_backend = Guard::FooBaz.new([], { :group => 'backend' })
|
||||
@guard_foo_baz_frontend = Guard::FooBaz.new([], { :group => 'frontend' })
|
||||
guard.instance_variable_get("@guards").push(@guard_foo_bar_backend)
|
||||
guard.instance_variable_get("@guards").push(@guard_foo_bar_frontend)
|
||||
guard.instance_variable_get("@guards").push(@guard_foo_baz_backend)
|
||||
guard.instance_variable_get("@guards").push(@guard_foo_baz_frontend)
|
||||
guard
|
||||
end
|
||||
|
||||
it "return @guards without any argument" do
|
||||
subject.guards.should eql subject.instance_variable_get("@guards")
|
||||
end
|
||||
|
||||
describe "find a guard by as string/symbol" do
|
||||
it "find a guard by a string" do
|
||||
subject.guards('foo-bar').should eql @guard_foo_bar_backend
|
||||
end
|
||||
|
||||
it "find a guard by a symbol" do
|
||||
subject.guards(:'foo-bar').should eql @guard_foo_bar_backend
|
||||
end
|
||||
|
||||
it "returns nil if guard is not found" do
|
||||
subject.guards('foo-foo').should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "find guards matching a regexp" do
|
||||
it "with matches" do
|
||||
subject.guards(/^foobar/).should eql [@guard_foo_bar_backend, @guard_foo_bar_frontend]
|
||||
end
|
||||
|
||||
it "without matches" do
|
||||
subject.guards(/foo$/).should eql []
|
||||
end
|
||||
end
|
||||
|
||||
describe "find guards by their group" do
|
||||
it "group name is a string" do
|
||||
subject.guards(:group => 'backend').should eql [@guard_foo_bar_backend, @guard_foo_baz_backend]
|
||||
end
|
||||
|
||||
it "group name is a symbol" do
|
||||
subject.guards(:group => :frontend).should eql [@guard_foo_bar_frontend, @guard_foo_baz_frontend]
|
||||
end
|
||||
|
||||
it "returns [] if guard is not found" do
|
||||
subject.guards(:group => :unknown).should eql []
|
||||
end
|
||||
end
|
||||
|
||||
describe "find guards by their group & name" do
|
||||
it "group name is a string" do
|
||||
subject.guards(:group => 'backend', :name => 'foo-bar').should eql [@guard_foo_bar_backend]
|
||||
end
|
||||
|
||||
it "group name is a symbol" do
|
||||
subject.guards(:group => :frontend, :name => :'foo-baz').should eql [@guard_foo_baz_frontend]
|
||||
end
|
||||
|
||||
it "returns [] if guard is not found" do
|
||||
subject.guards(:group => :unknown, :name => :'foo-baz').should eql []
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".groups" do
|
||||
subject do
|
||||
guard = ::Guard.setup
|
||||
@group_backend = guard.add_group(:backend)
|
||||
@group_backflip = guard.add_group(:backflip)
|
||||
guard
|
||||
end
|
||||
|
||||
it "return @groups without any argument" do
|
||||
subject.groups.should eql subject.instance_variable_get("@groups")
|
||||
end
|
||||
|
||||
describe "find a group by as string/symbol" do
|
||||
it "find a group by a string" do
|
||||
subject.groups('backend').should eql @group_backend
|
||||
end
|
||||
|
||||
it "find a group by a symbol" do
|
||||
subject.groups(:backend).should eql @group_backend
|
||||
end
|
||||
|
||||
it "returns nil if group is not found" do
|
||||
subject.groups(:foo).should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "find groups matching a regexp" do
|
||||
it "with matches" do
|
||||
subject.groups(/^back/).should eql [@group_backend, @group_backflip]
|
||||
end
|
||||
|
||||
it "without matches" do
|
||||
subject.groups(/back$/).should eql []
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".start" do
|
||||
@ -298,22 +135,19 @@ describe Guard do
|
||||
it "accepts group name as string" do
|
||||
subject.add_group('backend')
|
||||
|
||||
subject.groups[0].name.should eql :default
|
||||
subject.groups[1].name.should eql :backend
|
||||
subject.groups.should eql [{ :name => :default, :options => {} }, { :name => :backend, :options => {} }]
|
||||
end
|
||||
|
||||
it "accepts group name as symbol" do
|
||||
subject.add_group(:backend)
|
||||
|
||||
subject.groups[0].name.should eql :default
|
||||
subject.groups[1].name.should eql :backend
|
||||
subject.groups.should eql [{ :name => :default, :options => {} }, { :name => :backend, :options => {} }]
|
||||
end
|
||||
|
||||
it "accepts options" do
|
||||
subject.add_group(:backend, { :halt_on_fail => true })
|
||||
|
||||
subject.groups[0].options.should == {}
|
||||
subject.groups[1].options.should == { :halt_on_fail => true }
|
||||
subject.groups.should eql [{ :name => :default, :options => {} }, { :name => :backend, :options => { :halt_on_fail => true } }]
|
||||
end
|
||||
end
|
||||
|
||||
@ -392,7 +226,7 @@ describe Guard do
|
||||
end
|
||||
end
|
||||
|
||||
describe ".run_guard_task" do
|
||||
describe ".execute_supervised_task_for_all_guards" do
|
||||
subject { ::Guard.setup }
|
||||
|
||||
before do
|
||||
@ -413,13 +247,13 @@ describe Guard do
|
||||
end
|
||||
|
||||
it "executes the task for each guard in each group" do
|
||||
subject.run_guard_task(:task)
|
||||
subject.execute_supervised_task_for_all_guards(:task)
|
||||
|
||||
@sum.all? { |k, v| v == 2 }.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "one guard fails" do
|
||||
context "one guard fails (by returning false)" do
|
||||
before do
|
||||
subject.guards.each_with_index do |g, i|
|
||||
g.stub!(:task) do
|
||||
@ -434,7 +268,7 @@ describe Guard do
|
||||
end
|
||||
|
||||
it "executes the task only for guards that didn't fail for group with :halt_on_fail == true" do
|
||||
subject.run_guard_task(:task)
|
||||
subject.execute_supervised_task_for_all_guards(:task)
|
||||
|
||||
@sum[:foo].should eql 1
|
||||
@sum[:bar].should eql 7
|
||||
@ -442,52 +276,13 @@ describe Guard do
|
||||
end
|
||||
end
|
||||
|
||||
describe ".run_on_change_task" do
|
||||
let(:guard) do
|
||||
class Guard::Dummy < Guard::Guard
|
||||
def watchers
|
||||
[Guard::Watcher.new(/.+\.rb/)]
|
||||
end
|
||||
end
|
||||
|
||||
Guard::Dummy.new
|
||||
end
|
||||
|
||||
it 'runs the :run_on_change task with the watched file changes' do
|
||||
Guard.should_receive(:run_supervised_task).with(guard, :run_on_change, ['a.rb', 'b.rb'])
|
||||
Guard.run_on_change_task(['a.rb', 'b.rb', 'templates/d.haml'], guard, :run_on_change)
|
||||
end
|
||||
|
||||
it 'runs the :run_on_deletion task with the watched file deletions' do
|
||||
Guard.should_receive(:run_supervised_task).with(guard, :run_on_deletion, ['c.rb'])
|
||||
Guard.run_on_change_task(['!c.rb', '!templates/e.haml'], guard, :run_on_change)
|
||||
end
|
||||
end
|
||||
|
||||
describe ".changed_paths" do
|
||||
let(:paths) { ['a.rb', 'b.rb', '!c.rb', 'templates/d.haml', '!templates/e.haml'] }
|
||||
|
||||
it 'returns the changed paths' do
|
||||
Guard.changed_paths(paths).should =~ ['a.rb', 'b.rb', 'templates/d.haml']
|
||||
end
|
||||
end
|
||||
|
||||
describe ".deleted_paths" do
|
||||
let(:paths) { ['a.rb', 'b.rb', '!c.rb', 'templates/d.haml', '!templates/e.haml'] }
|
||||
|
||||
it 'returns the deleted paths' do
|
||||
Guard.deleted_paths(paths).should =~ ['c.rb', 'templates/e.haml']
|
||||
end
|
||||
end
|
||||
|
||||
describe ".run_supervised_task" do
|
||||
describe ".supervised_task" do
|
||||
subject { ::Guard.setup }
|
||||
|
||||
before do
|
||||
@g = mock(Guard::Guard).as_null_object
|
||||
subject.guards.push(@g)
|
||||
subject.add_group(:foo, { :halt_on_fail => true })
|
||||
subject.add_group(:bar, { :halt_on_fail => false })
|
||||
subject.groups.push({ :name => :foo, :options => { :halt_on_fail => true } })
|
||||
end
|
||||
|
||||
context "with a task that succeed" do
|
||||
@ -497,22 +292,22 @@ describe Guard do
|
||||
end
|
||||
|
||||
it "doesn't fire the Guard" do
|
||||
lambda { subject.run_supervised_task(@g, :regular_without_arg) }.should_not change(subject.guards, :size)
|
||||
lambda { subject.supervised_task(@g, :regular_without_arg) }.should_not change(subject.guards, :size)
|
||||
end
|
||||
|
||||
it "returns the result of the task" do
|
||||
::Guard.run_supervised_task(@g, :regular_without_arg).should be_true
|
||||
::Guard.supervised_task(@g, :regular_without_arg).should be_true
|
||||
end
|
||||
|
||||
it "passes the args to the :begin hook" do
|
||||
@g.should_receive(:hook).with("regular_without_arg_begin", "given_path")
|
||||
::Guard.run_supervised_task(@g, :regular_without_arg, "given_path")
|
||||
::Guard.supervised_task(@g, :regular_without_arg, "given_path")
|
||||
end
|
||||
|
||||
it "passes the result of the supervised method to the :end hook" do
|
||||
@g.should_receive(:hook).with("regular_without_arg_begin", "given_path")
|
||||
@g.should_receive(:hook).with("regular_without_arg_end", true)
|
||||
::Guard.run_supervised_task(@g, :regular_without_arg, "given_path")
|
||||
::Guard.supervised_task(@g, :regular_without_arg, "given_path")
|
||||
end
|
||||
end
|
||||
|
||||
@ -522,91 +317,45 @@ describe Guard do
|
||||
end
|
||||
|
||||
it "doesn't fire the Guard" do
|
||||
lambda { subject.run_supervised_task(@g, :regular_with_arg, "given_path") }.should_not change(subject.guards, :size)
|
||||
lambda { subject.supervised_task(@g, :regular_with_arg, "given_path") }.should_not change(subject.guards, :size)
|
||||
end
|
||||
|
||||
it "returns the result of the task" do
|
||||
::Guard.run_supervised_task(@g, :regular_with_arg, "given_path").should eql "I'm a success"
|
||||
::Guard.supervised_task(@g, :regular_with_arg, "given_path").should eql "I'm a success"
|
||||
end
|
||||
|
||||
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.run_supervised_task(@g, :failing)
|
||||
::Guard.supervised_task(@g, :failing)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with a task that throw :task_has_failed" do
|
||||
context "for a guard's group has the :halt_on_fail option == true" do
|
||||
before(:each) { @g.stub!(:group) { :foo }; @g.stub!(:failing) { throw :task_has_failed } }
|
||||
context "with a task that return false and guard's group has the :halt_on_fail option == true" do
|
||||
before(:each) { @g.stub!(:group) { :foo }; @g.stub!(:failing) { throw :task_has_failed } }
|
||||
|
||||
it "throws :task_has_failed" do
|
||||
expect { subject.run_supervised_task(@g, :failing) }.to throw_symbol(:task_has_failed)
|
||||
end
|
||||
end
|
||||
|
||||
context "for a guard's group has the :halt_on_fail option == false" do
|
||||
before(:each) { @g.stub!(:group) { :bar }; @g.stub!(:failing) { throw :task_has_failed } }
|
||||
|
||||
it "catches :task_has_failed" do
|
||||
expect { subject.run_supervised_task(@g, :failing) }.to_not throw_symbol(:task_has_failed)
|
||||
end
|
||||
it "throws :task_has_failed" do
|
||||
expect { subject.supervised_task(@g, :failing) }.to throw_symbol(:task_has_failed)
|
||||
end
|
||||
end
|
||||
|
||||
context "with a task that raises an exception" do
|
||||
before(:each) { @g.stub!(:group) { :foo }; @g.stub!(:failing) { raise "I break your system" } }
|
||||
before(:each) { @g.stub!(:failing) { raise "I break your system" } }
|
||||
|
||||
it "fires the Guard" do
|
||||
lambda { subject.run_supervised_task(@g, :failing) }.should change(subject.guards, :size).by(-1)
|
||||
lambda { subject.supervised_task(@g, :failing) }.should change(subject.guards, :size).by(-1)
|
||||
subject.guards.should_not include(@g)
|
||||
end
|
||||
|
||||
it "returns the exception" do
|
||||
failing_result = ::Guard.run_supervised_task(@g, :failing)
|
||||
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
|
||||
|
||||
describe '.guard_symbol' do
|
||||
let(:guard) { mock(Guard::Guard).as_null_object }
|
||||
|
||||
it 'returns :task_has_failed when the group is missing' do
|
||||
subject.guard_symbol(guard).should eql :task_has_failed
|
||||
end
|
||||
|
||||
context 'for a group with :halt_on_fail' do
|
||||
let(:group) { mock(Guard::Group) }
|
||||
|
||||
before do
|
||||
guard.stub(:group).and_return :foo
|
||||
group.stub(:options).and_return({ :halt_on_fail => true })
|
||||
end
|
||||
|
||||
it 'returns :no_catch' do
|
||||
subject.should_receive(:groups).with(:foo).and_return group
|
||||
subject.guard_symbol(guard).should eql :no_catch
|
||||
end
|
||||
end
|
||||
|
||||
context 'for a group without :halt_on_fail' do
|
||||
let(:group) { mock(Guard::Group) }
|
||||
|
||||
before do
|
||||
guard.stub(:group).and_return :foo
|
||||
group.stub(:options).and_return({ :halt_on_fail => false })
|
||||
end
|
||||
|
||||
it 'returns :task_has_failed' do
|
||||
subject.should_receive(:groups).with(:foo).and_return group
|
||||
subject.guard_symbol(guard).should eql :task_has_failed
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".debug_command_execution" do
|
||||
subject { ::Guard.setup }
|
||||
|
||||
|
@ -1,225 +1,139 @@
|
||||
private
|
||||
|
||||
# Set the sleep time around start/stop the listener. This defaults
|
||||
# to one second but can be overridden by setting the environment
|
||||
# variable `GUARD_SLEEP`.
|
||||
#
|
||||
def sleep_time
|
||||
@sleep_time ||= ENV['GUARD_SLEEP'] ? ENV['GUARD_SLEEP'].to_f : 1
|
||||
end
|
||||
|
||||
# Make the spec listen to a specific listener.
|
||||
# This automatically starts to record results for the supplied listener.
|
||||
#
|
||||
# @param [Guard::Listener] listener the Guard listener
|
||||
#
|
||||
def listen_to(listener)
|
||||
@listener = listener
|
||||
record_results
|
||||
end
|
||||
|
||||
# Start the listener. Normally you use {#watch} to wrap
|
||||
# the code block that should be listen to instead of starting
|
||||
# it manually.
|
||||
#
|
||||
def start
|
||||
sleep(sleep_time)
|
||||
sleep(@rest_delay || 1)
|
||||
@listener.update_last_event
|
||||
Thread.new { @listener.start }
|
||||
sleep(sleep_time)
|
||||
sleep(@rest_delay || 1)
|
||||
end
|
||||
|
||||
# Stop the listener. Normally you use {#watch} to wrap
|
||||
# the code block that should be listen to instead of stopping
|
||||
# it manually.
|
||||
#
|
||||
def stop
|
||||
sleep(sleep_time)
|
||||
@listener.stop
|
||||
sleep(sleep_time)
|
||||
end
|
||||
|
||||
# Watch file changes in a code block.
|
||||
#
|
||||
# @example Watch file changes
|
||||
# watch do
|
||||
# File.mv file1, file2
|
||||
# end
|
||||
#
|
||||
# @yield The block to listen for file changes
|
||||
#
|
||||
def watch
|
||||
start
|
||||
yield if block_given?
|
||||
stop
|
||||
end
|
||||
|
||||
# Start recording results from the current listener.
|
||||
# You may want to use {#listen_to} to set a listener
|
||||
# instead of set it up manually.
|
||||
#
|
||||
def record_results
|
||||
# Don't fail specs due to editor swap files, etc.
|
||||
noise = %r|\.sw.$|
|
||||
@results = []
|
||||
noise = %r|\.sw.$| # don't fail specs due to editor swap files, etc.
|
||||
|
||||
@results = []
|
||||
@listener.on_change do |files|
|
||||
@results += files.reject { |f| f =~ noise }
|
||||
end
|
||||
end
|
||||
|
||||
# Get the recorded result from the listener.
|
||||
#
|
||||
# @return [Array<String>] the result files
|
||||
#
|
||||
def stop
|
||||
sleep(@rest_delay || 1)
|
||||
@listener.stop
|
||||
sleep(@rest_delay || 1)
|
||||
end
|
||||
|
||||
def results
|
||||
@results.flatten
|
||||
end
|
||||
|
||||
# Define a file absolute to the fixture path.
|
||||
#
|
||||
# @param [String, Array<String>] file the relative file name, separated by segment
|
||||
# @return [String] the absolute file
|
||||
#
|
||||
def fixture(*file)
|
||||
@fixture_path.join(*file)
|
||||
shared_examples_for 'a listener that reacts to #on_change' do |rest_delay|
|
||||
before(:each) do
|
||||
@rest_delay = rest_delay if rest_delay.is_a?(Integer) || rest_delay.is_a?(Float) # jruby workaround
|
||||
@listener = described_class.new
|
||||
record_results
|
||||
end
|
||||
|
||||
shared_examples_for 'a listener that reacts to #on_change' do
|
||||
before do
|
||||
listen_to described_class.new
|
||||
end
|
||||
|
||||
context 'for a new file' do
|
||||
let(:file) { fixture('newfile.rb') }
|
||||
|
||||
before { File.delete(file) if File.exists?(file) }
|
||||
after { File.delete file }
|
||||
|
||||
it 'catches the new file' do
|
||||
File.exists?(file).should be_false
|
||||
|
||||
watch do
|
||||
FileUtils.touch file
|
||||
end
|
||||
|
||||
results.should =~ ['spec/fixtures/newfile.rb']
|
||||
end
|
||||
end
|
||||
|
||||
context 'for a single file update' do
|
||||
let(:file) { fixture('folder1', 'file1.txt') }
|
||||
|
||||
it 'catches the update' do
|
||||
File.exists?(file).should be_true
|
||||
|
||||
watch do
|
||||
File.open(file, 'w') { |f| f.write('') }
|
||||
end
|
||||
|
||||
results.should =~ ['spec/fixtures/folder1/file1.txt']
|
||||
end
|
||||
end
|
||||
|
||||
context 'for a single file chmod update' do
|
||||
let(:file) { fixture('folder1/file1.txt') }
|
||||
|
||||
it 'does not catch the update' do
|
||||
File.exists?(file).should be_true
|
||||
|
||||
watch do
|
||||
File.chmod(0777, file)
|
||||
end
|
||||
|
||||
results.should =~ []
|
||||
end
|
||||
end
|
||||
|
||||
context 'for a dotfile update' do
|
||||
let(:file) { fixture('.dotfile') }
|
||||
|
||||
it "catches the update" do
|
||||
File.exists?(file).should be_true
|
||||
|
||||
watch do
|
||||
File.open(file, 'w') { |f| f.write('') }
|
||||
end
|
||||
|
||||
results.should =~ ['spec/fixtures/.dotfile']
|
||||
end
|
||||
end
|
||||
|
||||
context 'for multiple file updates' do
|
||||
let(:file1) { fixture('folder1', 'file1.txt') }
|
||||
let(:file2) { fixture('folder1', 'folder2', 'file2.txt') }
|
||||
|
||||
it 'catches the updates' do
|
||||
File.exists?(file1).should be_true
|
||||
File.exists?(file2).should be_true
|
||||
|
||||
watch do
|
||||
File.open(file1, 'w') { |f| f.write('') }
|
||||
File.open(file2, 'w') { |f| f.write('') }
|
||||
end
|
||||
|
||||
results.should =~ ['spec/fixtures/folder1/file1.txt', 'spec/fixtures/folder1/folder2/file2.txt']
|
||||
end
|
||||
end
|
||||
|
||||
context 'for a deleted file' do
|
||||
let(:file) { fixture('folder1', 'file1.txt') }
|
||||
|
||||
after { FileUtils.touch file }
|
||||
|
||||
it 'does not catch the deletion' do
|
||||
File.exists?(file).should be_true
|
||||
|
||||
watch do
|
||||
it "catches a new file" do
|
||||
file = @fixture_path.join("newfile.rb")
|
||||
if File.exists?(file)
|
||||
begin
|
||||
File.delete file
|
||||
rescue
|
||||
end
|
||||
|
||||
results.should =~ []
|
||||
end
|
||||
File.exists?(file).should be_false
|
||||
start
|
||||
FileUtils.touch file
|
||||
stop
|
||||
begin
|
||||
File.delete file
|
||||
rescue
|
||||
end
|
||||
results.should =~ ['spec/fixtures/newfile.rb']
|
||||
end
|
||||
|
||||
context 'for a moved file' do
|
||||
let(:file1) { fixture('folder1', 'file1.txt') }
|
||||
let(:file2) { fixture('folder1', 'movedfile1.txt') }
|
||||
|
||||
after { FileUtils.mv file2, file1 }
|
||||
|
||||
it 'does not catch the move' do
|
||||
File.exists?(file1).should be_true
|
||||
File.exists?(file2).should be_false
|
||||
|
||||
watch do
|
||||
FileUtils.mv file1, file2
|
||||
end
|
||||
|
||||
results.should =~ []
|
||||
end
|
||||
it "catches a single file update" do
|
||||
file = @fixture_path.join("folder1/file1.txt")
|
||||
File.exists?(file).should be_true
|
||||
start
|
||||
File.open(file, 'w') { |f| f.write('') }
|
||||
stop
|
||||
results.should =~ ['spec/fixtures/folder1/file1.txt']
|
||||
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
|
||||
file = @fixture_path.join(".dotfile")
|
||||
File.exists?(file).should be_true
|
||||
start
|
||||
File.open(file, 'w') { |f| f.write('') }
|
||||
stop
|
||||
results.should =~ ['spec/fixtures/.dotfile']
|
||||
end
|
||||
|
||||
it "catches multiple file updates" do
|
||||
file1 = @fixture_path.join("folder1/file1.txt")
|
||||
file2 = @fixture_path.join("folder1/folder2/file2.txt")
|
||||
File.exists?(file1).should be_true
|
||||
File.exists?(file2).should be_true
|
||||
start
|
||||
File.open(file1, 'w') { |f| f.write('') }
|
||||
File.open(file2, 'w') { |f| f.write('') }
|
||||
stop
|
||||
results.should =~ ['spec/fixtures/folder1/file1.txt', 'spec/fixtures/folder1/folder2/file2.txt']
|
||||
end
|
||||
|
||||
it "not catches a deleted file" do
|
||||
file = @fixture_path.join("folder1/file1.txt")
|
||||
File.exists?(file).should be_true
|
||||
start
|
||||
File.delete file
|
||||
stop
|
||||
FileUtils.touch file
|
||||
results.should =~ []
|
||||
end
|
||||
|
||||
it "not catches a moved file" do
|
||||
file1 = @fixture_path.join("folder1/file1.txt")
|
||||
file2 = @fixture_path.join("folder1/movedfile1.txt")
|
||||
File.exists?(file1).should be_true
|
||||
File.exists?(file2).should be_false
|
||||
start
|
||||
FileUtils.mv file1, file2
|
||||
stop
|
||||
FileUtils.mv file2, file1
|
||||
results.should =~ []
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
shared_examples_for "a listener scoped to a specific directory" do
|
||||
shared_examples_for "a listener scoped to a specific directory" do |rest_delay|
|
||||
before :each do
|
||||
@rest_delay = rest_delay if rest_delay.is_a?(Integer) || rest_delay.is_a?(Float) # jruby workaround
|
||||
@wd = @fixture_path.join("folder1")
|
||||
@listener = described_class.new @wd
|
||||
end
|
||||
|
||||
let(:work_directory) { fixture('folder1') }
|
||||
|
||||
let(:new_file) { work_directory.join('folder2', 'newfile.rb') }
|
||||
let(:modified) { work_directory.join('file1.txt') }
|
||||
|
||||
before { listen_to described_class.new(work_directory) }
|
||||
after { File.delete new_file }
|
||||
|
||||
it 'should base paths within this directory' do
|
||||
it "should base paths within this directory" do
|
||||
record_results
|
||||
new_file = @wd.join("folder2/newfile.rb")
|
||||
modified = @wd.join("file1.txt")
|
||||
File.exists?(modified).should be_true
|
||||
File.exists?(new_file).should be_false
|
||||
|
||||
watch do
|
||||
FileUtils.touch new_file
|
||||
File.open(modified, 'w') { |f| f.write('') }
|
||||
end
|
||||
|
||||
results.should =~ ['folder2/newfile.rb', 'file1.txt']
|
||||
start
|
||||
FileUtils.touch new_file
|
||||
File.open(modified, 'w') { |f| f.write('') }
|
||||
stop
|
||||
File.delete new_file
|
||||
results.should =~ ["folder2/newfile.rb", 'file1.txt']
|
||||
end
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user