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.
Files changed (77) hide show
  1. data/CHANGELOG.md +0 -6
  2. data/README.md +38 -30
  3. data/lib/guard.rb +158 -285
  4. data/lib/guard/cli.rb +16 -2
  5. data/lib/guard/dsl.rb +41 -20
  6. data/lib/guard/dsl_describer.rb +1 -1
  7. data/lib/guard/group.rb +1 -1
  8. data/lib/guard/guard.rb +39 -5
  9. data/lib/guard/guardfile.rb +70 -0
  10. data/lib/guard/runner.rb +179 -0
  11. data/lib/guard/ui.rb +1 -1
  12. data/lib/guard/version.rb +2 -4
  13. data/lib/guard/watcher.rb +1 -0
  14. metadata +16 -77
  15. data/bin/fsevent_watch_guard_guard +0 -0
  16. data/lib/guard/listener.rb +0 -376
  17. data/lib/guard/listeners/darwin.rb +0 -62
  18. data/lib/guard/listeners/linux.rb +0 -93
  19. data/lib/guard/listeners/polling.rb +0 -55
  20. data/lib/guard/listeners/windows.rb +0 -63
  21. data/lib/vendor/darwin/Gemfile +0 -6
  22. data/lib/vendor/darwin/Guardfile +0 -8
  23. data/lib/vendor/darwin/LICENSE +0 -20
  24. data/lib/vendor/darwin/README.rdoc +0 -255
  25. data/lib/vendor/darwin/Rakefile +0 -21
  26. data/lib/vendor/darwin/bin/fsevent_watch +0 -0
  27. data/lib/vendor/darwin/ext/fsevent_watch/Info.plist +0 -38
  28. data/lib/vendor/darwin/ext/fsevent_watch/LICENSE +0 -21
  29. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch.xcodeproj/project.pbxproj +0 -254
  30. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/TSICTString.c +0 -394
  31. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/TSICTString.h +0 -74
  32. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/cli.c +0 -160
  33. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/cli.h +0 -45
  34. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/common.h +0 -34
  35. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/compat.c +0 -20
  36. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/compat.h +0 -40
  37. data/lib/vendor/darwin/ext/fsevent_watch/fsevent_watch/main.c +0 -509
  38. data/lib/vendor/darwin/ext/fsevent_watch/xcconfig/Common.xcconfig +0 -82
  39. data/lib/vendor/darwin/ext/fsevent_watch/xcconfig/Debug.xcconfig +0 -19
  40. data/lib/vendor/darwin/ext/fsevent_watch/xcconfig/Release.xcconfig +0 -23
  41. data/lib/vendor/darwin/ext/fsevent_watch/xcconfig/fsevent_watch.xcconfig +0 -17
  42. data/lib/vendor/darwin/ext/rakefile.rb +0 -47
  43. data/lib/vendor/darwin/ext/rb-fsevent.xcconfig +0 -33
  44. data/lib/vendor/darwin/lib/rb-fsevent.rb +0 -2
  45. data/lib/vendor/darwin/lib/rb-fsevent/fsevent.rb +0 -111
  46. data/lib/vendor/darwin/lib/rb-fsevent/version.rb +0 -3
  47. data/lib/vendor/darwin/rb-fsevent.gemspec +0 -25
  48. data/lib/vendor/darwin/spec/fixtures/folder1/file1.txt +0 -0
  49. data/lib/vendor/darwin/spec/fixtures/folder1/folder2/file2.txt +0 -0
  50. data/lib/vendor/darwin/spec/rb-fsevent/fsevent_spec.rb +0 -88
  51. data/lib/vendor/darwin/spec/spec_helper.rb +0 -23
  52. data/lib/vendor/linux/MIT-LICENSE +0 -20
  53. data/lib/vendor/linux/README.md +0 -66
  54. data/lib/vendor/linux/Rakefile +0 -54
  55. data/lib/vendor/linux/VERSION +0 -1
  56. data/lib/vendor/linux/lib/rb-inotify.rb +0 -17
  57. data/lib/vendor/linux/lib/rb-inotify/event.rb +0 -139
  58. data/lib/vendor/linux/lib/rb-inotify/native.rb +0 -31
  59. data/lib/vendor/linux/lib/rb-inotify/native/flags.rb +0 -89
  60. data/lib/vendor/linux/lib/rb-inotify/notifier.rb +0 -308
  61. data/lib/vendor/linux/lib/rb-inotify/watcher.rb +0 -83
  62. data/lib/vendor/linux/rb-inotify.gemspec +0 -53
  63. data/lib/vendor/windows/Gemfile +0 -4
  64. data/lib/vendor/windows/README.md +0 -34
  65. data/lib/vendor/windows/Rakefile +0 -18
  66. data/lib/vendor/windows/lib/rb-fchange.rb +0 -14
  67. data/lib/vendor/windows/lib/rb-fchange/event.rb +0 -29
  68. data/lib/vendor/windows/lib/rb-fchange/native.rb +0 -45
  69. data/lib/vendor/windows/lib/rb-fchange/native/flags.rb +0 -78
  70. data/lib/vendor/windows/lib/rb-fchange/notifier.rb +0 -149
  71. data/lib/vendor/windows/lib/rb-fchange/version.rb +0 -3
  72. data/lib/vendor/windows/lib/rb-fchange/watcher.rb +0 -99
  73. data/lib/vendor/windows/rb-fchange.gemspec +0 -34
  74. data/lib/vendor/windows/spec/fixtures/folder1/file1.txt +0 -0
  75. data/lib/vendor/windows/spec/fixtures/folder1/folder2/file2.txt +0 -0
  76. data/lib/vendor/windows/spec/rb-fchange/fchange_spec.rb +0 -119
  77. data/lib/vendor/windows/spec/spec_helper.rb +0 -21
