joshbuddy-guard 0.10.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 +370 -0
- data/LICENSE +20 -0
- data/README.md +470 -0
- data/bin/fsevent_watch_guard +0 -0
- data/bin/guard +6 -0
- data/images/failed.png +0 -0
- data/images/pending.png +0 -0
- data/images/success.png +0 -0
- data/lib/guard.rb +463 -0
- data/lib/guard/cli.rb +125 -0
- data/lib/guard/dsl.rb +370 -0
- data/lib/guard/dsl_describer.rb +150 -0
- data/lib/guard/group.rb +37 -0
- data/lib/guard/guard.rb +129 -0
- data/lib/guard/hook.rb +118 -0
- data/lib/guard/interactor.rb +116 -0
- data/lib/guard/listener.rb +351 -0
- data/lib/guard/listeners/darwin.rb +60 -0
- data/lib/guard/listeners/linux.rb +91 -0
- data/lib/guard/listeners/polling.rb +55 -0
- data/lib/guard/listeners/windows.rb +61 -0
- data/lib/guard/notifier.rb +290 -0
- data/lib/guard/templates/Guardfile +2 -0
- data/lib/guard/ui.rb +193 -0
- data/lib/guard/version.rb +6 -0
- data/lib/guard/watcher.rb +114 -0
- data/lib/vendor/darwin/Gemfile +6 -0
- data/lib/vendor/darwin/Guardfile +8 -0
- data/lib/vendor/darwin/LICENSE +20 -0
- data/lib/vendor/darwin/README.rdoc +254 -0
- data/lib/vendor/darwin/Rakefile +21 -0
- data/lib/vendor/darwin/ext/extconf.rb +61 -0
- data/lib/vendor/darwin/ext/fsevent/fsevent_watch.c +226 -0
- data/lib/vendor/darwin/lib/rb-fsevent.rb +2 -0
- data/lib/vendor/darwin/lib/rb-fsevent/fsevent.rb +105 -0
- data/lib/vendor/darwin/lib/rb-fsevent/version.rb +3 -0
- data/lib/vendor/darwin/rb-fsevent.gemspec +24 -0
- 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 +75 -0
- data/lib/vendor/darwin/spec/spec_helper.rb +24 -0
- data/lib/vendor/linux/MIT-LICENSE +20 -0
- data/lib/vendor/linux/README.md +66 -0
- data/lib/vendor/linux/Rakefile +54 -0
- data/lib/vendor/linux/VERSION +1 -0
- data/lib/vendor/linux/lib/rb-inotify.rb +17 -0
- data/lib/vendor/linux/lib/rb-inotify/event.rb +139 -0
- data/lib/vendor/linux/lib/rb-inotify/native.rb +31 -0
- data/lib/vendor/linux/lib/rb-inotify/native/flags.rb +89 -0
- data/lib/vendor/linux/lib/rb-inotify/notifier.rb +308 -0
- data/lib/vendor/linux/lib/rb-inotify/watcher.rb +83 -0
- data/lib/vendor/linux/rb-inotify.gemspec +53 -0
- data/lib/vendor/windows/Gemfile +4 -0
- data/lib/vendor/windows/README.md +34 -0
- data/lib/vendor/windows/Rakefile +18 -0
- data/lib/vendor/windows/lib/rb-fchange.rb +14 -0
- data/lib/vendor/windows/lib/rb-fchange/event.rb +29 -0
- data/lib/vendor/windows/lib/rb-fchange/native.rb +45 -0
- data/lib/vendor/windows/lib/rb-fchange/native/flags.rb +78 -0
- data/lib/vendor/windows/lib/rb-fchange/notifier.rb +149 -0
- data/lib/vendor/windows/lib/rb-fchange/version.rb +3 -0
- data/lib/vendor/windows/lib/rb-fchange/watcher.rb +99 -0
- data/lib/vendor/windows/rb-fchange.gemspec +34 -0
- 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 +119 -0
- data/lib/vendor/windows/spec/spec_helper.rb +21 -0
- data/man/guard.1 +96 -0
- data/man/guard.1.html +181 -0
- metadata +193 -0
Binary file
|
data/bin/guard
ADDED
data/images/failed.png
ADDED
Binary file
|
data/images/pending.png
ADDED
Binary file
|
data/images/success.png
ADDED
Binary file
|
data/lib/guard.rb
ADDED
@@ -0,0 +1,463 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
# Guard is the main module for all Guard related modules and classes.
|
4
|
+
# Also other Guard implementation should use this namespace.
|
5
|
+
#
|
6
|
+
module Guard
|
7
|
+
|
8
|
+
autoload :UI, 'guard/ui'
|
9
|
+
autoload :Dsl, 'guard/dsl'
|
10
|
+
autoload :DslDescriber, 'guard/dsl_describer'
|
11
|
+
autoload :Group, 'guard/group'
|
12
|
+
autoload :Interactor, 'guard/interactor'
|
13
|
+
autoload :Listener, 'guard/listener'
|
14
|
+
autoload :Watcher, 'guard/watcher'
|
15
|
+
autoload :Notifier, 'guard/notifier'
|
16
|
+
autoload :Hook, 'guard/hook'
|
17
|
+
|
18
|
+
# The Guardfile template for `guard init`
|
19
|
+
GUARDFILE_TEMPLATE = File.expand_path('../guard/templates/Guardfile', __FILE__)
|
20
|
+
|
21
|
+
class << self
|
22
|
+
attr_accessor :options, :interactor, :listener, :lock
|
23
|
+
|
24
|
+
# Creates the initial Guardfile template or add a Guard implementation
|
25
|
+
# Guardfile template to an existing Guardfile.
|
26
|
+
#
|
27
|
+
# @see Guard::Guard.init
|
28
|
+
#
|
29
|
+
# @param [String] guard_name the name of the Guard to initialize
|
30
|
+
#
|
31
|
+
def initialize_template(guard_name = nil)
|
32
|
+
if !File.exist?('Guardfile')
|
33
|
+
::Guard::UI.info "Writing new Guardfile to #{ Dir.pwd }/Guardfile"
|
34
|
+
FileUtils.cp(GUARDFILE_TEMPLATE, 'Guardfile')
|
35
|
+
elsif guard_name.nil?
|
36
|
+
::Guard::UI.error "Guardfile already exists at #{ Dir.pwd }/Guardfile"
|
37
|
+
exit 1
|
38
|
+
end
|
39
|
+
|
40
|
+
if guard_name
|
41
|
+
guard_class = ::Guard.get_guard_class(guard_name)
|
42
|
+
guard_class.init(guard_name)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Initialize the Guard singleton.
|
47
|
+
#
|
48
|
+
# @option options [Boolean] clear if auto clear the UI should be done
|
49
|
+
# @option options [Boolean] notify if system notifications should be shown
|
50
|
+
# @option options [Boolean] debug if debug output should be shown
|
51
|
+
# @option options [Array<String>] group the list of groups to start
|
52
|
+
# @option options [String] watchdir the director to watch
|
53
|
+
# @option options [String] guardfile the path to the Guardfile
|
54
|
+
# @option options [Boolean] watch_all_modifications watches all file modifications if true
|
55
|
+
#
|
56
|
+
def setup(options = {})
|
57
|
+
@lock = Mutex.new
|
58
|
+
|
59
|
+
@options = options
|
60
|
+
@guards = []
|
61
|
+
self.reset_groups
|
62
|
+
@interactor = Interactor.new unless options[:no_interactions]
|
63
|
+
@listener = Listener.select_and_init(options[:watchdir] && File.expand_path(options[:watchdir]), options)
|
64
|
+
|
65
|
+
@options[:notify] && ENV['GUARD_NOTIFY'] != 'false' ? Notifier.turn_on : Notifier.turn_off
|
66
|
+
|
67
|
+
UI.clear if @options[:clear]
|
68
|
+
|
69
|
+
debug_command_execution if @options[:debug]
|
70
|
+
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
# Smart accessor for retrieving a specific guard or several guards at once.
|
75
|
+
#
|
76
|
+
# @param [String, Symbol] filter return the guard with the given name, or nil if not found
|
77
|
+
# @param [Regexp] filter returns all guards matching the Regexp, or [] if no guard found
|
78
|
+
# @param [Hash] filter returns all guards matching the given Hash.
|
79
|
+
# Example: `{ :name => 'rspec', :group => 'backend' }`, or [] if no guard found
|
80
|
+
# @param [NilClass] filter returns all guards
|
81
|
+
#
|
82
|
+
# @see Guard.groups
|
83
|
+
#
|
84
|
+
def guards(filter = nil)
|
85
|
+
case filter
|
86
|
+
when String, Symbol
|
87
|
+
@guards.find { |guard| guard.class.to_s.downcase.sub('guard::', '') == filter.to_s.downcase.gsub('-', '') }
|
88
|
+
when Regexp
|
89
|
+
@guards.find_all { |guard| guard.class.to_s.downcase.sub('guard::', '') =~ filter }
|
90
|
+
when Hash
|
91
|
+
filter.inject(@guards) do |matches, (k, v)|
|
92
|
+
if k.to_sym == :name
|
93
|
+
matches.find_all { |guard| guard.class.to_s.downcase.sub('guard::', '') == v.to_s.downcase.gsub('-', '') }
|
94
|
+
else
|
95
|
+
matches.find_all { |guard| guard.send(k).to_sym == v.to_sym }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
else
|
99
|
+
@guards
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Smart accessor for retrieving a specific group or several groups at once.
|
104
|
+
#
|
105
|
+
# @param [NilClass] filter returns all groups
|
106
|
+
# @param [String, Symbol] filter return the group with the given name, or nil if not found
|
107
|
+
# @param [Regexp] filter returns all groups matching the Regexp, or [] if no group found
|
108
|
+
#
|
109
|
+
# @see Guard.guards
|
110
|
+
#
|
111
|
+
def groups(filter = nil)
|
112
|
+
case filter
|
113
|
+
when String, Symbol
|
114
|
+
@groups.find { |group| group.name == filter.to_sym }
|
115
|
+
when Regexp
|
116
|
+
@groups.find_all { |group| group.name.to_s =~ filter }
|
117
|
+
else
|
118
|
+
@groups
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Initialize the groups array with the `:default` group.
|
123
|
+
#
|
124
|
+
# @see Guard.groups
|
125
|
+
#
|
126
|
+
def reset_groups
|
127
|
+
@groups = [Group.new(:default)]
|
128
|
+
end
|
129
|
+
|
130
|
+
# Start Guard by evaluate the `Guardfile`, initialize the declared Guards
|
131
|
+
# and start the available file change listener.
|
132
|
+
#
|
133
|
+
# @option options [Boolean] clear if auto clear the UI should be done
|
134
|
+
# @option options [Boolean] notify if system notifications should be shown
|
135
|
+
# @option options [Boolean] debug if debug output should be shown
|
136
|
+
# @option options [Array<String>] group the list of groups to start
|
137
|
+
# @option options [String] watchdir the director to watch
|
138
|
+
# @option options [String] guardfile the path to the Guardfile
|
139
|
+
#
|
140
|
+
def start(options = {})
|
141
|
+
setup(options)
|
142
|
+
|
143
|
+
Dsl.evaluate_guardfile(options)
|
144
|
+
|
145
|
+
listener.on_change do |files|
|
146
|
+
Dsl.reevaluate_guardfile if Watcher.match_guardfile?(files)
|
147
|
+
listener.changed_files += files if Watcher.match_files?(guards, files)
|
148
|
+
end
|
149
|
+
|
150
|
+
UI.info "Guard is now watching at '#{ listener.directory }'"
|
151
|
+
|
152
|
+
run_on_guards do |guard|
|
153
|
+
run_supervised_task(guard, :start)
|
154
|
+
end
|
155
|
+
|
156
|
+
interactor.start if interactor
|
157
|
+
listener.start
|
158
|
+
end
|
159
|
+
|
160
|
+
# Stop Guard listening to file changes
|
161
|
+
#
|
162
|
+
def stop
|
163
|
+
UI.info 'Bye bye...', :reset => true
|
164
|
+
|
165
|
+
run_on_guards do |guard|
|
166
|
+
run_supervised_task(guard, :stop)
|
167
|
+
end
|
168
|
+
|
169
|
+
listener.stop
|
170
|
+
abort
|
171
|
+
end
|
172
|
+
|
173
|
+
# Reload all Guards currently enabled.
|
174
|
+
#
|
175
|
+
# @param [Hash] An hash with a guard or a group scope
|
176
|
+
#
|
177
|
+
def reload(scopes)
|
178
|
+
run do
|
179
|
+
run_on_guards(scopes) do |guard|
|
180
|
+
run_supervised_task(guard, :reload)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Trigger `run_all` on all Guards currently enabled.
|
186
|
+
#
|
187
|
+
# @param [Hash] An hash with a guard or a group scope
|
188
|
+
#
|
189
|
+
def run_all(scopes)
|
190
|
+
run do
|
191
|
+
run_on_guards(scopes) do |guard|
|
192
|
+
run_supervised_task(guard, :run_all)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# Pause Guard listening to file changes.
|
198
|
+
#
|
199
|
+
def pause
|
200
|
+
if listener.paused?
|
201
|
+
UI.info 'Un-paused files modification listening', :reset => true
|
202
|
+
listener.clear_changed_files
|
203
|
+
listener.run
|
204
|
+
else
|
205
|
+
UI.info 'Paused files modification listening', :reset => true
|
206
|
+
listener.pause
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# Trigger `run_on_change` on all Guards currently enabled.
|
211
|
+
#
|
212
|
+
def run_on_change(files)
|
213
|
+
run do
|
214
|
+
run_on_guards do |guard|
|
215
|
+
run_on_change_task(files, guard)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Run a block where the listener and the interactor is
|
221
|
+
# blocked.
|
222
|
+
#
|
223
|
+
# @yield the block to run
|
224
|
+
#
|
225
|
+
def run
|
226
|
+
UI.clear if options[:clear]
|
227
|
+
|
228
|
+
lock.synchronize do
|
229
|
+
begin
|
230
|
+
interactor.stop if interactor
|
231
|
+
yield
|
232
|
+
rescue Interrupt
|
233
|
+
end
|
234
|
+
|
235
|
+
interactor.start if interactor
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
# Loop through all groups and run the given task (as block) for each Guard.
|
240
|
+
#
|
241
|
+
# Stop the task run for the all Guards within a group if one Guard
|
242
|
+
# throws `:task_has_failed`.
|
243
|
+
#
|
244
|
+
# @param [Hash] An hash with a guard or a group scope
|
245
|
+
#
|
246
|
+
def run_on_guards(scopes = {})
|
247
|
+
if guard = scopes[:guard]
|
248
|
+
yield(guard)
|
249
|
+
else
|
250
|
+
groups = scopes[:group] ? [scopes[:group]] : @groups
|
251
|
+
groups.each do |group|
|
252
|
+
catch :task_has_failed do
|
253
|
+
guards(:group => group.name).each do |guard|
|
254
|
+
yield(guard)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
# Run the `:run_on_change` task. When the option `:watch_all_modifications` is set,
|
262
|
+
# the task is split to run changed paths on {Guard::Guard#run_on_change}, whereas
|
263
|
+
# deleted paths run on {Guard::Guard#run_on_deletion}.
|
264
|
+
#
|
265
|
+
# @param [Array<String>] files the list of files to pass to the task
|
266
|
+
# @param [Guard::Guard] guard the guard to run
|
267
|
+
# @raise [:task_has_failed] when task has failed
|
268
|
+
#
|
269
|
+
def run_on_change_task(files, guard)
|
270
|
+
paths = Watcher.match_files(guard, files)
|
271
|
+
changes = changed_paths(paths)
|
272
|
+
deletions = deleted_paths(paths)
|
273
|
+
|
274
|
+
unless changes.empty?
|
275
|
+
UI.debug "#{ guard.class.name }#run_on_change with #{ changes.inspect }"
|
276
|
+
run_supervised_task(guard, :run_on_change, changes)
|
277
|
+
end
|
278
|
+
|
279
|
+
unless deletions.empty?
|
280
|
+
UI.debug "#{ guard.class.name }#run_on_deletion with #{ deletions.inspect }"
|
281
|
+
run_supervised_task(guard, :run_on_deletion, deletions)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
# Detects the paths that have changed.
|
286
|
+
#
|
287
|
+
# Deleted paths are prefixed by an exclamation point.
|
288
|
+
# @see Guard::Listener#modified_files
|
289
|
+
#
|
290
|
+
# @param [Array<String>] paths the watched paths
|
291
|
+
# @return [Array<String>] the changed paths
|
292
|
+
#
|
293
|
+
def changed_paths(paths)
|
294
|
+
paths.select { |f| !f.respond_to?(:start_with?) || !f.start_with?('!') }
|
295
|
+
end
|
296
|
+
|
297
|
+
# Detects the paths that have been deleted.
|
298
|
+
#
|
299
|
+
# Deleted paths are prefixed by an exclamation point.
|
300
|
+
# @see Guard::Listener#modified_files
|
301
|
+
#
|
302
|
+
# @param [Array<String>] paths the watched paths
|
303
|
+
# @return [Array<String>] the deleted paths
|
304
|
+
#
|
305
|
+
def deleted_paths(paths)
|
306
|
+
paths.select { |f| f.respond_to?(:start_with?) && f.start_with?('!') }.map { |f| f.slice(1..-1) }
|
307
|
+
end
|
308
|
+
|
309
|
+
# Run a Guard task, but remove the Guard when his work leads to a system failure.
|
310
|
+
#
|
311
|
+
# When the Group has `:halt_on_fail` disabled, we've to catch `:task_has_failed`
|
312
|
+
# here in order to avoid an uncaught throw error.
|
313
|
+
#
|
314
|
+
# @param [Guard::Guard] guard the Guard to execute
|
315
|
+
# @param [Symbol] task the task to run
|
316
|
+
# @param [Array] args the arguments for the task
|
317
|
+
# @raise [:task_has_failed] when task has failed
|
318
|
+
#
|
319
|
+
def run_supervised_task(guard, task, *args)
|
320
|
+
catch guard_symbol(guard) do
|
321
|
+
guard.hook("#{ task }_begin", *args)
|
322
|
+
result = guard.send(task, *args)
|
323
|
+
guard.hook("#{ task }_end", result)
|
324
|
+
|
325
|
+
result
|
326
|
+
end
|
327
|
+
|
328
|
+
rescue Exception => ex
|
329
|
+
UI.error("#{ guard.class.name } failed to achieve its <#{ task.to_s }>, exception was:" +
|
330
|
+
"\n#{ ex.class }: #{ ex.message }\n#{ ex.backtrace.join("\n") }")
|
331
|
+
|
332
|
+
guards.delete guard
|
333
|
+
UI.info("\n#{ guard.class.name } has just been fired")
|
334
|
+
|
335
|
+
ex
|
336
|
+
end
|
337
|
+
|
338
|
+
# Get the symbol we have to catch when running a supervised task.
|
339
|
+
# If we are within a Guard group that has the `:halt_on_fail`
|
340
|
+
# option set, we do NOT catch it here, it will be catched at the
|
341
|
+
# group level.
|
342
|
+
#
|
343
|
+
# @see .run_on_guards
|
344
|
+
#
|
345
|
+
# @param [Guard::Guard] guard the Guard to execute
|
346
|
+
# @return [Symbol] the symbol to catch
|
347
|
+
#
|
348
|
+
def guard_symbol(guard)
|
349
|
+
if guard.group.class == Symbol
|
350
|
+
group = groups(guard.group)
|
351
|
+
group.options[:halt_on_fail] ? :no_catch : :task_has_failed
|
352
|
+
else
|
353
|
+
:task_has_failed
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
# Add a Guard to use.
|
358
|
+
#
|
359
|
+
# @param [String] name the Guard name
|
360
|
+
# @param [Array<Watcher>] watchers the list of declared watchers
|
361
|
+
# @param [Array<Hash>] callbacks the list of callbacks
|
362
|
+
# @param [Hash] options the Guard options (see the given Guard documentation)
|
363
|
+
# @return [Guard::Guard] the guard added
|
364
|
+
#
|
365
|
+
def add_guard(name, watchers = [], callbacks = [], options = {})
|
366
|
+
if name.to_sym == :ego
|
367
|
+
UI.deprecation('Guard::Ego is now part of Guard. You can remove it from your Guardfile.')
|
368
|
+
else
|
369
|
+
guard_class = get_guard_class(name)
|
370
|
+
callbacks.each { |callback| Hook.add_callback(callback[:listener], guard_class, callback[:events]) }
|
371
|
+
guard = guard_class.new(watchers, options)
|
372
|
+
@guards << guard
|
373
|
+
guard
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
# Add a Guard group.
|
378
|
+
#
|
379
|
+
# @param [String] name the group name
|
380
|
+
# @option options [Boolean] halt_on_fail if a task execution
|
381
|
+
# should be halted for all Guards in this group if one Guard throws `:task_has_failed`
|
382
|
+
# @return [Guard::Group] the group added (or retrieved from the `@groups` variable if already present)
|
383
|
+
#
|
384
|
+
def add_group(name, options = {})
|
385
|
+
group = groups(name)
|
386
|
+
if group.nil?
|
387
|
+
group = Group.new(name, options)
|
388
|
+
@groups << group
|
389
|
+
end
|
390
|
+
group
|
391
|
+
end
|
392
|
+
|
393
|
+
# Tries to load the Guard main class.
|
394
|
+
#
|
395
|
+
# @param [String] name the name of the Guard
|
396
|
+
# @return [Class, nil] the loaded class
|
397
|
+
#
|
398
|
+
def get_guard_class(name)
|
399
|
+
name = name.to_s
|
400
|
+
try_require = false
|
401
|
+
const_name = name.downcase.gsub('-', '')
|
402
|
+
begin
|
403
|
+
require "guard/#{ name.downcase }" if try_require
|
404
|
+
self.const_get(self.constants.find { |c| c.to_s.downcase == const_name })
|
405
|
+
rescue TypeError
|
406
|
+
unless try_require
|
407
|
+
try_require = true
|
408
|
+
retry
|
409
|
+
else
|
410
|
+
UI.error "Could not find class Guard::#{ const_name.capitalize }"
|
411
|
+
end
|
412
|
+
rescue LoadError => loadError
|
413
|
+
UI.error "Could not load 'guard/#{ name.downcase }' or find class Guard::#{ const_name.capitalize }"
|
414
|
+
UI.error loadError.to_s
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
# Locate a path to a Guard gem.
|
419
|
+
#
|
420
|
+
# @param [String] name the name of the Guard without the prefix `guard-`
|
421
|
+
# @return [String] the full path to the Guard gem
|
422
|
+
#
|
423
|
+
def locate_guard(name)
|
424
|
+
if Gem::Version.create(Gem::VERSION) >= Gem::Version.create('1.8.0')
|
425
|
+
Gem::Specification.find_by_name("guard-#{ name }").full_gem_path
|
426
|
+
else
|
427
|
+
Gem.source_index.find_name("guard-#{ name }").last.full_gem_path
|
428
|
+
end
|
429
|
+
rescue
|
430
|
+
UI.error "Could not find 'guard-#{ name }' gem path."
|
431
|
+
end
|
432
|
+
|
433
|
+
# Returns a list of guard Gem names installed locally.
|
434
|
+
#
|
435
|
+
# @return [Array<String>] a list of guard gem names
|
436
|
+
#
|
437
|
+
def guard_gem_names
|
438
|
+
if Gem::Version.create(Gem::VERSION) >= Gem::Version.create('1.8.0')
|
439
|
+
Gem::Specification.find_all.select { |x| x.name =~ /^guard-/ }
|
440
|
+
else
|
441
|
+
Gem.source_index.find_name(/^guard-/)
|
442
|
+
end.map { |x| x.name.sub /^guard-/, '' }
|
443
|
+
end
|
444
|
+
|
445
|
+
# Adds a command logger in debug mode. This wraps common command
|
446
|
+
# execution functions and logs the executed command before execution.
|
447
|
+
#
|
448
|
+
def debug_command_execution
|
449
|
+
Kernel.send(:alias_method, :original_system, :system)
|
450
|
+
Kernel.send(:define_method, :system) do |command, *args|
|
451
|
+
::Guard::UI.debug "Command execution: #{ command } #{ args.join(' ') }"
|
452
|
+
original_system command, *args
|
453
|
+
end
|
454
|
+
|
455
|
+
Kernel.send(:alias_method, :original_backtick, :'`')
|
456
|
+
Kernel.send(:define_method, :'`') do |command|
|
457
|
+
::Guard::UI.debug "Command execution: #{ command }"
|
458
|
+
original_backtick command
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
end
|
463
|
+
end
|