guard 1.0.3 → 1.1.0.alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|