data/lib/guard/cli.rb CHANGED
@@ -47,17 +47,19 @@ module Guard
47
47
  :aliases => '-G',
48
48
  :banner => 'Specify a Guardfile'
49
49
 
50
+ # DEPRECATED
50
51
  method_option :no_vendor,
51
52
  :type => :boolean,
52
53
  :default => false,
53
54
  :aliases => '-I',
54
- :banner => 'Ignore vendored dependencies'
55
+ :banner => 'DEPRECATED: Ignore vendored dependencies'
55
56
 
57
+ # DEPRECATED
56
58
  method_option :watch_all_modifications,
57
59
  :type => :boolean,
58
60
  :default => false,
59
61
  :aliases => '-A',
60
- :banner => 'Watch for all file modifications including moves and deletions'
62
+ :banner => 'DEPRECATED: Watch for all file modifications including moves and deletions'
61
63
 
62
64
  method_option :no_interactions,
63
65
  :type => :boolean,
@@ -71,6 +73,18 @@ module Guard
71
73
  :aliases => '-B',
72
74
  :banner => 'Turn off warning when Bundler is not present'
73
75
 
76
+ # Listen options
77
+ method_option :latency,
78
+ :type => :numeric,
79
+ :aliases => '-l',
80
+ :banner => 'Overwrite Listen default latency'
81
+
82
+ method_option :force_polling,
83
+ :type => :boolean,
84
+ :default => false,
85
+ :aliases => '-p',
86
+ :banner => 'Force Listen polling listener usage'
87
+
74
88
  # Start Guard by initialize the defined Guards and watch the file system.
75
89
  # This is the default task, so calling `guard` is the same as calling `guard start`.
76
90
  #
data/lib/guard/dsl.rb CHANGED
@@ -6,8 +6,8 @@ module Guard
6
6
  # The main keywords of the DSL are `guard` and `watch`. These are necessary to define
7
7
  # the used Guards and the file changes they are watching.
8
8
  #
9
- # You can optionally group the Guards with the `group` keyword and ignore certain paths
10
- # with the `ignore_paths` keyword.
9
+ # You can optionally group the Guards with the `group` keyword and ignore and filter certain paths
10
+ # with the `ignore` and `filter` keywords.
11
11
  #
12
12
  # You can set your preferred system notification library with `notification` and pass
13
13
  # some optional configuration options for the library. If you don't configure a library,
@@ -82,6 +82,15 @@ module Guard
82
82
  # end
83
83
  #
84
84
  class Dsl
