guard 0.6.3 → 0.7.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,9 +1,25 @@
1
+ ## 0.7.0.rc1 - September 5, 2011
2
+
3
+ ### Major Changes
4
+
5
+ - 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][])
6
+ - JRuby & Rubinius support (beta). ([@thibaudgg][] and [@netzpirat][])
7
+
8
+ ### New feature:
9
+
10
+ - 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][])
11
+ - Ability to 'pause' files modification listening. Please refer to the "Interactions" section in the README for more information. ([@thibaudgg][])
12
+
13
+ ### Improvement:
14
+
15
+ - Remove the need to scan the whole directory after guard's `run_on_change` method. ([@thibaudgg][])
16
+
1
17
  ## 0.6.3 - September 1, 2011
2
18
 
3
19
  ### New features:
4
20
 
5
- - Pull request [#130](https://github.com/guard/guard/pull/130): Adds ignore_paths option to DSL. ([@ianwhite][])
6
- - Pull request [#128](https://github.com/guard/guard/pull/128): Users can add additional settings to ~/.guard.rb that augment the existing Guardfile. ([@tpope][])
21
+ - Pull request [#130](https://github.com/guard/guard/pull/130): Adds `ignore_paths` method to DSL. ([@ianwhite][])
22
+ - Pull request [#128](https://github.com/guard/guard/pull/128): Users can add additional settings to `~/.guard.rb` that augment the existing Guardfile. ([@tpope][])
7
23
 
8
24
  ## 0.6.2 - August 17, 2011
9
25
 
@@ -14,7 +30,7 @@
14
30
 
15
31
  ### New features:
16
32
 
17
- - Groups are now stored in a @groups variable (will be used for future features). ([@rymai][])
33
+ - Groups are now stored in a `@groups` variable (will be used for future features). ([@rymai][])
18
34
  - Guards will now receive their group in the options hash at initialization (will be used for future features). ([@rymai][])
19
35
 
20
36
  ### Improvement:
@@ -25,15 +41,15 @@
25
41
 
26
42
  ### Bugs fixes:
27
43
 
28
- - Pull request [#120](https://github.com/guard/guard/pull/120): remove guardfile_contents when re-evaluating so that the Guardfile gets reloaded correctly. ([@mordaroso][])
29
- - Pull request [#119](https://github.com/guard/guard/pull/119): Dsl.evaluate_guardfile uses all groups if none specified. ([@ches][])
44
+ - Pull request [#120](https://github.com/guard/guard/pull/120): remove `guardfile_contents` when re-evaluating so that the Guardfile gets reloaded correctly. ([@mordaroso][])
45
+ - Pull request [#119](https://github.com/guard/guard/pull/119): `Dsl.evaluate_guardfile` uses all groups if none specified. ([@ches][])
30
46
 
31
47
  ## 0.6.0 - August 13, 2011
32
48
 
33
49
  ### Bugs fixes:
34
50
 
35
51
  - Pull request [#107](https://github.com/guard/guard/pull/107): Small spelling fix. ([@dnagir][])
36
- - Dir.glob now ignores files that don't need to be watched. ([@rymai][])
52
+ - `Dir.glob` now ignores files that don't need to be watched. ([@rymai][])
37
53
 
38
54
  ### New features:
39
55
 
@@ -42,7 +58,7 @@
42
58
  ### Improvements:
43
59
 
44
60
  - Pull request [#99](https://github.com/guard/guard/pull/99): [OS X] Switch from growl gem to growl_notify gem. ([@johnbintz][])
45
- - Pull request [#115](https://github.com/guard/guard/pull/115): [Linux] Add ':transient => true' to default libnotify options. ([@zonque][])
61
+ - Pull request [#115](https://github.com/guard/guard/pull/115): [Linux] Add `:transient => true` to default libnotify options. ([@zonque][])
46
62
  - 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][])
47
63
  - `Guard::Dsl.revaluate_guardfile` has been renamed to `Guard::Dsl.reevaluate_guardfile`. ([@rymai][])
48
64
  - New CLI options: ([@nestegg][])
@@ -233,6 +249,7 @@
233
249
  [@Gazer]: https://github.com/Gazer
234
250
  [@gix]: https://github.com/gix
235
251
  [@hashrocketeer]: https://github.com/hashrocketeer
252
+ [@ianwhite]: https://github.com/ianwhite
236
253
  [@indirect]: https://github.com/indirect
237
254
  [@jeffutter]: https://github.com/jeffutter
238
255
  [@johnbintz]: https://github.com/johnbintz
@@ -240,6 +257,7 @@
240
257
  [@koshigoe]: https://github.com/koshigoe
241
258
  [@mcmire]: https://github.com/mcmire
242
259
  [@mislav]: https://github.com/mislav
260
+ [@monocle]: https://github.com/monocle
243
261
  [@mordaroso]: https://github.com/mordaroso
244
262
  [@nestegg]: https://github.com/nestegg
245
263
  [@netzpirat]: https://github.com/netzpirat
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- Guard [![Build Status](https://travis-ci.org/guard/guard.png)](http://travis-ci.org/guard/guard)
1
+ Guard [![Build Status](http://travis-ci.org/guard/guard.png)](http://travis-ci.org/guard/guard)
2
2
  =====
3
3
 
4
4
  Guard is a command line tool that easily handle events on files modifications.
@@ -13,14 +13,13 @@ Features
13
13
  * [Directory Change Notification](http://msdn.microsoft.com/en-us/library/aa365261\(VS.85\).aspx) support on Windows ([rb-fchange, >= 0.0.2](https://rubygems.org/gems/rb-fchange) required).
14
14
  * Polling on the other operating systems (help us to support more OS).
15
15
  * Automatic & Super fast (when polling is not used) files modifications detection (even new files are detected).
16
- * Growl notifications ([growl_notify gem](https://rubygems.org/gems/growl_notify) or [growlnotify](http://growl.info/documentation/growlnotify.php) & [growl gem](https://rubygems.org/gems/growl) required).
17
- * Libnotify notifications ([libnotify gem](https://rubygems.org/gems/libnotify) required).
18
- * Tested against Ruby 1.8.7, 1.9.2 and REE.
16
+ * Visual notifications on Mac OSX ([Growl](http://growl.info)), Linux ([Libnotify](http://developer.gnome.org/libnotify)) and Windows ([Notifu](http://www.paralint.com/projects/notifu)).
17
+ * Tested against Ruby 1.8.7, 1.9.2, REE and the latest versions of JRuby & Rubinius.
19
18
 
20
19
  Screencast
21
20
  ----------
22
21
 
23
- Ryan Bates made a screencast on Guard, you can view it here: http://railscasts.com/episodes/264-guard
22
+ Ryan Bates made a Railscast on Guard, you can view it here: http://railscasts.com/episodes/264-guard
24
23
 
25
24
  Install
26
25
  -------
@@ -31,12 +30,18 @@ Install the gem:
31
30
  $ gem install guard
32
31
  ```
33
32
 
34
- Add it to your Gemfile (inside the `development` group):
33
+ Or add it to your Gemfile (inside the `development` group):
35
34
 
36
35
  ``` ruby
37
36
  gem 'guard'
38
37
  ```
39
38
 
39
+ and install it via Bundler:
40
+
41
+ ``` bash
42
+ $ bundle install
43
+ ```
44
+
40
45
  Generate an empty Guardfile with:
41
46
 
42
47
  ``` bash
@@ -44,6 +49,7 @@ $ guard init
44
49
  ```
45
50
 
46
51
  You may optionally place a .Guardfile in your home directory to use it across multiple projects.
52
+ Also note that if a `.guard.rb` is found in your home directory, it will be appended to the Guardfile.
47
53
 
48
54
  Add the guards you need to your Guardfile (see the existing guards below).
49
55
 
@@ -55,11 +61,18 @@ Install the rb-fsevent gem for [FSEvent](http://en.wikipedia.org/wiki/FSEvents)
55
61
  $ gem install rb-fsevent
56
62
  ```
57
63
 
58
- Install either the growl_notify or the growl gem if you want notification support:
64
+ You have two possibilities:
65
+
66
+ Use the [growl_notify gem](https://rubygems.org/gems/growl_notify) (recommended):
59
67
 
60
68
  ``` bash
61
69
  $ gem install growl_notify
62
- $ # or
70
+ ```
71
+
72
+ Use the [growlnotify](http://growl.info/extras.php#growlnotify) (cli tool for growl) + the [growl gem](https://rubygems.org/gems/growl).
73
+
74
+ ``` bash
75
+ $ brew install growlnotify
63
76
  $ gem install growl
64
77
  ```
65
78
 
@@ -67,22 +80,23 @@ And add them to your Gemfile:
67
80
 
68
81
  ``` ruby
69
82
  gem 'rb-fsevent'
70
- gem 'growl'
83
+ gem 'growl_notify' # or gem 'growl'
71
84
  ```
72
85
 
73
- The difference between growl and growl_notify is that growl_notify uses AppleScript to
86
+ The difference between growl and growl_notify is that growl_notify uses AppleScript to
74
87
  display a message, whereas growl uses the `growlnotify` command. In general the AppleScript
75
- approach is preferred, but this is currently known to not work in conjunction with Spork.
88
+ approach is preferred, but you may also use the older growl gem. Have a look at the
89
+ [Guard Wiki](https://github.com/guard/guard/wiki/Use-growl_notify-or-growl-gem) for more information.
76
90
 
77
91
  ### On Linux
78
92
 
79
- Install the rb-inotify gem for [inotify](http://en.wikipedia.org/wiki/Inotify) support:
93
+ Install the [rb-inotify gem](https://rubygems.org/gems/rb-inotify) for [inotify](http://en.wikipedia.org/wiki/Inotify) support:
80
94
 
81
95
  ``` bash
82
96
  $ gem install rb-inotify
83
97
  ```
84
98
 
85
- Install the Libnotify gem if you want notification support:
99
+ Install the [libnotify gem](https://rubygems.org/gems/libnotify) if you want visual notification support:
86
100
 
87
101
  ``` bash
88
102
  $ gem install libnotify
@@ -97,19 +111,19 @@ gem 'libnotify'
97
111
 
98
112
  ### On Windows
99
113
 
100
- Install the rb-fchange gem for [Directory Change Notification](http://msdn.microsoft.com/en-us/library/aa365261\(VS.85\).aspx) support:
114
+ 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:
101
115
 
102
116
  ``` bash
103
117
  $ gem install rb-fchange
104
118
  ```
105
119
 
106
- Install the win32console gem if you want colors in your terminal:
120
+ Install the [win32console gem](https://rubygems.org/gems/win32console) if you want colors in your terminal:
107
121
 
108
122
  ``` bash
109
123
  $ gem install win32console
110
124
  ```
111
125
 
112
- Install the Notifu gem if you want notification support:
126
+ Install the [rb-notifu gem](https://rubygems.org/gems/rb-notifu) if you want visual notification support:
113
127
 
114
128
  ``` bash
115
129
  $ gem install rb-notifu
@@ -120,6 +134,7 @@ And add them to your Gemfile:
120
134
  ``` ruby
121
135
  gem 'rb-fchange'
122
136
  gem 'rb-notifu'
137
+ gem 'win32console'
123
138
  ```
124
139
 
125
140
  Usage
@@ -204,16 +219,17 @@ An exhaustive list of options is available with:
204
219
  $ guard help [TASK]
205
220
  ```
206
221
 
207
- Signal handlers
208
- ---------------
222
+ Interactions
223
+ ------------
209
224
 
210
- Signal handlers are used to interact with Guard:
225
+ **From version >= 0.7.0 Posix Signal handlers are no more used to interact with Guard. If you're using a version < 0.7, please refer to the [README in the v0.6 branch](https://github.com/guard/guard/blob/v0.6/README.md).**
211
226
 
212
- * `Ctrl-C` - Calls each guard's `#stop` method, in the same order they are declared in the Guardfile, and then quits Guard itself.
213
- * `Ctrl-\` - Calls each guard's `#run_all` method, in the same order they are declared in the Guardfile.
214
- * `Ctrl-Z` - Calls each guard's `#reload` method, in the same order they are declared in the Guardfile.
227
+ When Guard do nothing you can interact with by entering a command + hitting enter:
215
228
 
216
- You can read more about [configure the signal keyboard shortcuts](https://github.com/guard/guard/wiki/Configure-keyboard-shortcuts) in the wiki.
229
+ * `stop|quit|exit|s|q|e + enter` - Calls each guard's `#stop` method, in the same order they are declared in the Guardfile, and then quits Guard itself.
230
+ * `reload|r|z + enter` - Calls each guard's `#reload` method, in the same order they are declared in the Guardfile.
231
+ * `pause|p + enter` - Toggle files modification listening. Useful when switching git branches.
232
+ * `just enter (no commands)` - Calls each guard's `#run_all` method, in the same order they are declared in the Guardfile.
217
233
 
218
234
  Available Guards
219
235
  ----------------
@@ -245,17 +261,13 @@ You are good to go, or you can modify your guards' definition to suit your needs
245
261
  Guardfile DSL
246
262
  -------------
247
263
 
248
- The Guardfile DSL consists of just three simple methods: `#guard`, `#watch` & `#group`.
249
-
250
- Required:
251
-
252
- * The `#guard` method allows you to add a guard with an optional hash of options.
264
+ The Guardfile DSL consists of the following methods:
253
265
 
254
- Optional:
255
-
256
- * The `#watch` method allows you to define which files are supervised by this guard. An optional block can be added to overwrite the paths sent to the guard's `#run_on_change` method or to launch any arbitrary command.
257
- * The `#group` method allows you to group several guards together. Groups to be run can be specified with the Guard DSL option `--group` (or `-g`). This comes in handy especially when you have a huge Guardfile and want to focus your development on a certain part. Guards that don't belong to a group are considered global and are always run.
258
- * The `#ignore_paths` method allows you to ignore top level directories altogether. This comes is handy when you have large amounts of non-source data in you project. By default .bundle, .git, log, tmp, and vendor are ignored. Currently it is only possible to ignore the immediate descendants of the watched directory.
266
+ * `#guard`: allows you to add a guard with an optional hash of options.
267
+ * `#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.
268
+ * `#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.
269
+ * `#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.
270
+ * `#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.
259
271
 
260
272
  Example:
261
273
 
@@ -290,7 +302,8 @@ group 'frontend' do
290
302
  end
291
303
  ```
292
304
 
293
- ### Using a Guardfile without the `guard` binary
305
+ Using a Guardfile without the `guard` binary
306
+ --------------------------------------------
294
307
 
295
308
  The Guardfile DSL can also be used in a programmatic fashion by calling directly `Guard::Dsl.evaluate_guardfile`.
296
309
  Available options are as follow:
@@ -337,7 +350,7 @@ Group frontend:
337
350
  User config file
338
351
  ----------------
339
352
 
340
- If a .guard.rb is found in your home directory, it will be appended to
353
+ If a `.guard.rb` is found in your home directory, it will be appended to
341
354
  the Guardfile. This can be used for tasks you want guard to handle but
342
355
  other users probably don't. For example, indexing your source tree with
343
356
  [Ctags](http://ctags.sourceforge.net):
@@ -346,7 +359,6 @@ other users probably don't. For example, indexing your source tree with
346
359
  guard 'shell' do
347
360
  watch(%r{^(?:app|lib)/.+\.rb$}) { `ctags -R` }
348
361
  end
349
-
350
362
  ```
351
363
 
352
364
  Create a new guard
@@ -454,7 +466,13 @@ Development
454
466
  * Source hosted at [GitHub](https://github.com/guard/guard).
455
467
  * Report issues and feature requests to [GitHub Issues](https://github.com/guard/guard/issues).
456
468
 
457
- Pull requests are very welcome! Make sure your patches are well tested. Please create a topic branch for every separate change you make. Please **do not change** the version in your pull-request.
469
+ Pull requests are very welcome! Please try to follow these simple "rules", though:
470
+
471
+ - Please create a topic branch for every separate change you make;
472
+ - Make sure your patches are well tested;
473
+ - Update the README (if applicable);
474
+ - Update the CHANGELOG (maybe not for a typo but don't hesitate!);
475
+ - Please **do not change** the version number.
458
476
 
459
477
  For questions please join us on our [Google group](http://groups.google.com/group/guard-dev) or on `#guard` (irc.freenode.net).
460
478
 
@@ -464,6 +482,6 @@ Author
464
482
  [Thibaud Guillaume-Gentil](https://github.com/thibaudgg)
465
483
 
466
484
  Contributors
467
- ------
485
+ ------------
468
486
 
469
487
  https://github.com/guard/guard/contributors
data/lib/guard.rb CHANGED
@@ -7,16 +7,18 @@ module Guard
7
7
  autoload :Listener, 'guard/listener'
8
8
  autoload :Watcher, 'guard/watcher'
9
9
  autoload :Notifier, 'guard/notifier'
10
+ autoload :Hook, 'guard/hook'
10
11
 
11
12
  class << self
12
- attr_accessor :options, :guards, :groups, :listener
13
+ attr_accessor :options, :guards, :groups, :interactor, :listener
13
14
 
14
15
  # initialize this singleton
15
16
  def setup(options = {})
16
- @options = options
17
- @listener = Listener.select_and_init(@options[:watchdir] ? File.expand_path(@options[:watchdir]) : Dir.pwd)
18
- @groups = [:default]
19
- @guards = []
17
+ @options = options
18
+ @guards = []
19
+ @groups = [:default]
20
+ @interactor = Interactor.new
21
+ @listener = Listener.select_and_init(@options[:watchdir] ? File.expand_path(@options[:watchdir]) : Dir.pwd)
20
22
 
21
23
  @options[:notify] && ENV["GUARD_NOTIFY"] != 'false' ? Notifier.turn_on : Notifier.turn_off
22
24
 
@@ -27,43 +29,83 @@ module Guard
27
29
  end
28
30
 
29
31
  def start(options = {})
30
- Interactor.init_signal_traps
31
-
32
32
  setup(options)
33
33
 
34
34
  Dsl.evaluate_guardfile(options)
35
35
 
36
36
  listener.on_change do |files|
37
- Dsl.reevaluate_guardfile if Watcher.match_guardfile?(files)
38
-
39
- run { run_on_change_for_all_guards(files) } if Watcher.match_files?(guards, files)
37
+ Dsl.reevaluate_guardfile if Watcher.match_guardfile?(files)
38
+ listener.changed_files += files if Watcher.match_files?(guards, files)
40
39
  end
41
40
 
42
41
  UI.info "Guard is now watching at '#{listener.directory}'"
43
42
  guards.each { |guard| supervised_task(guard, :start) }
43
+
44
+ interactor.start
44
45
  listener.start
45
46
  end
46
47
 
47
- def run_on_change_for_all_guards(files)
48
- guards.each do |guard|
49
- paths = Watcher.match_files(guard, files)
50
- unless paths.empty?
51
- UI.debug "#{guard.class.name}#run_on_change with #{paths.inspect}"
52
- supervised_task(guard, :run_on_change, paths)
48
+ def stop
49
+ UI.info "Bye bye...", :reset => true
50
+ listener.stop
51
+ guards.each { |guard| supervised_task(guard, :stop) }
52
+ abort
53
+ end
54
+
55
+ def reload
56
+ run do
57
+ guards.each { |guard| supervised_task(guard, :reload) }
58
+ end
59
+ end
60
+
61
+ def run_all
62
+ run do
63
+ guards.each { |guard| supervised_task(guard, :run_all) }
64
+ end
65
+ end
66
+
67
+ def pause
68
+ if listener.locked
69
+ UI.info "Un-paused files modification listening", :reset => true
70
+ listener.clear_changed_files
71
+ listener.unlock
72
+ else
73
+ UI.info "Paused files modification listening", :reset => true
74
+ listener.lock
75
+ end
76
+ end
77
+
78
+ def run_on_change(files)
79
+ run do
80
+ guards.each do |guard|
81
+ paths = Watcher.match_files(guard, files)
82
+ unless paths.empty?
83
+ UI.debug "#{guard.class.name}#run_on_change with #{paths.inspect}"
84
+ supervised_task(guard, :run_on_change, paths)
85
+ end
53
86
  end
54
87
  end
88
+ end
55
89
 
56
- # Reparse the whole directory to catch new files modified during the guards run
57
- new_modified_files = listener.modified_files([listener.directory], :all => true)
58
- if !new_modified_files.empty? && Watcher.match_files?(guards, new_modified_files)
59
- run { run_on_change_for_all_guards(new_modified_files) }
90
+ def run
91
+ listener.lock
92
+ interactor.lock
93
+ UI.clear if options[:clear]
94
+ begin
95
+ yield
96
+ rescue Interrupt
60
97
  end
98
+ interactor.unlock
99
+ listener.unlock
61
100
  end
62
101
 
63
102
  # Let a guard execute its task but
64
103
  # fire it if his work leads to a system failure
65
104
  def supervised_task(guard, task_to_supervise, *args)
66
- guard.send(task_to_supervise, *args)
105
+ guard.hook("#{task_to_supervise}_begin", *args)
106
+ result = guard.send(task_to_supervise, *args)
107
+ guard.hook("#{task_to_supervise}_end", result)
108
+ result
67
109
  rescue Exception => ex
68
110
  UI.error("#{guard.class.name} failed to achieve its <#{task_to_supervise.to_s}>, exception was:" +
69
111
  "\n#{ex.class}: #{ex.message}\n#{ex.backtrace.join("\n")}")
@@ -72,22 +114,13 @@ module Guard
72
114
  return ex
73
115
  end
74
116
 
75
- def run
76
- listener.stop
77
- UI.clear if options[:clear]
78
- begin
79
- yield
80
- rescue Interrupt
81
- end
82
- listener.start
83
- end
84
-
85
- def add_guard(name, watchers = [], options = {})
117
+ def add_guard(name, watchers = [], callbacks = [], options = {})
86
118
  if name.to_sym == :ego
87
119
  UI.deprecation("Guard::Ego is now part of Guard. You can remove it from your Guardfile.")
88
120
  else
89
- guard = get_guard_class(name).new(watchers, options)
90
- @guards << guard
121
+ guard_class = get_guard_class(name)
122
+ callbacks.each { |callback| Hook.add_callback(callback[:listener], guard_class, callback[:events]) }
123
+ @guards << guard_class.new(watchers, options)
91
124
  end
92
125
  end
93
126