guard 0.7.0 → 0.8.0
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 +23 -1
- data/README.md +173 -226
- data/bin/guard +1 -1
- data/lib/guard.rb +243 -45
- data/lib/guard/cli.rb +135 -46
- data/lib/guard/dsl.rb +260 -38
- data/lib/guard/dsl_describer.rb +36 -4
- data/lib/guard/group.rb +22 -0
- data/lib/guard/guard.rb +53 -13
- data/lib/guard/hook.rb +61 -15
- data/lib/guard/interactor.rb +52 -14
- data/lib/guard/listener.rb +181 -26
- data/lib/guard/listeners/darwin.rb +26 -7
- data/lib/guard/listeners/linux.rb +32 -8
- data/lib/guard/listeners/polling.rb +23 -5
- data/lib/guard/listeners/windows.rb +25 -6
- data/lib/guard/notifier.rb +78 -3
- data/lib/guard/ui.rb +125 -47
- data/lib/guard/version.rb +4 -1
- data/lib/guard/watcher.rb +48 -4
- data/man/guard.1 +1 -1
- data/man/guard.1.html +1 -1
- metadata +36 -13
data/bin/guard
CHANGED
data/lib/guard.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
|
+
# Guard is the main module for all Guard related modules and classes.
|
2
|
+
# Also other Guard implementation should use this namespace.
|
3
|
+
#
|
1
4
|
module Guard
|
2
5
|
|
3
6
|
autoload :UI, 'guard/ui'
|
4
7
|
autoload :Dsl, 'guard/dsl'
|
5
8
|
autoload :DslDescriber, 'guard/dsl_describer'
|
9
|
+
autoload :Group, 'guard/group'
|
6
10
|
autoload :Interactor, 'guard/interactor'
|
7
11
|
autoload :Listener, 'guard/listener'
|
8
12
|
autoload :Watcher, 'guard/watcher'
|
@@ -10,24 +14,92 @@ module Guard
|
|
10
14
|
autoload :Hook, 'guard/hook'
|
11
15
|
|
12
16
|
class << self
|
13
|
-
attr_accessor :options, :
|
17
|
+
attr_accessor :options, :interactor, :listener
|
14
18
|
|
15
|
-
#
|
19
|
+
# Initialize the Guard singleton.
|
20
|
+
#
|
21
|
+
# @option options [Boolean] clear if auto clear the UI should be done
|
22
|
+
# @option options [Boolean] notify if system notifications should be shown
|
23
|
+
# @option options [Boolean] debug if debug output should be shown
|
24
|
+
# @option options [Array<String>] group the list of groups to start
|
25
|
+
# @option options [String] watchdir the director to watch
|
26
|
+
# @option options [String] guardfile the path to the Guardfile
|
27
|
+
# @option options [Boolean] watch_all_modifications watches all file modifications if true
|
28
|
+
#
|
16
29
|
def setup(options = {})
|
17
30
|
@options = options
|
18
31
|
@guards = []
|
19
|
-
@groups = [:default]
|
32
|
+
@groups = [Group.new(:default)]
|
20
33
|
@interactor = Interactor.new
|
21
|
-
@listener = Listener.select_and_init(@options[:watchdir] ? File.expand_path(@options[:watchdir]) : Dir.pwd)
|
34
|
+
@listener = Listener.select_and_init(@options[:watchdir] ? File.expand_path(@options[:watchdir]) : Dir.pwd, options)
|
22
35
|
|
23
|
-
@options[:notify] && ENV[
|
36
|
+
@options[:notify] && ENV['GUARD_NOTIFY'] != 'false' ? Notifier.turn_on : Notifier.turn_off
|
24
37
|
|
25
38
|
UI.clear if @options[:clear]
|
39
|
+
|
26
40
|
debug_command_execution if @options[:debug]
|
27
41
|
|
28
42
|
self
|
29
43
|
end
|
30
44
|
|
45
|
+
# Smart accessor for retrieving a specific guard or several guards at once.
|
46
|
+
#
|
47
|
+
# @param [String, Symbol] filter return the guard with the given name, or nil if not found
|
48
|
+
# @param [Regexp] filter returns all guards matching the Regexp, or [] if no guard found
|
49
|
+
# @param [Hash] filter returns all guards matching the given Hash.
|
50
|
+
# Example: `{ :name => 'rspec', :group => 'backend' }`, or [] if no guard found
|
51
|
+
# @param [NilClass] filter returns all guards
|
52
|
+
#
|
53
|
+
# @see Guard.groups
|
54
|
+
#
|
55
|
+
def guards(filter = nil)
|
56
|
+
case filter
|
57
|
+
when String, Symbol
|
58
|
+
@guards.find { |guard| guard.class.to_s.downcase.sub('guard::', '') == filter.to_s.downcase.gsub('-', '') }
|
59
|
+
when Regexp
|
60
|
+
@guards.find_all { |guard| guard.class.to_s.downcase.sub('guard::', '') =~ filter }
|
61
|
+
when Hash
|
62
|
+
filter.inject(@guards) do |matches, (k, v)|
|
63
|
+
if k.to_sym == :name
|
64
|
+
matches.find_all { |guard| guard.class.to_s.downcase.sub('guard::', '') == v.to_s.downcase.gsub('-', '') }
|
65
|
+
else
|
66
|
+
matches.find_all { |guard| guard.send(k).to_sym == v.to_sym }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
else
|
70
|
+
@guards
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Smart accessor for retrieving a specific group or several groups at once.
|
75
|
+
#
|
76
|
+
# @param [NilClass] filter returns all groups
|
77
|
+
# @param [String, Symbol] filter return the group with the given name, or nil if not found
|
78
|
+
# @param [Regexp] filter returns all groups matching the Regexp, or [] if no group found
|
79
|
+
#
|
80
|
+
# @see Guard.guards
|
81
|
+
#
|
82
|
+
def groups(filter = nil)
|
83
|
+
case filter
|
84
|
+
when String, Symbol
|
85
|
+
@groups.find { |group| group.name == filter.to_sym }
|
86
|
+
when Regexp
|
87
|
+
@groups.find_all { |group| group.name.to_s =~ filter }
|
88
|
+
else
|
89
|
+
@groups
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Start Guard by evaluate the `Guardfile`, initialize the declared Guards
|
94
|
+
# and start the available file change listener.
|
95
|
+
#
|
96
|
+
# @option options [Boolean] clear if auto clear the UI should be done
|
97
|
+
# @option options [Boolean] notify if system notifications should be shown
|
98
|
+
# @option options [Boolean] debug if debug output should be shown
|
99
|
+
# @option options [Array<String>] group the list of groups to start
|
100
|
+
# @option options [String] watchdir the director to watch
|
101
|
+
# @option options [String] guardfile the path to the Guardfile
|
102
|
+
#
|
31
103
|
def start(options = {})
|
32
104
|
setup(options)
|
33
105
|
|
@@ -38,85 +110,184 @@ module Guard
|
|
38
110
|
listener.changed_files += files if Watcher.match_files?(guards, files)
|
39
111
|
end
|
40
112
|
|
41
|
-
UI.info "Guard is now watching at '#{listener.directory}'"
|
42
|
-
|
113
|
+
UI.info "Guard is now watching at '#{ listener.directory }'"
|
114
|
+
|
115
|
+
run_guard_task(:start)
|
43
116
|
|
44
117
|
interactor.start
|
45
118
|
listener.start
|
46
119
|
end
|
47
120
|
|
121
|
+
# Stop Guard listening to file changes
|
122
|
+
#
|
48
123
|
def stop
|
49
|
-
UI.info
|
124
|
+
UI.info 'Bye bye...', :reset => true
|
50
125
|
listener.stop
|
51
|
-
|
126
|
+
run_guard_task(:stop)
|
52
127
|
abort
|
53
128
|
end
|
54
129
|
|
130
|
+
# Reload all Guards currently enabled.
|
131
|
+
#
|
55
132
|
def reload
|
56
133
|
run do
|
57
|
-
|
134
|
+
run_guard_task(:reload)
|
58
135
|
end
|
59
136
|
end
|
60
137
|
|
138
|
+
# Trigger `run_all` on all Guards currently enabled.
|
139
|
+
#
|
61
140
|
def run_all
|
62
141
|
run do
|
63
|
-
|
142
|
+
run_guard_task(:run_all)
|
64
143
|
end
|
65
144
|
end
|
66
145
|
|
146
|
+
# Pause Guard listening to file changes.
|
147
|
+
#
|
67
148
|
def pause
|
68
149
|
if listener.locked
|
69
|
-
UI.info
|
150
|
+
UI.info 'Un-paused files modification listening', :reset => true
|
70
151
|
listener.clear_changed_files
|
71
152
|
listener.unlock
|
72
153
|
else
|
73
|
-
UI.info
|
154
|
+
UI.info 'Paused files modification listening', :reset => true
|
74
155
|
listener.lock
|
75
156
|
end
|
76
157
|
end
|
77
158
|
|
78
|
-
|
159
|
+
# Trigger `run_on_change` on all Guards currently enabled.
|
160
|
+
#
|
161
|
+
def run_on_change(paths)
|
79
162
|
run do
|
80
|
-
|
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
|
86
|
-
end
|
163
|
+
run_guard_task(:run_on_change, paths)
|
87
164
|
end
|
88
165
|
end
|
89
166
|
|
167
|
+
# Run a block where the listener and the interactor is
|
168
|
+
# blocked.
|
169
|
+
#
|
170
|
+
# @yield the block to run
|
171
|
+
#
|
90
172
|
def run
|
91
173
|
listener.lock
|
92
174
|
interactor.lock
|
175
|
+
|
93
176
|
UI.clear if options[:clear]
|
177
|
+
|
94
178
|
begin
|
95
179
|
yield
|
96
180
|
rescue Interrupt
|
97
181
|
end
|
182
|
+
|
98
183
|
interactor.unlock
|
99
184
|
listener.unlock
|
100
185
|
end
|
101
186
|
|
102
|
-
#
|
103
|
-
#
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
187
|
+
# Loop through all groups and run the given task for each Guard.
|
188
|
+
#
|
189
|
+
# Stop the task run for the all Guards within a group if one Guard
|
190
|
+
# throws `:task_has_failed` and the group has its `:halt_on_fail` option to `true`.
|
191
|
+
#
|
192
|
+
# @param [Symbol] task the task to run
|
193
|
+
# @param [Array<String>] files the list of files to pass to the task
|
194
|
+
#
|
195
|
+
def run_guard_task(task, files = nil)
|
196
|
+
groups.each do |group|
|
197
|
+
catch group.options[:halt_on_fail] == true ? :task_has_failed : :no_catch do
|
198
|
+
guards(:group => group.name).each do |guard|
|
199
|
+
if task == :run_on_change
|
200
|
+
run_on_change_task(files, guard, task)
|
201
|
+
else
|
202
|
+
run_supervised_task(guard, task)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# Run the `:run_on_change` task. When the option `:watch_all_modifications` is set,
|
210
|
+
# the task is split to run changed paths on {Guard::Guard#run_on_change}, whereas
|
211
|
+
# deleted paths run on {Guard::Guard#run_on_deletion}.
|
212
|
+
#
|
213
|
+
# @param [Array<String>] files the list of files to pass to the task
|
214
|
+
# @param [Guard::Guard] guard the guard to run
|
215
|
+
# @param [Symbol] task the task to run
|
216
|
+
#
|
217
|
+
def run_on_change_task(files, guard, task)
|
218
|
+
paths = Watcher.match_files(guard, files)
|
219
|
+
changes = changed_paths(paths)
|
220
|
+
deletions = deleted_paths(paths)
|
221
|
+
|
222
|
+
unless changes.empty?
|
223
|
+
UI.debug "#{ guard.class.name }##{ task } with #{ changes.inspect }"
|
224
|
+
run_supervised_task(guard, task, changes)
|
225
|
+
end
|
226
|
+
|
227
|
+
unless deletions.empty?
|
228
|
+
UI.debug "#{ guard.class.name }#run_on_deletion with #{ deletions.inspect }"
|
229
|
+
run_supervised_task(guard, :run_on_deletion, deletions)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Detects the paths that have changed.
|
234
|
+
#
|
235
|
+
# Deleted paths are prefixed by an exclamation point.
|
236
|
+
# @see Guard::Listener#modified_files
|
237
|
+
#
|
238
|
+
# @param [Array<String>] paths the watched paths
|
239
|
+
# @return [Array<String>] the changed paths
|
240
|
+
#
|
241
|
+
def changed_paths(paths)
|
242
|
+
paths.select { |f| !f.start_with?('!') }
|
243
|
+
end
|
244
|
+
|
245
|
+
# Detects the paths that have been deleted.
|
246
|
+
#
|
247
|
+
# Deleted paths are prefixed by an exclamation point.
|
248
|
+
# @see Guard::Listener#modified_files
|
249
|
+
#
|
250
|
+
# @param [Array<String>] paths the watched paths
|
251
|
+
# @return [Array<String>] the deleted paths
|
252
|
+
#
|
253
|
+
def deleted_paths(paths)
|
254
|
+
paths.select { |f| f.start_with?('!') }.map { |f| f.slice(1..-1) }
|
255
|
+
end
|
256
|
+
|
257
|
+
# Run a Guard task, but remove the Guard when his work leads to a system failure.
|
258
|
+
#
|
259
|
+
# @param [Guard::Guard] guard the Guard to execute
|
260
|
+
# @param [Symbol] task the task to run
|
261
|
+
# @param [Array] args the arguments for the task
|
262
|
+
# @return [Boolean, Exception] the result of the Guard
|
263
|
+
#
|
264
|
+
def run_supervised_task(guard, task, *args)
|
265
|
+
guard.hook("#{ task }_begin", *args)
|
266
|
+
result = guard.send(task, *args)
|
267
|
+
guard.hook("#{ task }_end", result)
|
268
|
+
|
108
269
|
result
|
270
|
+
|
109
271
|
rescue Exception => ex
|
110
|
-
UI.error("#{guard.class.name} failed to achieve its <#{
|
111
|
-
|
272
|
+
UI.error("#{ guard.class.name } failed to achieve its <#{ task.to_s }>, exception was:" +
|
273
|
+
"\n#{ ex.class }: #{ ex.message }\n#{ ex.backtrace.join("\n") }")
|
274
|
+
|
112
275
|
guards.delete guard
|
113
|
-
UI.info("\n#{guard.class.name} has just been fired")
|
114
|
-
|
276
|
+
UI.info("\n#{ guard.class.name } has just been fired")
|
277
|
+
|
278
|
+
ex
|
115
279
|
end
|
116
280
|
|
281
|
+
# Add a Guard to use.
|
282
|
+
#
|
283
|
+
# @param [String] name the Guard name
|
284
|
+
# @param [Array<Watcher>] watchers the list of declared watchers
|
285
|
+
# @param [Array<Hash>] callbacks the list of callbacks
|
286
|
+
# @param [Hash] options the Guard options (see the given Guard documentation)
|
287
|
+
#
|
117
288
|
def add_guard(name, watchers = [], callbacks = [], options = {})
|
118
289
|
if name.to_sym == :ego
|
119
|
-
UI.deprecation(
|
290
|
+
UI.deprecation('Guard::Ego is now part of Guard. You can remove it from your Guardfile.')
|
120
291
|
else
|
121
292
|
guard_class = get_guard_class(name)
|
122
293
|
callbacks.each { |callback| Hook.add_callback(callback[:listener], guard_class, callback[:events]) }
|
@@ -124,42 +295,66 @@ module Guard
|
|
124
295
|
end
|
125
296
|
end
|
126
297
|
|
127
|
-
|
128
|
-
|
298
|
+
# Add a Guard group.
|
299
|
+
#
|
300
|
+
# @param [String] name the group name
|
301
|
+
# @option options [Boolean] halt_on_fail if a task execution
|
302
|
+
# should be halted for all Guards in this group if one Guard throws `:task_has_failed`
|
303
|
+
# @return [Guard::Group] the group added (or retrieved from the `@groups` variable if already present)
|
304
|
+
#
|
305
|
+
def add_group(name, options = {})
|
306
|
+
group = groups(name)
|
307
|
+
if group.nil?
|
308
|
+
group = Group.new(name, options)
|
309
|
+
@groups << group
|
310
|
+
end
|
311
|
+
group
|
129
312
|
end
|
130
313
|
|
314
|
+
# Tries to load the Guard main class.
|
315
|
+
#
|
316
|
+
# @param [String] name the name of the Guard
|
317
|
+
# @return [Class, nil] the loaded class
|
318
|
+
#
|
131
319
|
def get_guard_class(name)
|
132
320
|
name = name.to_s
|
133
321
|
try_require = false
|
134
322
|
const_name = name.downcase.gsub('-', '')
|
135
323
|
begin
|
136
|
-
require "guard/#{name.downcase}" if try_require
|
324
|
+
require "guard/#{ name.downcase }" if try_require
|
137
325
|
self.const_get(self.constants.find { |c| c.to_s.downcase == const_name })
|
138
326
|
rescue TypeError
|
139
327
|
unless try_require
|
140
328
|
try_require = true
|
141
329
|
retry
|
142
330
|
else
|
143
|
-
UI.error "Could not find class Guard::#{const_name.capitalize}"
|
331
|
+
UI.error "Could not find class Guard::#{ const_name.capitalize }"
|
144
332
|
end
|
145
333
|
rescue LoadError => loadError
|
146
|
-
UI.error "Could not load 'guard/#{name.downcase}' or find class Guard::#{const_name.capitalize}"
|
334
|
+
UI.error "Could not load 'guard/#{ name.downcase }' or find class Guard::#{ const_name.capitalize }"
|
147
335
|
UI.error loadError.to_s
|
148
336
|
end
|
149
337
|
end
|
150
338
|
|
339
|
+
# Locate a path to a Guard gem.
|
340
|
+
#
|
341
|
+
# @param [String] name the name of the Guard without the prefix `guard-`
|
342
|
+
# @return [String] the full path to the Guard gem
|
343
|
+
#
|
151
344
|
def locate_guard(name)
|
152
345
|
if Gem::Version.create(Gem::VERSION) >= Gem::Version.create('1.8.0')
|
153
|
-
Gem::Specification.find_by_name("guard-#{name}").full_gem_path
|
346
|
+
Gem::Specification.find_by_name("guard-#{ name }").full_gem_path
|
154
347
|
else
|
155
|
-
Gem.source_index.find_name("guard-#{name}").last.full_gem_path
|
348
|
+
Gem.source_index.find_name("guard-#{ name }").last.full_gem_path
|
156
349
|
end
|
157
350
|
rescue
|
158
|
-
UI.error "Could not find 'guard-#{name}' gem path."
|
351
|
+
UI.error "Could not find 'guard-#{ name }' gem path."
|
159
352
|
end
|
160
353
|
|
161
|
-
##
|
162
354
|
# Returns a list of guard Gem names installed locally.
|
355
|
+
#
|
356
|
+
# @return [Array<String>] a list of guard gem names
|
357
|
+
#
|
163
358
|
def guard_gem_names
|
164
359
|
if Gem::Version.create(Gem::VERSION) >= Gem::Version.create('1.8.0')
|
165
360
|
Gem::Specification.find_all.select { |x| x.name =~ /^guard-/ }
|
@@ -168,16 +363,19 @@ module Guard
|
|
168
363
|
end.map { |x| x.name.sub /^guard-/, '' }
|
169
364
|
end
|
170
365
|
|
366
|
+
# Adds a command logger in debug mode. This wraps common command
|
367
|
+
# execution functions and logs the executed command before execution.
|
368
|
+
#
|
171
369
|
def debug_command_execution
|
172
370
|
Kernel.send(:alias_method, :original_system, :system)
|
173
371
|
Kernel.send(:define_method, :system) do |command, *args|
|
174
|
-
::Guard::UI.debug "Command execution: #{command} #{args.join(' ')}"
|
372
|
+
::Guard::UI.debug "Command execution: #{ command } #{ args.join(' ') }"
|
175
373
|
original_system command, *args
|
176
374
|
end
|
177
375
|
|
178
|
-
Kernel.send(:alias_method, :original_backtick, :
|
179
|
-
Kernel.send(:define_method, :
|
180
|
-
::Guard::UI.debug "Command execution: #{command}"
|
376
|
+
Kernel.send(:alias_method, :original_backtick, :'`')
|
377
|
+
Kernel.send(:define_method, :'`') do |command|
|
378
|
+
::Guard::UI.debug "Command execution: #{ command }"
|
181
379
|
original_backtick command
|
182
380
|
end
|
183
381
|
end
|
data/lib/guard/cli.rb
CHANGED
@@ -2,89 +2,178 @@ require 'thor'
|
|
2
2
|
require 'guard/version'
|
3
3
|
|
4
4
|
module Guard
|
5
|
+
|
6
|
+
# Guard command line interface managed by [Thor](https://github.com/wycats/thor).
|
7
|
+
# This is the main interface to Guard that is called by the Guard binary `bin/guard`.
|
8
|
+
#
|
5
9
|
class CLI < Thor
|
10
|
+
|
6
11
|
default_task :start
|
7
12
|
|
8
|
-
|
9
|
-
|
10
|
-
method_option :
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
desc 'start', 'Starts Guard'
|
14
|
+
|
15
|
+
method_option :clear,
|
16
|
+
:type => :boolean,
|
17
|
+
:default => false,
|
18
|
+
:aliases => '-c',
|
19
|
+
:banner => 'Auto clear shell before each change/run_all/reload'
|
20
|
+
|
21
|
+
method_option :notify,
|
22
|
+
:type => :boolean,
|
23
|
+
:default => true,
|
24
|
+
:aliases => '-n',
|
25
|
+
:banner => 'Notifications feature (growl/libnotify)'
|
26
|
+
|
27
|
+
method_option :debug,
|
28
|
+
:type => :boolean,
|
29
|
+
:default => false,
|
30
|
+
:aliases => '-d',
|
31
|
+
:banner => 'Print debug messages'
|
32
|
+
|
33
|
+
method_option :group,
|
34
|
+
:type => :array,
|
35
|
+
:default => [],
|
36
|
+
:aliases => '-g',
|
37
|
+
:banner => 'Run only the passed groups'
|
38
|
+
|
39
|
+
method_option :watchdir,
|
40
|
+
:type => :string,
|
41
|
+
:aliases => '-w',
|
42
|
+
:banner => 'Specify the directory to watch'
|
43
|
+
|
44
|
+
method_option :guardfile,
|
45
|
+
:type => :string,
|
46
|
+
:aliases => '-G',
|
47
|
+
:banner => 'Specify a Guardfile'
|
14
48
|
|
15
|
-
|
49
|
+
method_option :watch_all_modifications,
|
50
|
+
:type => :boolean,
|
51
|
+
:default => false,
|
52
|
+
:aliases => '-A',
|
53
|
+
:banner => "Watch for all file modifications including moves and deletions"
|
54
|
+
|
55
|
+
# Start Guard by initialize the defined Guards and watch the file system.
|
56
|
+
# This is the default task, so calling `guard` is the same as calling `guard start`.
|
57
|
+
#
|
58
|
+
# @see Guard.start
|
59
|
+
#
|
16
60
|
def start
|
17
61
|
::Guard.start(options)
|
18
62
|
end
|
19
63
|
|
20
|
-
desc
|
64
|
+
desc 'list', 'Lists guards that can be used with init'
|
65
|
+
|
66
|
+
# List the Guards that are available for use in your system and marks
|
67
|
+
# those that are currently used in your `Guardfile`.
|
68
|
+
#
|
69
|
+
# @example Guard list output
|
70
|
+
#
|
71
|
+
# Available guards:
|
72
|
+
# bundler *
|
73
|
+
# livereload
|
74
|
+
# ronn
|
75
|
+
# rspec *
|
76
|
+
# spork
|
77
|
+
#
|
78
|
+
# See also https://github.com/guard/guard/wiki/List-of-available-Guards
|
79
|
+
# * denotes ones already in your Guardfile
|
80
|
+
#
|
81
|
+
# @see Guard::DslDescriber
|
82
|
+
#
|
21
83
|
def list
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
group[:guards].each {|
|
84
|
+
Guard::DslDescriber.evaluate_guardfile(options)
|
85
|
+
|
86
|
+
installed = Guard::DslDescriber.guardfile_structure.inject([]) do |installed, group|
|
87
|
+
group[:guards].each { |guard| installed << guard[:name] } if group[:guards]
|
88
|
+
installed
|
26
89
|
end
|
27
90
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
else
|
33
|
-
::Guard::UI.info " #{name}"
|
34
|
-
end
|
91
|
+
Guard::UI.info 'Available guards:'
|
92
|
+
|
93
|
+
Guard::guard_gem_names.sort.uniq.each do |name|
|
94
|
+
Guard::UI.info " #{ name } #{ installed.include?(name) ? '*' : '' }"
|
35
95
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
96
|
+
|
97
|
+
Guard::UI.info ' '
|
98
|
+
Guard::UI.info 'See also https://github.com/guard/guard/wiki/List-of-available-Guards'
|
99
|
+
Guard::UI.info '* denotes ones already in your Guardfile'
|
39
100
|
end
|
40
101
|
|
41
|
-
desc
|
102
|
+
desc 'version', 'Show the Guard version'
|
103
|
+
map %w(-v --version) => :version
|
104
|
+
|
105
|
+
# Shows the current version of Guard.
|
106
|
+
#
|
107
|
+
# @see Guard::VERSION
|
108
|
+
#
|
42
109
|
def version
|
43
|
-
|
110
|
+
Guard::UI.info "Guard version #{ Guard::VERSION }"
|
44
111
|
end
|
45
|
-
map %w(-v --version) => :version
|
46
112
|
|
47
|
-
desc
|
48
|
-
def init(guard_name = nil)
|
49
|
-
if !File.exist?("Guardfile")
|
50
|
-
puts "Writing new Guardfile to #{Dir.pwd}/Guardfile"
|
51
|
-
FileUtils.cp(File.expand_path('../templates/Guardfile', __FILE__), 'Guardfile')
|
52
|
-
elsif guard_name.nil?
|
53
|
-
::Guard::UI.error "Guardfile already exists at #{Dir.pwd}/Guardfile"
|
54
|
-
exit 1
|
55
|
-
end
|
113
|
+
desc 'init [GUARD]', 'Generates a Guardfile at the current working directory, or insert the given GUARD to an existing Guardfile'
|
56
114
|
|
115
|
+
# Appends the Guard template to the `Guardfile`, or creates an initial
|
116
|
+
# `Guardfile` when no Guard name is passed.
|
117
|
+
#
|
118
|
+
# @param [String] guard_name the name of the Guard to initialize
|
119
|
+
#
|
120
|
+
def init(guard_name = nil)
|
57
121
|
if guard_name
|
58
122
|
guard_class = ::Guard.get_guard_class(guard_name)
|
59
123
|
guard_class.init(guard_name)
|
124
|
+
|
125
|
+
else
|
126
|
+
if File.exist?('Guardfile')
|
127
|
+
puts 'Writing new Guardfile to #{Dir.pwd}/Guardfile'
|
128
|
+
FileUtils.cp(File.expand_path('../templates/Guardfile', __FILE__), 'Guardfile')
|
129
|
+
else
|
130
|
+
Guard::UI.error "Guardfile already exists at #{ Dir.pwd }/Guardfile"
|
131
|
+
exit 1
|
132
|
+
end
|
60
133
|
end
|
61
134
|
end
|
62
135
|
|
63
|
-
desc
|
136
|
+
desc 'show', 'Show all defined Guards and their options'
|
137
|
+
map %w(-T) => :show
|
138
|
+
|
139
|
+
# Shows all Guards and their options that are defined in
|
140
|
+
# the `Guardfile`.
|
141
|
+
#
|
142
|
+
# @example guard show output
|
143
|
+
#
|
144
|
+
# (global):
|
145
|
+
# bundler
|
146
|
+
# coffeescript: input => "app/assets/javascripts", noop => true
|
147
|
+
# jasmine
|
148
|
+
# rspec: cli => "--fail-fast --format Fuubar
|
149
|
+
#
|
150
|
+
# @see Guard::DslDescriber
|
151
|
+
#
|
64
152
|
def show
|
65
|
-
|
153
|
+
Guard::DslDescriber.evaluate_guardfile(options)
|
66
154
|
|
67
|
-
|
68
|
-
|
155
|
+
Guard::DslDescriber.guardfile_structure.each do |group|
|
156
|
+
unless group[:guards].empty?
|
69
157
|
if group[:group]
|
70
|
-
|
158
|
+
Guard::UI.info "Group #{ group[:group] }:"
|
71
159
|
else
|
72
|
-
|
160
|
+
Guard::UI.info '(global):'
|
73
161
|
end
|
74
162
|
|
75
163
|
group[:guards].each do |guard|
|
76
|
-
line = " #{guard[:name]}"
|
164
|
+
line = " #{ guard[:name] }"
|
77
165
|
|
78
|
-
|
79
|
-
line += ": #{guard[:options].collect { |k, v| "#{k} => #{v.inspect}" }.join(
|
166
|
+
unless guard[:options].empty?
|
167
|
+
line += ": #{ guard[:options].collect { |k, v| "#{ k } => #{ v.inspect }" }.join(', ') }"
|
80
168
|
end
|
81
|
-
|
169
|
+
|
170
|
+
Guard::UI.info line
|
82
171
|
end
|
83
172
|
end
|
84
173
|
end
|
85
174
|
|
86
|
-
|
175
|
+
Guard::UI.info ''
|
87
176
|
end
|
88
|
-
|
177
|
+
|
89
178
|
end
|
90
179
|
end
|