85
+
86
+ # Deprecation message for the `ignore_paths` method
87
+ IGNORE_PATHS_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
88
+ Starting with Guard v1.1 the use of the 'ignore_paths' Guardfile dsl method is deprecated.
89
+
90
+ Please replace that method with the better 'ignore' or/and 'filter' methods.
91
+ Documentation on the README: https://github.com/guard/guard#guardfile-dsl-ignore
92
+ EOS
93
+
85
94
  class << self
86
95
 
87
96
  @@options = nil
@@ -105,23 +114,18 @@ module Guard
105
114
  # Re-evaluate the `Guardfile` to update the current Guard configuration.
106
115
  #
107
116
  def reevaluate_guardfile
108
- ::Guard.run do
109
- before_reevaluate_guardfile
110
- Dsl.evaluate_guardfile(@@options)
111
- after_reevaluate_guardfile
112
- end
117
+ before_reevaluate_guardfile
118
+ Dsl.evaluate_guardfile(@@options)
119
+ after_reevaluate_guardfile
113
120
  end
114
121
 
115
122
  # Stop Guards and clear internal state
116
123
  # before the Guardfile will be re-evaluated.
117
124
  #
118
125
  def before_reevaluate_guardfile
119
- ::Guard.run_on_guards do |guard|
120
- ::Guard.run_supervised_task(guard, :stop)
121
- end
122
-
126
+ ::Guard.runner.run(:stop)
123
127
  ::Guard.guards.clear
124
- ::Guard.reset_groups
128
+ ::Guard.setup_groups
125
129
  ::Guard::Notifier.clear_notifications
126
130
 
127
131
  @@options.delete(:guardfile_contents)
@@ -140,9 +144,7 @@ module Guard
140
144
  ::Guard::UI.info(msg)
141
145
  ::Guard::Notifier.notify(msg, :title => 'Guard re-evaluate')
142
146
 
143
- ::Guard.run_on_guards do |guard|
144
- ::Guard.run_supervised_task(guard, :start)
145
- end
147
+ ::Guard.runner.run(:start)
146
148
  end
147
149
  end
148
150
 
@@ -421,18 +423,37 @@ module Guard
421
423
  @callbacks << { :events => events, :listener => listener }
422
424
  end
423
425
 
424
- # Ignore certain paths globally.
426
+ # @deprecated Ignore certain paths globally.
425
427
  #
426
428
  # @example Ignore some paths
427
429
  # ignore_paths ".git", ".svn"
428
430
  #
429
431
  # @param [Array] paths the list of paths to ignore
430
432
  #
431
- # @see Guard::Listener
432
- #
433
433
  def ignore_paths(*paths)
434
- UI.info "Ignoring paths: #{ paths.join(', ') }"
435
- ::Guard.listener.ignore_paths.push(*paths)
434
+ UI.deprecation(IGNORE_PATHS_DEPRECATION)
435
+ end
436
+
437
+ # Ignore certain patterns paths globally.
438
+ #
439
+ # @example Ignore some paths
440
+ # ignore %r{^ignored/path/}, /man/
441
+ #
442
+ # @param [Regexp] regexp a pattern for ignoring paths
443
+ #
444
+ def ignore(*regexps)
445
+ ::Guard.listener = ::Guard.listener.ignore(*regexps)
446
+ end
447
+
448
+ # Filter certain patterns paths globally.
449
+ #
450
+ # @example Filter some files
451
+ # ignore /\.txt$/, /.*\.zip/
452
+ #
453
+ # @param [Regexp] regexp a pattern for filtering paths
454
+ #
455
+ def filter(*regexps)
456
+ ::Guard.listener = ::Guard.listener.filter(*regexps)
436
457
  end
437
458
 
438
459
  end
@@ -2,7 +2,7 @@ require 'guard/dsl'
2
2
 
3
3
  module Guard
4
4
 
5
- autoload :UI, 'guard/ui'
5
+ autoload :UI, 'guard/ui'
6
6
 
7
7
  # The DslDescriber overrides methods to create an internal structure
8
8
  # of the Guardfile that is used in some inspection utility methods
data/lib/guard/group.rb CHANGED
@@ -20,7 +20,7 @@ module Guard
20
20
 
21
21
  attr_accessor :name, :options
22
22
 
23
- # Initialize a Group.
23
+ # Initializes a Group.
24
24
  #
