guard 1.0.3 → 1.1.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +0 -6
- data/README.md +38 -30
- data/lib/guard.rb +158 -285
- data/lib/guard/cli.rb +16 -2
- data/lib/guard/dsl.rb +41 -20
- data/lib/guard/dsl_describer.rb +1 -1
- data/lib/guard/group.rb +1 -1
- data/lib/guard/guard.rb +39 -5
- data/lib/guard/guardfile.rb +70 -0
- data/lib/guard/runner.rb +179 -0
- data/lib/guard/ui.rb +1 -1
- data/lib/guard/version.rb +2 -4
- data/lib/guard/watcher.rb +1 -0
- metadata +16 -77
- data/bin/fsevent_watch_guard_guard +0 -0
- data/lib/guard/listener.rb +0 -376
- data/lib/guard/listeners/darwin.rb +0 -62
- data/lib/guard/listeners/linux.rb +0 -93
- data/lib/guard/listeners/polling.rb +0 -55
- data/lib/guard/listeners/windows.rb +0 -63
- data/lib/vendor/darwin/Gemfile +0 -6
- data/lib/vendor/darwin/Guardfile +0 -8
- data/lib/vendor/darwin/LICENSE +0 -20
- data/lib/vendor/darwin/README.rdoc +0 -255
- data/lib/vendor/darwin/Rakefile +0 -21
- data/lib/vendor/darwin/bin/fsevent_watch +0 -0
- data/lib/vendor/darwin/ext/fsevent_watch/Info.plist +0 -38
- data/lib/vendor/darwin/ext/fsevent_watch/LICENSE +0 -21
- data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch.xcodeproj/project.pbxproj +0 -254
- data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/TSICTString.c +0 -394
- data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/TSICTString.h +0 -74
- data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/cli.c +0 -160
- data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/cli.h +0 -45
- data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/common.h +0 -34
- data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/compat.c +0 -20
- data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/compat.h +0 -40
- data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/main.c +0 -509
- data/lib/vendor/darwin/ext/fsevent_watch/xcconfig/Common.xcconfig +0 -82
- data/lib/vendor/darwin/ext/fsevent_watch/xcconfig/Debug.xcconfig +0 -19
- data/lib/vendor/darwin/ext/fsevent_watch/xcconfig/Release.xcconfig +0 -23
- data/lib/vendor/darwin/ext/fsevent_watch/xcconfig/fsevent_watch.xcconfig +0 -17
- data/lib/vendor/darwin/ext/rakefile.rb +0 -47
- data/lib/vendor/darwin/ext/rb-fsevent.xcconfig +0 -33
- data/lib/vendor/darwin/lib/rb-fsevent.rb +0 -2
- data/lib/vendor/darwin/lib/rb-fsevent/fsevent.rb +0 -111
- data/lib/vendor/darwin/lib/rb-fsevent/version.rb +0 -3
- data/lib/vendor/darwin/rb-fsevent.gemspec +0 -25
- data/lib/vendor/darwin/spec/fixtures/folder1/file1.txt +0 -0
- data/lib/vendor/darwin/spec/fixtures/folder1/folder2/file2.txt +0 -0
- data/lib/vendor/darwin/spec/rb-fsevent/fsevent_spec.rb +0 -88
- data/lib/vendor/darwin/spec/spec_helper.rb +0 -23
- data/lib/vendor/linux/MIT-LICENSE +0 -20
- data/lib/vendor/linux/README.md +0 -66
- data/lib/vendor/linux/Rakefile +0 -54
- data/lib/vendor/linux/VERSION +0 -1
- data/lib/vendor/linux/lib/rb-inotify.rb +0 -17
- data/lib/vendor/linux/lib/rb-inotify/event.rb +0 -139
- data/lib/vendor/linux/lib/rb-inotify/native.rb +0 -31
- data/lib/vendor/linux/lib/rb-inotify/native/flags.rb +0 -89
- data/lib/vendor/linux/lib/rb-inotify/notifier.rb +0 -308
- data/lib/vendor/linux/lib/rb-inotify/watcher.rb +0 -83
- data/lib/vendor/linux/rb-inotify.gemspec +0 -53
- data/lib/vendor/windows/Gemfile +0 -4
- data/lib/vendor/windows/README.md +0 -34
- data/lib/vendor/windows/Rakefile +0 -18
- data/lib/vendor/windows/lib/rb-fchange.rb +0 -14
- data/lib/vendor/windows/lib/rb-fchange/event.rb +0 -29
- data/lib/vendor/windows/lib/rb-fchange/native.rb +0 -45
- data/lib/vendor/windows/lib/rb-fchange/native/flags.rb +0 -78
- data/lib/vendor/windows/lib/rb-fchange/notifier.rb +0 -149
- data/lib/vendor/windows/lib/rb-fchange/version.rb +0 -3
- data/lib/vendor/windows/lib/rb-fchange/watcher.rb +0 -99
- data/lib/vendor/windows/rb-fchange.gemspec +0 -34
- data/lib/vendor/windows/spec/fixtures/folder1/file1.txt +0 -0
- data/lib/vendor/windows/spec/fixtures/folder1/folder2/file2.txt +0 -0
- data/lib/vendor/windows/spec/rb-fchange/fchange_spec.rb +0 -119
- data/lib/vendor/windows/spec/spec_helper.rb +0 -21
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -34,7 +34,8 @@ Contents
|
|
34
34
|
* [notification](#guardfile-dsl-notification)
|
35
35
|
* [interactor](#guardfile-dsl-interactor)
|
36
36
|
* [callback](#guardfile-dsl-callback)
|
37
|
-
* [
|
37
|
+
* [ignore](#guardfile-dsl-ignore)
|
38
|
+
* [filter](#guardfile-dsl-filter)
|
38
39
|
* [Example](#guardfile-dsl-example)
|
39
40
|
* [Shared configurations](#shared-configurations)
|
40
41
|
* [Advanced Linux system configuration](#advanced-linux-system-configuration)
|
@@ -47,13 +48,9 @@ Contents
|
|
47
48
|
Features
|
48
49
|
--------
|
49
50
|
|
50
|
-
* [
|
51
|
-
* [Inotify](http://en.wikipedia.org/wiki/Inotify) support on Linux.
|
52
|
-
* [Directory Change Notification](http://msdn.microsoft.com/en-us/library/aa365261\(VS.85\).aspx) support on Windows.
|
53
|
-
* Polling on the other operating systems.
|
54
|
-
* Automatic and super fast file modification detection when polling is not used.
|
55
|
-
Even new and deleted files are detected.
|
51
|
+
* File system changes handled by our awesome [Listen](https://github.com/guard/listen) gem.
|
56
52
|
* Support for visual system notifications.
|
53
|
+
* Huge ([more than 120](https://rubygems.org/search?query=guard-)) guard extensions eco-system.
|
57
54
|
* Tested against Ruby 1.8.7, 1.9.2, 1.9.3, REE and the latest versions of JRuby & Rubinius.
|
58
55
|
|
59
56
|
<a name="screencast" />
|
@@ -358,40 +355,40 @@ $ guard --guardfile ~/.your_global_guardfile
|
|
358
355
|
$ guard -G ~/.your_global_guardfile # shortcut
|
359
356
|
```
|
360
357
|
|
361
|
-
#### `-
|
358
|
+
#### `-i`/`--no-interactions` option
|
362
359
|
|
363
|
-
|
360
|
+
Turn off completely any Guard terminal interactions with:
|
364
361
|
|
365
362
|
```bash
|
366
|
-
$ guard start -
|
367
|
-
$ guard start --
|
363
|
+
$ guard start -i
|
364
|
+
$ guard start --no-interactions
|
368
365
|
```
|
369
366
|
|
370
|
-
#### `-
|
367
|
+
#### `-B`/`--no-bundler-warning` option
|
371
368
|
|
372
|
-
|
369
|
+
Skip Bundler warning when a Gemfile exists in the project directory but Guard is not run with Bundler.
|
373
370
|
|
374
371
|
```bash
|
375
|
-
$ guard start -
|
376
|
-
$ guard start --no-
|
372
|
+
$ guard start -B
|
373
|
+
$ guard start --no-bundler-warning
|
377
374
|
```
|
378
375
|
|
379
|
-
#### `-
|
376
|
+
#### `-l`/`--latency` option
|
380
377
|
|
381
|
-
|
378
|
+
Overwrite Listen default latency, usefull when your harddrive/system is slow.
|
382
379
|
|
383
380
|
```bash
|
384
|
-
$ guard start -
|
385
|
-
$ guard start --
|
381
|
+
$ guard start -l 1.5
|
382
|
+
$ guard start --latency 1.5
|
386
383
|
```
|
387
384
|
|
388
|
-
#### `-
|
385
|
+
#### `-p`/`--force-polling` option
|
389
386
|
|
390
|
-
|
387
|
+
Force Listen polling listener usage.
|
391
388
|
|
392
389
|
```bash
|
393
|
-
$ guard start -
|
394
|
-
$ guard start --
|
390
|
+
$ guard start -p
|
391
|
+
$ guard start --force-polling
|
395
392
|
```
|
396
393
|
|
397
394
|
<a name="usage-list" />
|
@@ -682,22 +679,33 @@ end
|
|
682
679
|
Please see the [hooks and callbacks](https://github.com/guard/guard/wiki/Hooks-and-callbacks) page in the Guard wiki for
|
683
680
|
more details.
|
684
681
|
|
685
|
-
<a name="guardfile-dsl-ignore
|
686
|
-
###
|
682
|
+
<a name="guardfile-dsl-ignore" />
|
683
|
+
### ignore
|
684
|
+
|
685
|
+
The `ignore` method allows you to ignore specific paths. This comes is handy when you have large
|
686
|
+
amounts of non-source data in you project. By default [`.rbx`, `.bundle`, `.git`, `.svn`, `log`, `tmp`, `vendor`](https://github.com/guard/listen/blob/master/lib/listen/directory_record.rb#L14) are ignored.
|
687
|
+
Please note that method only accept regexps. More on the [Listen README](https://github.com/guard/listen#the-patterns-for-filtering-and-ignoring-paths).
|
688
|
+
|
689
|
+
```ruby
|
690
|
+
ignore %r{^ignored/path/}, /public/
|
691
|
+
```
|
692
|
+
|
693
|
+
<a name="guardfile-dsl-filter" />
|
694
|
+
### filter
|
687
695
|
|
688
|
-
The `
|
689
|
-
|
690
|
-
Currently it is only possible to ignore the immediate descendants of the watched directory.
|
696
|
+
The `filter` method allows you to filter specific paths.
|
697
|
+
Please note that method only accept regexps. More on the [Listen README](https://github.com/guard/listen#the-patterns-for-filtering-and-ignoring-paths).
|
691
698
|
|
692
699
|
```ruby
|
693
|
-
|
700
|
+
filter /\.txt$/, /.*\.zip/
|
694
701
|
```
|
695
702
|
|
696
703
|
<a name="guardfile-dsl-example" />
|
697
704
|
### Example
|
698
705
|
|
699
706
|
```ruby
|
700
|
-
|
707
|
+
ignore %r{^ignored/path/}, /public/
|
708
|
+
filter /\.txt$/, /.*\.zip/
|
701
709
|
|
702
710
|
notification :growl_notify
|
703
711
|
notification :gntp, :host => '192.168.1.5'
|
data/lib/guard.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'thread'
|
2
|
+
require 'listen'
|
2
3
|
|
3
4
|
# Guard is the main module for all Guard related modules and classes.
|
4
5
|
# Also other Guard implementation should use this namespace.
|
@@ -6,13 +7,14 @@ require 'thread'
|
|
6
7
|
module Guard
|
7
8
|
|
8
9
|
autoload :UI, 'guard/ui'
|
10
|
+
autoload :Guardfile, 'guard/guardfile'
|
9
11
|
autoload :Dsl, 'guard/dsl'
|
10
12
|
autoload :DslDescriber, 'guard/dsl_describer'
|
11
13
|
autoload :Group, 'guard/group'
|
12
14
|
autoload :Interactor, 'guard/interactor'
|
13
|
-
autoload :Listener, 'guard/listener'
|
14
15
|
autoload :Watcher, 'guard/watcher'
|
15
16
|
autoload :Notifier, 'guard/notifier'
|
17
|
+
autoload :Runner, 'guard/runner'
|
16
18
|
autoload :Hook, 'guard/hook'
|
17
19
|
|
18
20
|
# The Guardfile template for `guard init`
|
@@ -21,63 +23,7 @@ module Guard
|
|
21
23
|
HOME_TEMPLATES = File.expand_path('~/.guard/templates')
|
22
24
|
|
23
25
|
class << self
|
24
|
-
attr_accessor :options, :interactor, :listener, :lock
|
25
|
-
|
26
|
-
# Creates the initial Guardfile template when it does not
|
27
|
-
# already exist.
|
28
|
-
#
|
29
|
-
# @see Guard::CLI.init
|
30
|
-
#
|
31
|
-
# @param [Hash] options The options for creating a Guardfile
|
32
|
-
# @option options [Boolean] :abort_on_existence Whether to abort or not when a Guardfile already exists
|
33
|
-
#
|
34
|
-
def create_guardfile(options = {})
|
35
|
-
if !File.exist?('Guardfile')
|
36
|
-
::Guard::UI.info "Writing new Guardfile to #{ Dir.pwd }/Guardfile"
|
37
|
-
FileUtils.cp(GUARDFILE_TEMPLATE, 'Guardfile')
|
38
|
-
elsif options[:abort_on_existence]
|
39
|
-
::Guard::UI.error "Guardfile already exists at #{ Dir.pwd }/Guardfile"
|
40
|
-
abort
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# Adds the Guardfile template of a Guard implementation
|
45
|
-
# to an existing Guardfile.
|
46
|
-
#
|
47
|
-
# @see Guard::CLI.init
|
48
|
-
#
|
49
|
-
# @param [String] guard_name the name of the Guard or template to initialize
|
50
|
-
#
|
51
|
-
def initialize_template(guard_name)
|
52
|
-
guard_class = ::Guard.get_guard_class(guard_name, true)
|
53
|
-
|
54
|
-
if guard_class
|
55
|
-
guard_class.init(guard_name)
|
56
|
-
elsif File.exist?(File.join(HOME_TEMPLATES, guard_name))
|
57
|
-
content = File.read('Guardfile')
|
58
|
-
template = File.read(File.join(HOME_TEMPLATES, guard_name))
|
59
|
-
|
60
|
-
File.open('Guardfile', 'wb') do |f|
|
61
|
-
f.puts(content)
|
62
|
-
f.puts("")
|
63
|
-
f.puts(template)
|
64
|
-
end
|
65
|
-
|
66
|
-
::Guard::UI.info "#{ guard_name } template added to Guardfile, feel free to edit it"
|
67
|
-
else
|
68
|
-
const_name = guard_name.downcase.gsub('-', '')
|
69
|
-
UI.error "Could not load 'guard/#{ guard_name.downcase }' or '~/.guard/templates/#{ guard_name.downcase }' or find class Guard::#{ const_name.capitalize }"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
# Adds the templates of all installed Guard implementations
|
74
|
-
# to an existing Guardfile.
|
75
|
-
#
|
76
|
-
# @see Guard::CLI.init
|
77
|
-
#
|
78
|
-
def initialize_all_templates
|
79
|
-
guard_gem_names.each {|g| initialize_template(g) }
|
80
|
-
end
|
26
|
+
attr_accessor :options, :interactor, :runner, :listener, :lock
|
81
27
|
|
82
28
|
# Initialize the Guard singleton:
|
83
29
|
#
|
@@ -91,98 +37,97 @@ module Guard
|
|
91
37
|
# @option options [Array<String>] group the list of groups to start
|
92
38
|
# @option options [String] watchdir the director to watch
|
93
39
|
# @option options [String] guardfile the path to the Guardfile
|
94
|
-
# @option options [Boolean] watch_all_modifications watches all file modifications if true
|
40
|
+
# @deprecated @option options [Boolean] watch_all_modifications watches all file modifications if true
|
41
|
+
# @deprecated @option options [Boolean] no_vendor ignore vendored dependencies
|
95
42
|
#
|
96
43
|
def setup(options = {})
|
97
44
|
@lock = Mutex.new
|
98
45
|
@options = options
|
99
|
-
@
|
100
|
-
|
101
|
-
@listener = Listener.select_and_init(options)
|
46
|
+
@watchdir = (options[:watchdir] && File.expand_path(options[:watchdir])) || Dir.pwd
|
47
|
+
@runner = Runner.new
|
102
48
|
|
103
|
-
|
104
|
-
|
105
|
-
end
|
49
|
+
UI.clear
|
50
|
+
deprecated_options_warning
|
106
51
|
|
107
|
-
|
108
|
-
|
109
|
-
|
52
|
+
setup_groups
|
53
|
+
setup_guards
|
54
|
+
setup_listener
|
55
|
+
setup_signal_traps
|
110
56
|
|
111
|
-
UI.clear if @options[:clear]
|
112
57
|
debug_command_execution if @options[:verbose]
|
113
58
|
|
59
|
+
Dsl.evaluate_guardfile(options)
|
60
|
+
UI.error 'No guards found in Guardfile, please add at least one.' if @guards.empty?
|
61
|
+
|
62
|
+
runner.deprecation_warning # Guard deprecation go here
|
63
|
+
|
64
|
+
setup_notifier
|
65
|
+
setup_interactor
|
66
|
+
|
114
67
|
self
|
115
68
|
end
|
116
69
|
|
117
|
-
#
|
70
|
+
# Initialize the groups array with the `:default` group.
|
118
71
|
#
|
119
72
|
# @see Guard.groups
|
120
73
|
#
|
121
|
-
|
122
|
-
|
123
|
-
|
74
|
+
def setup_groups
|
75
|
+
@groups = [Group.new(:default)]
|
76
|
+
end
|
77
|
+
|
78
|
+
# Initialize the guards array to an empty array.
|
124
79
|
#
|
125
|
-
# @
|
126
|
-
# Guard.guards(/rsp.+/)
|
80
|
+
# @see Guard.guards
|
127
81
|
#
|
128
|
-
|
129
|
-
|
82
|
+
def setup_guards
|
83
|
+
@guards = []
|
84
|
+
end
|
85
|
+
|
86
|
+
# Sets up traps to catch signlas used to control Guard.
|
130
87
|
#
|
131
|
-
#
|
132
|
-
#
|
88
|
+
# Currently two signals are cought:
|
89
|
+
# - `USR1` which pauses listening to changes.
|
90
|
+
# - `USR2` which resumes listening to changes.
|
133
91
|
#
|
134
|
-
def
|
135
|
-
|
92
|
+
def setup_signal_traps
|
93
|
+
if Signal.list.keys.include?('USR1')
|
94
|
+
Signal.trap('USR1') { ::Guard.pause unless @listener.paused? }
|
95
|
+
end
|
136
96
|
|
137
|
-
|
138
|
-
|
139
|
-
@guards.find { |guard| guard.class.to_s.downcase.sub('guard::', '') == filter.to_s.downcase.gsub('-', '') }
|
140
|
-
when Regexp
|
141
|
-
@guards.find_all { |guard| guard.class.to_s.downcase.sub('guard::', '') =~ filter }
|
142
|
-
when Hash
|
143
|
-
filter.inject(@guards) do |matches, (k, v)|
|
144
|
-
if k.to_sym == :name
|
145
|
-
matches.find_all { |guard| guard.class.to_s.downcase.sub('guard::', '') == v.to_s.downcase.gsub('-', '') }
|
146
|
-
else
|
147
|
-
matches.find_all { |guard| guard.send(k).to_sym == v.to_sym }
|
148
|
-
end
|
149
|
-
end
|
150
|
-
else
|
151
|
-
@guards
|
97
|
+
if Signal.list.keys.include?('USR2')
|
98
|
+
Signal.trap('USR2') { ::Guard.pause if @listener.paused? }
|
152
99
|
end
|
153
100
|
end
|
154
101
|
|
155
|
-
#
|
156
|
-
#
|
157
|
-
# @see Guard.guards
|
102
|
+
# Initializes the listener and registers a callback for changes.
|
158
103
|
#
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
# @example Filter groups by Regexp
|
164
|
-
# Guard.groups(/(back|front)end/)
|
165
|
-
#
|
166
|
-
# @param [String, Symbol, Regexp] filter the filter to apply to the Groups
|
167
|
-
# @return [Array<Group>] the filtered groups
|
168
|
-
#
|
169
|
-
def groups(filter = nil)
|
170
|
-
case filter
|
171
|
-
when String, Symbol
|
172
|
-
@groups.find { |group| group.name == filter.to_sym }
|
173
|
-
when Regexp
|
174
|
-
@groups.find_all { |group| group.name.to_s =~ filter }
|
175
|
-
else
|
176
|
-
@groups
|
104
|
+
def setup_listener
|
105
|
+
listener_callback = lambda do |modified, added, removed|
|
106
|
+
Dsl.reevaluate_guardfile if Watcher.match_guardfile?(modified)
|
107
|
+
runner.run_on_changes(modified, added, removed)
|
177
108
|
end
|
109
|
+
|
110
|
+
listener_options = { :relative_paths => true }
|
111
|
+
%w[latency force_polling].each do |option|
|
112
|
+
listener_options[option.to_sym] = options[option] if options.key?(option)
|
113
|
+
end
|
114
|
+
|
115
|
+
@listener = Listen.to(@watchdir, listener_options).change(&listener_callback)
|
178
116
|
end
|
179
117
|
|
180
|
-
#
|
118
|
+
# Enables or disables the notifier based on user's configurations.
|
181
119
|
#
|
182
|
-
|
120
|
+
def setup_notifier
|
121
|
+
options[:notify] && ENV['GUARD_NOTIFY'] != 'false' ? Notifier.turn_on : Notifier.turn_off
|
122
|
+
end
|
123
|
+
|
124
|
+
# Initializes the interactor unless the user has specified not to.
|
183
125
|
#
|
184
|
-
def
|
185
|
-
|
126
|
+
def setup_interactor
|
127
|
+
unless options[:no_interactions]
|
128
|
+
@interactor = Interactor.fabricate
|
129
|
+
@interactor.start if @interactor
|
130
|
+
end
|
186
131
|
end
|
187
132
|
|
188
133
|
# Start Guard by evaluate the `Guardfile`, initialize the declared Guards
|
@@ -204,40 +149,20 @@ module Guard
|
|
204
149
|
#
|
205
150
|
def start(options = {})
|
206
151
|
setup(options)
|
152
|
+
UI.info "Guard is now watching at '#{ @watchdir }'"
|
207
153
|
|
208
|
-
|
209
|
-
UI.error 'No guards found in Guardfile, please add at least one.' if ::Guard.guards.empty?
|
210
|
-
|
211
|
-
options[:notify] && ENV['GUARD_NOTIFY'] != 'false' ? Notifier.turn_on : Notifier.turn_off
|
212
|
-
|
213
|
-
listener.on_change do |files|
|
214
|
-
Dsl.reevaluate_guardfile if Watcher.match_guardfile?(files)
|
215
|
-
listener.changed_files += files if Watcher.match_files?(guards, files)
|
216
|
-
end
|
217
|
-
|
218
|
-
UI.info "Guard is now watching at '#{ listener.directory }'"
|
219
|
-
|
220
|
-
run_on_guards do |guard|
|
221
|
-
run_supervised_task(guard, :start)
|
222
|
-
end
|
223
|
-
|
224
|
-
unless options[:no_interactions]
|
225
|
-
@interactor = Interactor.fabricate
|
226
|
-
@interactor.start if @interactor
|
227
|
-
end
|
154
|
+
interactor.start if interactor
|
228
155
|
|
156
|
+
runner.run(:start)
|
229
157
|
listener.start
|
230
158
|
end
|
231
159
|
|
232
160
|
# Stop Guard listening to file changes
|
233
161
|
#
|
234
162
|
def stop
|
235
|
-
run_on_guards do |guard|
|
236
|
-
run_supervised_task(guard, :stop)
|
237
|
-
end
|
238
|
-
|
239
163
|
interactor.stop if interactor
|
240
164
|
listener.stop
|
165
|
+
runner.run(:stop)
|
241
166
|
|
242
167
|
UI.info 'Bye bye...', :reset => true
|
243
168
|
end
|
@@ -247,11 +172,8 @@ module Guard
|
|
247
172
|
# @param [Hash] scopes an hash with a guard or a group scope
|
248
173
|
#
|
249
174
|
def reload(scopes)
|
250
|
-
|
251
|
-
|
252
|
-
run_supervised_task(guard, :reload)
|
253
|
-
end
|
254
|
-
end
|
175
|
+
UI.clear
|
176
|
+
runner.run(:reload, scopes)
|
255
177
|
end
|
256
178
|
|
257
179
|
# Trigger `run_all` on all Guards currently enabled.
|
@@ -259,11 +181,8 @@ module Guard
|
|
259
181
|
# @param [Hash] scopes an hash with a guard or a group scope
|
260
182
|
#
|
261
183
|
def run_all(scopes)
|
262
|
-
|
263
|
-
|
264
|
-
run_supervised_task(guard, :run_all)
|
265
|
-
end
|
266
|
-
end
|
184
|
+
UI.clear
|
185
|
+
runner.run(:run_all, scopes)
|
267
186
|
end
|
268
187
|
|
269
188
|
# Pause Guard listening to file changes.
|
@@ -271,159 +190,73 @@ module Guard
|
|
271
190
|
def pause
|
272
191
|
if listener.paused?
|
273
192
|
UI.info 'Un-paused files modification listening', :reset => true
|
274
|
-
listener.
|
275
|
-
listener.run
|
193
|
+
listener.unpause
|
276
194
|
else
|
277
195
|
UI.info 'Paused files modification listening', :reset => true
|
278
196
|
listener.pause
|
279
197
|
end
|
280
198
|
end
|
281
199
|
|
282
|
-
#
|
200
|
+
# Smart accessor for retrieving a specific guard or several guards at once.
|
283
201
|
#
|
284
|
-
|
285
|
-
run do
|
286
|
-
run_on_guards do |guard|
|
287
|
-
run_on_change_task(files, guard)
|
288
|
-
end
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
# Run a block where the listener and the interactor is
|
293
|
-
# blocked.
|
202
|
+
# @see Guard.groups
|
294
203
|
#
|
295
|
-
# @
|
204
|
+
# @example Filter Guards by String or Symbol
|
205
|
+
# Guard.guards('rspec')
|
206
|
+
# Guard.guards(:rspec)
|
296
207
|
#
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
lock.synchronize do
|
301
|
-
begin
|
302
|
-
interactor.stop if interactor
|
303
|
-
yield
|
304
|
-
rescue Interrupt
|
305
|
-
end
|
306
|
-
|
307
|
-
interactor.start if interactor
|
308
|
-
end
|
309
|
-
end
|
310
|
-
|
311
|
-
# Loop through all groups and run the given task for each Guard.
|
208
|
+
# @example Filter Guards by Regexp
|
209
|
+
# Guard.guards(/rsp.+/)
|
312
210
|
#
|
313
|
-
#
|
314
|
-
#
|
211
|
+
# @example Filter Guards by Hash
|
212
|
+
# Guard.guards({ :name => 'rspec', :group => 'backend' })
|
315
213
|
#
|
316
|
-
# @param [Hash]
|
317
|
-
# @
|
214
|
+
# @param [String, Symbol, Regexp, Hash] filter the filter to apply to the Guards
|
215
|
+
# @return [Array<Guard>] the filtered Guards
|
318
216
|
#
|
319
|
-
def
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
217
|
+
def guards(filter = nil)
|
218
|
+
@guards ||= []
|
219
|
+
|
220
|
+
case filter
|
221
|
+
when String, Symbol
|
222
|
+
@guards.find { |guard| guard.class.to_s.downcase.sub('guard::', '') == filter.to_s.downcase.gsub('-', '') }
|
223
|
+
when Regexp
|
224
|
+
@guards.find_all { |guard| guard.class.to_s.downcase.sub('guard::', '') =~ filter }
|
225
|
+
when Hash
|
226
|
+
filter.inject(@guards) do |matches, (k, v)|
|
227
|
+
if k.to_sym == :name
|
228
|
+
matches.find_all { |guard| guard.class.to_s.downcase.sub('guard::', '') == v.to_s.downcase.gsub('-', '') }
|
229
|
+
else
|
230
|
+
matches.find_all { |guard| guard.send(k).to_sym == v.to_sym }
|
329
231
|
end
|
330
232
|
end
|
233
|
+
else
|
234
|
+
@guards
|
331
235
|
end
|
332
236
|
end
|
333
237
|
|
334
|
-
#
|
335
|
-
# the task is split to run changed paths on {Guard::Guard#run_on_change}, whereas
|
336
|
-
# deleted paths run on {Guard::Guard#run_on_deletion}.
|
337
|
-
#
|
338
|
-
# @param [Array<String>] files the list of files to pass to the task
|
339
|
-
# @param [Guard::Guard] guard the guard to run
|
340
|
-
# @raise [:task_has_failed] when task has failed
|
341
|
-
#
|
342
|
-
def run_on_change_task(files, guard)
|
343
|
-
paths = Watcher.match_files(guard, files)
|
344
|
-
changes = changed_paths(paths)
|
345
|
-
deletions = deleted_paths(paths)
|
346
|
-
|
347
|
-
unless changes.empty?
|
348
|
-
UI.debug "#{ guard.class.name }#run_on_change with #{ changes.inspect }"
|
349
|
-
run_supervised_task(guard, :run_on_change, changes)
|
350
|
-
end
|
351
|
-
|
352
|
-
unless deletions.empty?
|
353
|
-
UI.debug "#{ guard.class.name }#run_on_deletion with #{ deletions.inspect }"
|
354
|
-
run_supervised_task(guard, :run_on_deletion, deletions)
|
355
|
-
end
|
356
|
-
end
|
357
|
-
|
358
|
-
# Detects the paths that have changed.
|
359
|
-
#
|
360
|
-
# Deleted paths are prefixed by an exclamation point.
|
361
|
-
# @see Guard::Listener#modified_files
|
362
|
-
#
|
363
|
-
# @param [Array<String>] paths the watched paths
|
364
|
-
# @return [Array<String>] the changed paths
|
365
|
-
#
|
366
|
-
def changed_paths(paths)
|
367
|
-
paths.select { |f| !f.respond_to?(:start_with?) || !f.start_with?('!') }
|
368
|
-
end
|
369
|
-
|
370
|
-
# Detects the paths that have been deleted.
|
371
|
-
#
|
372
|
-
# Deleted paths are prefixed by an exclamation point.
|
373
|
-
# @see Guard::Listener#modified_files
|
374
|
-
#
|
375
|
-
# @param [Array<String>] paths the watched paths
|
376
|
-
# @return [Array<String>] the deleted paths
|
377
|
-
#
|
378
|
-
def deleted_paths(paths)
|
379
|
-
paths.select { |f| f.respond_to?(:start_with?) && f.start_with?('!') }.map { |f| f.slice(1..-1) }
|
380
|
-
end
|
381
|
-
|
382
|
-
# Run a Guard task, but remove the Guard when his work leads to a system failure.
|
383
|
-
#
|
384
|
-
# When the Group has `:halt_on_fail` disabled, we've to catch `:task_has_failed`
|
385
|
-
# here in order to avoid an uncaught throw error.
|
238
|
+
# Smart accessor for retrieving a specific group or several groups at once.
|
386
239
|
#
|
387
|
-
# @
|
388
|
-
# @param [Symbol] task the task to run
|
389
|
-
# @param [Array] args the arguments for the task
|
390
|
-
# @raise [:task_has_failed] when task has failed
|
240
|
+
# @see Guard.guards
|
391
241
|
#
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
result = guard.send(task, *args)
|
396
|
-
guard.hook("#{ task }_end", result)
|
397
|
-
|
398
|
-
result
|
399
|
-
end
|
400
|
-
|
401
|
-
rescue Exception => ex
|
402
|
-
UI.error("#{ guard.class.name } failed to achieve its <#{ task.to_s }>, exception was:" +
|
403
|
-
"\n#{ ex.class }: #{ ex.message }\n#{ ex.backtrace.join("\n") }")
|
404
|
-
|
405
|
-
guards.delete guard
|
406
|
-
UI.info("\n#{ guard.class.name } has just been fired")
|
407
|
-
|
408
|
-
ex
|
409
|
-
end
|
410
|
-
|
411
|
-
# Get the symbol we have to catch when running a supervised task.
|
412
|
-
# If we are within a Guard group that has the `:halt_on_fail`
|
413
|
-
# option set, we do NOT catch it here, it will be catched at the
|
414
|
-
# group level.
|
242
|
+
# @example Filter groups by String or Symbol
|
243
|
+
# Guard.groups('backend')
|
244
|
+
# Guard.groups(:backend)
|
415
245
|
#
|
416
|
-
# @
|
246
|
+
# @example Filter groups by Regexp
|
247
|
+
# Guard.groups(/(back|front)end/)
|
417
248
|
#
|
418
|
-
# @param [
|
419
|
-
# @return [
|
249
|
+
# @param [String, Symbol, Regexp] filter the filter to apply to the Groups
|
250
|
+
# @return [Array<Group>] the filtered groups
|
420
251
|
#
|
421
|
-
def
|
422
|
-
|
423
|
-
|
424
|
-
group.
|
252
|
+
def groups(filter = nil)
|
253
|
+
case filter
|
254
|
+
when String, Symbol
|
255
|
+
@groups.find { |group| group.name == filter.to_sym }
|
256
|
+
when Regexp
|
257
|
+
@groups.find_all { |group| group.name.to_s =~ filter }
|
425
258
|
else
|
426
|
-
|
259
|
+
@groups
|
427
260
|
end
|
428
261
|
end
|
429
262
|
|
@@ -463,6 +296,25 @@ module Guard
|
|
463
296
|
group
|
464
297
|
end
|
465
298
|
|
299
|
+
# Runs a block where the interactor is
|
300
|
+
# blocked and execution is synchronized
|
301
|
+
# to avoid state inconsistency.
|
302
|
+
#
|
303
|
+
# @yield the block to run
|
304
|
+
#
|
305
|
+
def within_preserved_state
|
306
|
+
lock.synchronize do
|
307
|
+
begin
|
308
|
+
interactor.stop if interactor
|
309
|
+
@result = yield
|
310
|
+
rescue Interrupt
|
311
|
+
end
|
312
|
+
|
313
|
+
interactor.start if interactor
|
314
|
+
end
|
315
|
+
@result
|
316
|
+
end
|
317
|
+
|
466
318
|
# Tries to load the Guard main class. This transforms the supplied Guard
|
467
319
|
# name into a class name:
|
468
320
|
#
|
@@ -545,5 +397,26 @@ module Guard
|
|
545
397
|
end
|
546
398
|
end
|
547
399
|
|
400
|
+
# Deprecation message for the `watch_all_modifications` start option
|
401
|
+
WATCH_ALL_MODIFICATIONS_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
|
402
|
+
Starting with Guard v1.1 the 'watch_all_modifications' option is removed and is now always on.
|
403
|
+
EOS
|
404
|
+
|
405
|
+
# Deprecation message for the `no_vendor` start option
|
406
|
+
NO_VENDOR_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
|
407
|
+
Starting with Guard v1.1 the 'no_vendor' option is removed because the monitoring gems are now
|
408
|
+
a part of a new gem called Listen.
|
409
|
+
|
410
|
+
You can specify a custom version of any monitoring gem directly in your Gemfile
|
411
|
+
if you want to overwrite Listen's default monitoring gems.
|
412
|
+
EOS
|
413
|
+
|
414
|
+
# Displays a warning for each deprecated options used.
|
415
|
+
#
|
416
|
+
def deprecated_options_warning
|
417
|
+
::Guard::UI.deprecation(WATCH_ALL_MODIFICATIONS_DEPRECATION) if options[:watch_all_modifications]
|
418
|
+
::Guard::UI.deprecation(NO_VENDOR_DEPRECATION) if options[:no_vendor]
|
419
|
+
end
|
420
|
+
|
548
421
|
end
|
549
422
|
end
|