25
25
  # @param [String] name the name of the group
26
26
  # @param [Hash] options the group options
data/lib/guard/guard.rb CHANGED
@@ -38,7 +38,7 @@ module Guard
38
38
 
39
39
  attr_accessor :watchers, :options, :group
40
40
 
41
- # Initialize a Guard.
41
+ # Initializes a Guard.
42
42
  #
43
43
  # @param [Array<Guard::Watcher>] watchers the Guard file watchers
44
44
  # @param [Hash] options the custom Guard options
@@ -106,24 +106,58 @@ module Guard
106
106
  def run_all
107
107
  end
108
108
 
109
+ # Default behavious on file(s) changes that the Guard watches.
110
+ #
111
+ # @param [Array<String>] paths the changes files or paths
112
+ # @raise [:task_has_failed] when run_on_change has failed
113
+ # @return [Object] the task result
114
+ #
115
+ def run_on_changes(paths)
116
+ raise NotImplementedError
117
+ end
118
+
119
+ # Called on file(s) additions that the Guard watches.
120
+ #
121
+ # @param [Array<String>] paths the changes files or paths
122
+ # @raise [:task_has_failed] when run_on_change has failed
123
+ # @return [Object] the task result
124
+ #
125
+ def run_on_addtions(paths)
126
+ run_on_changes(paths)
127
+ end
128
+
109
129
  # Called on file(s) modifications that the Guard watches.
110
130
  #
111
131
  # @param [Array<String>] paths the changes files or paths
112
132
  # @raise [:task_has_failed] when run_on_change has failed
113
133
  # @return [Object] the task result
114
134
  #
115
- def run_on_change(paths)
135
+ def run_on_modifications(paths)
136
+ run_on_changes(paths)
116
137
  end
117
138
 
118
- # Called on file(s) deletions that the Guard watches.
139
+ # Called on file(s) removals that the Guard watches.
119
140
  #
120
- # @param [Array<String>] paths the deleted files or paths
141
+ # @param [Array<String>] paths the changes files or paths
121
142
  # @raise [:task_has_failed] when run_on_change has failed
122
143
  # @return [Object] the task result
123
144
  #
124
- def run_on_deletion(paths)
145
+ def run_on_removals(paths)
146
+ run_on_changes(paths)
125
147
  end
126
148
 
149
+ # @deprecated Use #run_on_modifications or #run_on_addtions instead
150
+ #
151
+ # def run_on_change(paths)
152
+ # raise NotImplementedError
153
+ # end
154
+
155
+ # @deprecated Use #run_on_removals instead
156
+ #
157
+ # def run_on_deletion(paths)
158
+ # raise NotImplementedError
159
+ # end
160
+
127
161
  end
128
162
 
129
163
  end
@@ -0,0 +1,70 @@
1
+ module Guard
2
+
3
+ # The Guardfile is responsible for generating the Guardfile
4
+ # and adding guards' template into it.
5
+ #
6
+ # @see Guard::CLI
7
+ #
8
+ class Guardfile
9
+
10
+ class << self
11
+
12
+ # Creates the initial Guardfile template when it does not
13
+ # already exist.
14
+ #
15
+ # @see Guard::CLI.init
16
+ #
17
+ # @param [Hash] options The options for creating a Guardfile
18
+ # @option options [Boolean] :abort_on_existence Whether to abort or not when a Guardfile already exists
19
+ #
20
+ def create_guardfile(options = {})
21
+ if !File.exist?('Guardfile')
22
+ ::Guard::UI.info "Writing new Guardfile to #{ Dir.pwd }/Guardfile"
23
+ FileUtils.cp(GUARDFILE_TEMPLATE, 'Guardfile')
24
+ elsif options[:abort_on_existence]
25
+ ::Guard::UI.error "Guardfile already exists at #{ Dir.pwd }/Guardfile"
26
+ abort
27
+ end
28
+ end
29
+
30
+ # Adds the Guardfile template of a Guard implementation
31
+ # to an existing Guardfile.
32
+ #
33
+ # @see Guard::CLI.init
34
+ #
35
+ # @param [String] guard_name the name of the Guard or template to initialize
36
+ #
37
+ def initialize_template(guard_name)
38
+ guard_class = ::Guard.get_guard_class(guard_name, true)
39
+
40
+ if guard_class
41
+ guard_class.init(guard_name)
42
+ elsif File.exist?(File.join(HOME_TEMPLATES, guard_name))
43
+ content = File.read('Guardfile')
44
+ template = File.read(File.join(HOME_TEMPLATES, guard_name))
45
+
46
+ File.open('Guardfile', 'wb') do |f|
47
+ f.puts(content)
48
+ f.puts('')
49
+ f.puts(template)
50
+ end
51
+
52
+ ::Guard::UI.info "#{ guard_name } template added to Guardfile, feel free to edit it"
53
+ else
54
+ const_name = guard_name.downcase.gsub('-', '')
55
+ UI.error "Could not load 'guard/#{ guard_name.downcase }' or '~/.guard/templates/#{ guard_name.downcase }' or find class Guard::#{ const_name.capitalize }"
56
+ end
57
+ end
58
+
59
+ # Adds the templates of all installed Guard implementations
60
+ # to an existing Guardfile.
61
+ #
62
+ # @see Guard::CLI.init
63
+ #
64
+ def initialize_all_templates
65
+ ::Guard.guard_gem_names.each { |g| initialize_template(g) }
66
+ end
67
+
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,179 @@
1
+ module Guard
2
+
3
+ # The runner is responsible for running all methods defined on each guards.
4
+ #
5
+ class Runner
6
+
7
+ # Deprecation message for the `run_on_change` method
8
+ RUN_ON_CHANGE_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
9
+ Starting with Guard v1.1 the use of the 'run_on_change' method in the '%s' guard is deprecated.
10
+
11
+ Please consider replacing that method-call with 'run_on_changes' if the type of change
12
+ is not important for your usecase or using either 'run_on_modifications' or 'run_on_addtions'
13
+ based on the type of the changes you want to handle.
14
+
15
+ For more information on how to update existing guards, please head over to:
16
+ https://github.com/guard/guard/wiki/Upgrade-guide-for-existing-guards-to-Guard-v1.1
17
+ EOS
18
+
19
+ # Deprecation message for the `run_on_deletion` method
20
+ RUN_ON_DELETION_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
21
+ Starting with Guard v1.1 the use of the 'run_on_deletion' method in the '%s' guard is deprecated.
22
+
23
+ Please consider replacing that method-call with 'run_on_removals' for future proofing your code.
24
+
25
+ For more information on how to update existing guards, please head over to:
26
+ https://github.com/guard/guard/wiki/Upgrade-guide-for-existing-guards-to-Guard-v1.1
27
+ EOS
28
+
29
+ # Displays a warning for each deprecated-method used is any registered guard.
30
+ #
31
+ def deprecation_warning
32
+ ::Guard.guards.each do |guard|
33
+ UI.deprecation(RUN_ON_CHANGE_DEPRECATION % guard.class.name) if guard.respond_to?(:run_on_change)
34
+ UI.deprecation(RUN_ON_DELETION_DEPRECATION % guard.class.name) if guard.respond_to?(:run_on_deletion)
35
+ end
36
+ end
37
+
38
+ # Runs a Guard-task on all registered guards.
39
+ #
40
+ # @param [Symbol] task the task to run
41
+ # @param [Hash] scope either the guard or the group to run the task on
42
+ #
43
+ # @see self.run_supervised_task
44
+ #
45
+ def run(task, scopes = {})
46
+ scoped_guards(scopes) do |guard|
47
+ run_supervised_task(guard, task)
48
+ end
49
+ end
50
+
51
+ # Runs the appropriate tasks on all registered guards
52
+ # based on the passed changes.
53
+ #
54
+ # @param [Array<String>] modified the modified paths.
55
+ # @param [Array<String>] added the added paths.
56
+ # @param [Array<String>] removed the removed paths.
57
+ #
58
+ def run_on_changes(modified, added, removed)
59
+ scoped_guards do |guard|
60
+ modified_paths = Watcher.match_files(guard, modified)
61
+ added_paths = Watcher.match_files(guard, added)
62
+ removed_paths = Watcher.match_files(guard, removed)
63
+
64
+ if !modified_paths.empty? || !added_paths.empty? || !removed_paths.empty?
65
+ UI.clear
66
+
67
+ unless modified_paths.empty?
68
+ run_first_task_found(guard, [:run_on_modifications, :run_on_change], modified_paths)
69
+ end
70
+ unless added_paths.empty?
71
+ run_first_task_found(guard, [:run_on_addtions, :run_on_change], added_paths)
72
+ end
73
+ unless removed_paths.empty?
74
+ run_first_task_found(guard, [:run_on_removals, :run_on_deletion], removed_paths)
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ # Run a Guard task, but remove the Guard when his work leads to a system failure.
81
+ #
82
+ # When the Group has `:halt_on_fail` disabled, we've to catch `:task_has_failed`
83
+ # here in order to avoid an uncaught throw error.
84
+ #
85
+ # @param [Guard::Guard] guard the Guard to execute
86
+ # @param [Symbol] task the task to run
87
+ # @param [Array] args the arguments for the task
88
+ # @raise [:task_has_failed] when task has failed
89
+ #
90
+ def run_supervised_task(guard, task, *args)
91
+ ::Guard.within_preserved_state do
92
+ begin
93
+ catch Runner.stopping_symbol_for(guard) do
94
+ guard.hook("#{ task }_begin", *args)
95
+ result = guard.send(task, *args)
96
+ guard.hook("#{ task }_end", result)
97
+ result
98
+ end
99
+
100
+ rescue NotImplementedError => ex
101
+ raise ex
102
+ rescue Exception => ex
103
+ UI.error("#{ guard.class.name } failed to achieve its <#{ task.to_s }>, exception was:" +
104
+ "\n#{ ex.class }: #{ ex.message }\n#{ ex.backtrace.join("\n") }")
105
+
106
+ ::Guard.guards.delete guard
107
+ UI.info("\n#{ guard.class.name } has just been fired")
108
+
109
+ ex
110
+ end
111
+ end
112
+ end
113
+
114
+ # Returns the symbol that has to be caught when running a supervised task.
115
+ #
116
+ # @note If a Guard group is being run and it has the `:halt_on_fail`
117
+ # option set, this method returns :no_catch as it will be caught at the
118
+ # group level.
119
+ # @see .scoped_guards
120
+ #
121
+ # @param [Guard::Guard] guard the Guard to execute
122
+ #
123
+ # @return [Symbol] the symbol to catch
124
+ #
125
+ def self.stopping_symbol_for(guard)
126
+ return :task_has_failed if guard.group.class != Symbol
127
+
128
+ group = ::Guard.groups(guard.group)
129
+ group.options[:halt_on_fail] ? :no_catch : :task_has_failed
130
+ end
131
+
132
+ private
133
+
134
+ # Tries to run the first implemented task by a given guard
135
+ # from a collection of tasks.
136
+ #
137
+ # @param [Guard::Guard] guard the guard to run the found task on
138
+ # @param [Array<Symbol>] tasks the tasks to run the first among
139
+ # @param [Object] task_param the param to pass to each task
140
+ #
141
+ def run_first_task_found(guard, tasks, task_param)
142
+ enum = tasks.to_enum
143
+
144
+ begin
145
+ task = enum.next
146
+ UI.debug "Trying to run #{ guard.class.name }##{ task.to_s } with #{ task_param.inspect }"
147
+ run_supervised_task(guard, task, task_param)
148
+ rescue StopIteration
149
+ # Do nothing
150
+ rescue NotImplementedError
151
+ retry
152
+ end
153
+ end
154
+
155
+ # Loop through all groups and run the given task for each Guard.
156
+ #
157
+ # Stop the task run for the all Guards within a group if one Guard
158
+ # throws `:task_has_failed`.
159
+ #
160
+ # @param [Hash] scope an hash with a guard or a group scope
161
+ # @yield the task to run
162
+ #
163
+ def scoped_guards(scopes = {})
164
+ if guard = scopes[:guard]
165
+ yield(guard)
166
+ else
167
+ groups = scopes[:group] ? [scopes[:group]] : ::Guard.groups
168
+ groups.each do |group|
169
+ catch :task_has_failed do
170
+ ::Guard.guards(:group => group.name).each do |guard|
171
+ yield(guard)
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+ end
179
+ end