guard 1.8.3 → 2.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +68 -10
  3. data/README.md +54 -33
  4. data/lib/guard.rb +133 -483
  5. data/lib/guard/cli.rb +78 -82
  6. data/lib/guard/commander.rb +121 -0
  7. data/lib/guard/commands/all.rb +1 -1
  8. data/lib/guard/commands/reload.rb +1 -1
  9. data/lib/guard/deprecated_methods.rb +59 -0
  10. data/lib/guard/deprecator.rb +107 -0
  11. data/lib/guard/dsl.rb +143 -329
  12. data/lib/guard/dsl_describer.rb +101 -57
  13. data/lib/guard/group.rb +27 -8
  14. data/lib/guard/guard.rb +25 -150
  15. data/lib/guard/guardfile.rb +35 -85
  16. data/lib/guard/guardfile/evaluator.rb +245 -0
  17. data/lib/guard/guardfile/generator.rb +89 -0
  18. data/lib/guard/interactor.rb +147 -163
  19. data/lib/guard/notifier.rb +83 -137
  20. data/lib/guard/notifiers/base.rb +220 -0
  21. data/lib/guard/notifiers/emacs.rb +39 -37
  22. data/lib/guard/notifiers/file_notifier.rb +29 -25
  23. data/lib/guard/notifiers/gntp.rb +68 -75
  24. data/lib/guard/notifiers/growl.rb +49 -52
  25. data/lib/guard/notifiers/growl_notify.rb +51 -56
  26. data/lib/guard/notifiers/libnotify.rb +41 -48
  27. data/lib/guard/notifiers/notifysend.rb +58 -38
  28. data/lib/guard/notifiers/rb_notifu.rb +54 -54
  29. data/lib/guard/notifiers/terminal_notifier.rb +48 -36
  30. data/lib/guard/notifiers/terminal_title.rb +23 -19
  31. data/lib/guard/notifiers/tmux.rb +110 -93
  32. data/lib/guard/options.rb +21 -0
  33. data/lib/guard/plugin.rb +66 -0
  34. data/lib/guard/plugin/base.rb +178 -0
  35. data/lib/guard/plugin/hooker.rb +123 -0
  36. data/lib/guard/plugin_util.rb +158 -0
  37. data/lib/guard/rake_task.rb +47 -0
  38. data/lib/guard/runner.rb +62 -82
  39. data/lib/guard/setuper.rb +248 -0
  40. data/lib/guard/ui.rb +24 -80
  41. data/lib/guard/ui/colors.rb +60 -0
  42. data/lib/guard/version.rb +1 -2
  43. data/lib/guard/watcher.rb +30 -30
  44. data/man/guard.1 +4 -4
  45. data/man/guard.1.html +6 -4
  46. metadata +25 -11
  47. data/lib/guard/hook.rb +0 -120
@@ -0,0 +1,107 @@
1
+ require 'guard/ui'
2
+
3
+ module Guard
4
+ class Deprecator
5
+
6
+ MORE_INFO_ON_UPGRADING_TO_GUARD_1_1 = <<-EOS.gsub(/^\s*/, '')
7
+ For more information on how to update existing Guard plugins, please head over
8
+ to: https://github.com/guard/guard/wiki/Upgrade-guide-for-existing-guards-to-Guard-v1.1
9
+ EOS
10
+
11
+ MORE_INFO_ON_UPGRADING_TO_GUARD_2 = <<-EOS.gsub(/^\s*/, '')
12
+ For more information on how to upgrade for Guard 2.0, please head over
13
+ to: https://github.com/guard/guard/wiki/Upgrading-to-Guard-2.0%s
14
+ EOS
15
+
16
+ ADD_GUARD_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
17
+ Starting with Guard 2.0 'Guard.add_guard(name, options = {})' is deprecated.
18
+
19
+ Please use 'Guard.add_plugin(name, options = {})' instead.
20
+
21
+ #{MORE_INFO_ON_UPGRADING_TO_GUARD_2 % '#deprecated-methods'}
22
+ EOS
23
+
24
+ GUARDS_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
25
+ Starting with Guard 2.0 'Guard.guards(filter)' is deprecated.
26
+
27
+ Please use 'Guard.plugins(filter)' instead.
28
+
29
+ #{MORE_INFO_ON_UPGRADING_TO_GUARD_2 % '#deprecated-methods'}
30
+ EOS
31
+
32
+ # Deprecator message for the `Guard.get_guard_class` method
33
+ GET_GUARD_CLASS_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
34
+ Starting with Guard 2.0 'Guard.get_guard_class(name, fail_gracefully =
35
+ false)' is deprecated and is now always on.
36
+
37
+ Please use 'Guard::PluginUtil.new(name).plugin_class(fail_gracefully:
38
+ fail_gracefully)' instead.
39
+
40
+ #{MORE_INFO_ON_UPGRADING_TO_GUARD_2 % '#deprecated-methods'}
41
+ EOS
42
+
43
+ # Deprecator message for the `Guard.locate_guard` method
44
+ LOCATE_GUARD_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
45
+ Starting with Guard 2.0 'Guard.locate_guard(name)' is deprecated.
46
+
47
+ Please use 'Guard::PluginUtil.new(name).plugin_location' instead.
48
+
49
+ #{MORE_INFO_ON_UPGRADING_TO_GUARD_2 % '#deprecated-methods'}
50
+ EOS
51
+
52
+ # Deprecator message for the `Guard.guard_gem_names` method
53
+ GUARD_GEM_NAMES_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
54
+ Starting with Guard 2.0 'Guard.guard_gem_names' is deprecated.
55
+
56
+ Please use 'Guard::PluginUtil.plugin_names' instead.
57
+
58
+ #{MORE_INFO_ON_UPGRADING_TO_GUARD_2 % '#deprecated-methods'}
59
+ EOS
60
+
61
+ # Deprecator message for the `Guard::Dsl.evaluate_guardfile` method
62
+ EVALUATE_GUARDFILE_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
63
+ Starting with Guard 2.0 'Guard::Dsl.evaluate_guardfile(options)' is deprecated.
64
+
65
+ Please use 'Guard::Guardfile::Evaluator.new(options).evaluate_guardfile' instead.
66
+
67
+ #{MORE_INFO_ON_UPGRADING_TO_GUARD_2 % '#deprecated-methods-1'}
68
+ EOS
69
+
70
+ # Deprecator message for the `Guardfile.create_guardfile` method
71
+ CREATE_GUARDFILE_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
72
+ Starting with Guard 2.0 'Guard::Guardfile.create_guardfile(options)' is deprecated.
73
+
74
+ Please use 'Guard::Guardfile::Generator.new(options).create_guardfile' instead.
75
+
76
+ #{MORE_INFO_ON_UPGRADING_TO_GUARD_2 % '#deprecated-methods-2'}
77
+ EOS
78
+
79
+ # Deprecator message for the `Guardfile.initialize_template` method
80
+ INITIALIZE_TEMPLATE_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
81
+ Starting with Guard 2.0 'Guard::Guardfile.initialize_template(plugin_name)' is deprecated.
82
+
83
+ Please use 'Guard::Guardfile::Generator.new.initialize_template(plugin_name)' instead.
84
+
85
+ #{MORE_INFO_ON_UPGRADING_TO_GUARD_2 % '#deprecated-methods-2'}
86
+ EOS
87
+
88
+ # Deprecator message for the `Guardfile.initialize_all_templates` method
89
+ INITIALIZE_ALL_TEMPLATES_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
90
+ Starting with Guard 2.0 'Guard::Guardfile.initialize_all_templates' is deprecated.
91
+
92
+ Please use 'Guard::Guardfile::Generator.new.initialize_all_templates' instead.
93
+
94
+ #{MORE_INFO_ON_UPGRADING_TO_GUARD_2 % '#deprecated-methods-2'}
95
+ EOS
96
+
97
+ # Deprecator message for when a Guard plugin inherits from Guard::Guard
98
+ GUARD_GUARD_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
99
+ Starting with Guard 2.0, Guard::%s should inherit from Guard::Plugin instead of Guard::Guard.
100
+
101
+ Please note that the constructor signature has changed from Guard::Guard#initialize(watchers = [], options = {}) to Guard::Plugin#initialize(options = {}).
102
+
103
+ #{MORE_INFO_ON_UPGRADING_TO_GUARD_2 % '#changes-in-guardguard'}
104
+ EOS
105
+
106
+ end
107
+ end
@@ -1,347 +1,159 @@
1
+ require 'guard/guardfile'
2
+ require 'guard/interactor'
3
+ require 'guard/notifier'
4
+ require 'guard/ui'
5
+ require 'guard/watcher'
6
+
1
7
  module Guard
2
8
 
3
- # The DSL class provides the methods that are used in each `Guardfile` to describe
4
- # the behaviour of Guard.
9
+ # The Dsl class provides the methods that are used in each `Guardfile` to
10
+ # describe the behaviour of Guard.
5
11
  #
6
- # The main keywords of the DSL are `guard` and `watch`. These are necessary to define
7
- # the used Guard plugins and the file changes they are watching.
12
+ # The main keywords of the DSL are {#guard} and {#watch}. These are necessary
13
+ # to define the used Guard plugins and the file changes they are watching.
8
14
  #
9
- # You can optionally group the Guard plugins with the `group` keyword and ignore and filter certain paths
10
- # with the `ignore` and `filter` keywords.
15
+ # You can optionally group the Guard plugins with the {#group} keyword and
16
+ # ignore and filter certain paths with the {#ignore} and {#filter} keywords.
11
17
  #
12
- # You can set your preferred system notification library with `notification` and pass
13
- # some optional configuration options for the library. If you don't configure a library,
14
- # Guard will automatically pick one with default options (if you don't want notifications,
15
- # specify `:off` as library). @see ::Guard::Notifier for more information about the supported libraries.
18
+ # You can set your preferred system notification library with {#notification}
19
+ # and pass some optional configuration options for the library. If you don't
20
+ # configure a library, Guard will automatically pick one with default options
21
+ # (if you don't want notifications, specify `:off` as library). Please see
22
+ # {Notifier} for more information about the supported libraries.
16
23
  #
17
- # A more advanced DSL use is the `callback` keyword that allows you to execute arbitrary
18
- # code before or after any of the `start`, `stop`, `reload`, `run_all`, `run_on_changes`,
19
- # `run_on_additions`, `run_on_modifications` and `run_on_removals` Guard plugins method.
20
- # You can even insert more hooks inside these methods.
21
- # Please [checkout the Wiki page](https://github.com/guard/guard/wiki/Hooks-and-callbacks) for more details.
24
+ # A more advanced DSL use is the {#callback} keyword that allows you to
25
+ # execute arbitrary code before or after any of the {Plugin::Base#start},
26
+ # {Plugin::Base#stop}, {Plugin::Base#reload}, {Plugin::Base#run_all},
27
+ # {Plugin::Base#run_on_changes}, {Plugin::Base#run_on_additions},
28
+ # {Plugin::Base#run_on_modifications} and {Plugin::Base#run_on_removals}
29
+ # Guard plugins method.
30
+ # You can even insert more hooks inside these methods. Please [checkout the
31
+ # Wiki page](https://github.com/guard/guard/wiki/Hooks-and-callbacks) for
32
+ # more details.
22
33
  #
23
34
  # The DSL will also evaluate normal Ruby code.
24
35
  #
25
36
  # There are two possible locations for the `Guardfile`:
26
- # - The `Guardfile` in the current directory where Guard has been started
27
- # - The `.Guardfile` in your home directory.
28
37
  #
29
- # In addition, if a user configuration `.guard.rb` in your home directory is found, it will
30
- # be appended to the current project `Guardfile`.
38
+ # * The `Guardfile` in the current directory where Guard has been started
39
+ # * The `.Guardfile` in your home directory.
40
+ #
41
+ # In addition, if a user configuration `.guard.rb` in your home directory is
42
+ # found, it will be appended to the current project `Guardfile`.
31
43
  #
32
44
  # @see https://github.com/guard/guard/wiki/Guardfile-examples
33
45
  #
34
46
  class Dsl
35
47
 
36
- require 'guard'
37
- require 'guard/dsl'
38
- require 'guard/interactor'
39
- require 'guard/notifier'
40
- require 'guard/ui'
41
- require 'guard/watcher'
42
-
43
- # Deprecation message for the `ignore_paths` method
44
- IGNORE_PATHS_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
45
- Starting with Guard v1.1 the use of the 'ignore_paths' Guardfile DSL method is deprecated.
46
-
47
- Please replace that method with the better 'ignore' or/and 'filter' methods.
48
- Documentation on the README: https://github.com/guard/guard#ignore
49
- EOS
50
-
51
- # Deprecation message for the `interactor` method
52
- INTERACTOR_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
53
- Starting with Guard v1.4 the use of the 'interactor' Guardfile DSL method is only used to
54
- disable or pass options to the Pry interactor. All other usages are deprecated.
55
- EOS
56
-
57
- class << self
58
-
59
- attr_accessor :options
60
-
61
- # Evaluate the DSL methods in the `Guardfile`.
62
- #
63
- # @option options [Array<Symbol,String>] groups the groups to evaluate
64
- # @option options [String] guardfile the path to a valid Guardfile
65
- # @option options [String] guardfile_contents a string representing the content of a valid Guardfile
66
- # @raise [ArgumentError] when options are not a Hash
67
- #
68
- def evaluate_guardfile(options = {})
69
- raise ArgumentError.new('No option hash passed to evaluate_guardfile!') unless options.is_a?(Hash)
70
-
71
- self.options = options.dup
72
-
73
- fetch_guardfile_contents
74
- instance_eval_guardfile(guardfile_contents_with_user_config)
75
- end
76
-
77
- # Re-evaluate the `Guardfile` to update the current Guard configuration.
78
- #
79
- def reevaluate_guardfile
80
- before_reevaluate_guardfile
81
- ::Guard::Dsl.evaluate_guardfile(options)
82
- after_reevaluate_guardfile
83
- end
84
-
85
- # Stop Guard and clear internal state
86
- # before the Guardfile will be re-evaluated.
87
- #
88
- def before_reevaluate_guardfile
89
- ::Guard.runner.run(:stop)
90
- ::Guard.guards.clear
91
- ::Guard.setup_groups
92
- ::Guard::Notifier.clear_notifications
93
-
94
- options.delete(:guardfile_contents)
95
- end
96
-
97
- # Start Guard and notification and show a message
98
- # after the Guardfile has been re-evaluated.
99
- #
100
- def after_reevaluate_guardfile
101
- ::Guard::Notifier.turn_on if ::Guard::Notifier.enabled?
102
-
103
- if ::Guard.guards.empty?
104
- ::Guard::Notifier.notify('No guards found in Guardfile, please add at least one.', :title => 'Guard re-evaluate', :image => :failed)
105
- else
106
- msg = 'Guardfile has been re-evaluated.'
107
- ::Guard::UI.info(msg)
108
- ::Guard::Notifier.notify(msg, :title => 'Guard re-evaluate')
109
-
110
- ::Guard.runner.run(:start)
111
- end
112
- end
113
-
114
- # Evaluate the content of the `Guardfile`.
115
- #
116
- # @param [String] contents the content to evaluate.
117
- #
118
- def instance_eval_guardfile(contents)
119
- new.instance_eval(contents, options[:guardfile_path], 1)
120
- rescue
121
- ::Guard::UI.error "Invalid Guardfile, original error is:\n#{ $! }"
122
- end
123
-
124
- # Test if the current `Guardfile` contains a specific Guard plugin.
125
- #
126
- # @param [String] guard_name the name of the Guard
127
- # @return [Boolean] whether the Guard has been declared
128
- #
129
- def guardfile_include?(guard_name)
130
- guardfile_contents.match(/^guard\s*\(?\s*['":]#{ guard_name }['"]?/)
131
- end
132
-
133
- # Read the current `Guardfile` content.
134
- #
135
- # @param [String] guardfile_path the path to the Guardfile
136
- #
137
- def read_guardfile(guardfile_path)
138
- options[:guardfile_path] = guardfile_path
139
- options[:guardfile_contents] = File.read(guardfile_path)
140
- rescue
141
- ::Guard::UI.error("Error reading file #{ guardfile_path }")
142
- exit 1
143
- end
144
-
145
- # Get the content to evaluate and stores it into
146
- # the options as `:guardfile_contents`.
147
- #
148
- def fetch_guardfile_contents
149
- if options[:guardfile_contents]
150
- ::Guard::UI.info 'Using inline Guardfile.'
151
- options[:guardfile_path] = 'Inline Guardfile'
152
-
153
- elsif options[:guardfile]
154
- if File.exist?(options[:guardfile])
155
- read_guardfile(options[:guardfile])
156
- ::Guard::UI.info "Using Guardfile at #{ options[:guardfile] }."
157
- else
158
- ::Guard::UI.error "No Guardfile exists at #{ options[:guardfile] }."
159
- exit 1
160
- end
161
-
162
- else
163
- if File.exist?(guardfile_default_path)
164
- read_guardfile(guardfile_default_path)
165
- else
166
- ::Guard::UI.error 'No Guardfile found, please create one with `guard init`.'
167
- exit 1
168
- end
169
- end
170
-
171
- unless guardfile_contents_usable?
172
- ::Guard::UI.error 'No Guard plugins found in Guardfile, please add at least one.'
173
- end
174
- end
175
-
176
- # Get the content of the `Guardfile`.
177
- #
178
- # @return [String] the Guardfile content
179
- #
180
- def guardfile_contents
181
- options ? options[:guardfile_contents] : ''
182
- end
183
-
184
- # Get the content of the `Guardfile` and the global
185
- # user configuration file.
186
- #
187
- # @see #user_config_path
188
- #
189
- # @return [String] the Guardfile content
190
- #
191
- def guardfile_contents_with_user_config
192
- config = File.read(user_config_path) if File.exist?(user_config_path)
193
- [guardfile_contents, config].join("\n")
194
- end
195
-
196
- # Get the file path to the project `Guardfile`.
197
- #
198
- # @return [String] the path to the Guardfile
199
- #
200
- def guardfile_path
201
- options ? options[:guardfile_path] : ''
202
- end
203
-
204
- # Tests if the current `Guardfile` content is usable.
205
- #
206
- # @return [Boolean] if the Guardfile is usable
207
- #
208
- def guardfile_contents_usable?
209
- guardfile_contents && guardfile_contents.size >= 'guard :a'.size # Smallest Guard definition
210
- end
211
-
212
- # Gets the default path of the `Guardfile`. This returns the `Guardfile`
213
- # from the current directory when existing, or the global `.Guardfile`
214
- # at the home directory.
215
- #
216
- # @return [String] the path to the Guardfile
217
- #
218
- def guardfile_default_path
219
- File.exist?(local_guardfile_path) ? local_guardfile_path : home_guardfile_path
220
- end
221
-
222
- private
223
-
224
- # The path to the `Guardfile` that is located at
225
- # the directory, where Guard has been started from.
226
- #
227
- # @return [String] the path to the local Guardfile
228
- #
229
- def local_guardfile_path
230
- File.join(Dir.pwd, 'Guardfile')
231
- end
232
-
233
- # The path to the `.Guardfile` that is located at
234
- # the users home directory.
235
- #
236
- # @return [String] the path to ~/.Guardfile
237
- #
238
- def home_guardfile_path
239
- File.expand_path(File.join('~', '.Guardfile'))
240
- end
241
-
242
- # The path to the user configuration `.guard.rb`
243
- # that is located at the users home directory.
244
- #
245
- # @return [String] the path to ~/.guard.rb
246
- #
247
- def user_config_path
248
- File.expand_path(File.join('~', '.guard.rb'))
249
- end
250
-
48
+ # @deprecated Use
49
+ # `Guard::Guardfile::Evaluator.new(options).evaluate_guardfile` instead.
50
+ #
51
+ # @see https://github.com/guard/guard/wiki/Upgrading-to-Guard-2.0 How to
52
+ # upgrade for Guard 2.0
53
+ #
54
+ def self.evaluate_guardfile(options = {})
55
+ ::Guard::UI.deprecation(::Guard::Deprecator::EVALUATE_GUARDFILE_DEPRECATION)
56
+ ::Guard::Guardfile::Evaluator.new(options).evaluate_guardfile
251
57
  end
252
58
 
253
59
  # Set notification options for the system notifications.
254
- # You can set multiple notification, which allows you to show local
60
+ # You can set multiple notifications, which allows you to show local
255
61
  # system notifications and remote notifications with separate libraries.
256
62
  # You can also pass `:off` as library to turn off notifications.
257
63
  #
258
64
  # @example Define multiple notifications
259
65
  # notification :growl_notify
260
- # notification :ruby_gntp, :host => '192.168.1.5'
261
- #
262
- # @see Guard::Notifier for available notifier and its options.
66
+ # notification :ruby_gntp, host: '192.168.1.5'
263
67
  #
264
68
  # @param [Symbol, String] notifier the name of the notifier to use
265
69
  # @param [Hash] options the notification library options
266
70
  #
71
+ # @see Guard::Notifier for available notifier and its options.
72
+ #
267
73
  def notification(notifier, options = {})
268
- ::Guard::Notifier.add_notification(notifier.to_sym, options, false)
74
+ ::Guard::Notifier.add_notifier(notifier.to_sym, options.merge(silent: false))
269
75
  end
270
76
 
271
- # Sets the interactor to use.
77
+ # Sets the interactor options or disable the interactor.
78
+ #
79
+ # @example Pass options to the interactor
80
+ # interactor option1: 'value1', option2: 'value2'
272
81
  #
273
82
  # @example Turn off interactions
274
83
  # interactor :off
275
84
  #
276
- # @param [Symbol,Hash] options either `:off` or a Hash with interactor options
85
+ # @param [Symbol, Hash] options either `:off` or a Hash with interactor
86
+ # options
277
87
  #
278
88
  def interactor(options)
279
- if options == :off
89
+ case options
90
+ when :off
280
91
  ::Guard::Interactor.enabled = false
281
-
282
- elsif options.is_a?(Hash)
92
+ when Hash
283
93
  ::Guard::Interactor.options = options
284
-
285
- else
286
- ::Guard::UI.deprecation(INTERACTOR_DEPRECATION)
287
94
  end
288
95
  end
289
96
 
290
- # Declares a group of Guard plugins to be run with `guard start --group group_name`.
97
+ # Declares a group of Guard plugins to be run with `guard start --group
98
+ # group_name`.
291
99
  #
292
100
  # @example Declare two groups of Guard plugins
293
- #
294
- # group 'backend' do
295
- # guard 'spork'
296
- # guard 'rspec'
101
+ # group :backend do
102
+ # guard :spork
103
+ # guard :rspec
297
104
  # end
298
105
  #
299
- # group 'frontend' do
300
- # guard 'passenger'
301
- # guard 'livereload'
106
+ # group :frontend do
107
+ # guard :passenger
108
+ # guard :livereload
302
109
  # end
303
110
  #
304
111
  # @param [Symbol, String] name the group name called from the CLI
305
112
  # @param [Hash] options the options accepted by the group
306
- # @yield a block where you can declare several guards
113
+ # @yield a block where you can declare several Guard plugins
307
114
  #
115
+ # @see Group
308
116
  # @see Guard.add_group
309
- # @see Dsl#guard
310
- # @see Guard::DslDescriber
117
+ # @see #guard
311
118
  #
312
119
  def group(name, options = {})
313
- name = name.to_sym
120
+ raise ArgumentError, "'all' is not an allowed group name!" if name.to_sym == :all
314
121
 
315
122
  if block_given?
316
- ::Guard.add_group(name.to_s.downcase, options)
123
+ ::Guard.add_group(name, options)
317
124
  @current_group = name
318
125
 
319
- yield if block_given?
126
+ yield
320
127
 
321
128
  @current_group = nil
129
+ else
130
+ ::Guard::UI.error "No Guard plugins found in the group '#{ name }', please add at least one."
322
131
  end
323
132
  end
324
133
 
325
- # Declare a Guard plugin to be used when running `guard start`.
134
+ # Declares a Guard plugin to be used when running `guard start`.
326
135
  #
327
136
  # The name parameter is usually the name of the gem without
328
137
  # the 'guard-' prefix.
329
138
  #
330
139
  # The available options are different for each Guard implementation.
331
140
  #
332
- # @example Declare a Guard
141
+ # @example Declare a Guard without `watch` patterns
142
+ # guard :rspec
333
143
  #
334
- # guard 'rspec' do
144
+ # @example Declare a Guard with a `watch` pattern
145
+ # guard :rspec do
146
+ # watch %r{.*_spec.rb}
335
147
  # end
336
148
  #
337
- # @param [String] name the Guard name
338
- # @param [Hash] options the options accepted by the Guard
149
+ # @param [String] name the Guard plugin name
150
+ # @param [Hash] options the options accepted by the Guard plugin
339
151
  # @yield a block where you can declare several watch patterns and actions
340
152
  #
341
- # @see Guard.add_guard
342
- # @see Dsl#group
343
- # @see Dsl#watch
344
- # @see Guard::DslDescriber
153
+ # @see Plugin
154
+ # @see Guard.add_plugin
155
+ # @see #watch
156
+ # @see #group
345
157
  #
346
158
  def guard(name, options = {})
347
159
  @watchers = []
@@ -350,129 +162,137 @@ module Guard
350
162
 
351
163
  yield if block_given?
352
164
 
353
- options.update(:group => @current_group)
354
- ::Guard.add_guard(name.to_s.downcase, @watchers, @callbacks, options)
165
+ options.merge!(group: @current_group, watchers: @watchers, callbacks: @callbacks)
166
+ ::Guard.add_plugin(name, options)
355
167
  end
356
168
 
357
- # Define a pattern to be watched in order to run actions on file modification.
169
+ # Defines a pattern to be watched in order to run actions on file modification.
358
170
  #
359
171
  # @example Declare watchers for a Guard
360
- #
361
- # guard 'rspec' do
172
+ # guard :rspec do
362
173
  # watch('spec/spec_helper.rb')
363
174
  # watch(%r{^.+_spec.rb})
364
175
  # watch(%r{^app/controllers/(.+).rb}) { |m| 'spec/acceptance/#{m[1]}s_spec.rb' }
365
176
  # end
366
177
  #
367
- # @param [String, Regexp] pattern the pattern to be watched by the guard
178
+ # @param [String, Regexp] pattern the pattern that Guard must watch for modification
368
179
  # @yield a block to be run when the pattern is matched
369
180
  # @yieldparam [MatchData] m matches of the pattern
370
181
  # @yieldreturn a directory, a filename, an array of directories / filenames, or nothing (can be an arbitrary command)
371
182
  #
372
183
  # @see Guard::Watcher
373
- # @see Dsl#guard
184
+ # @see #guard
374
185
  #
375
186
  def watch(pattern, &action)
376
187
  @watchers << ::Guard::Watcher.new(pattern, action)
377
188
  end
378
189
 
379
- # Define a callback to execute arbitrary code before or after any of
380
- # the `start`, `stop`, `reload`, `run_all`, `run_on_changes` `run_on_additions`, `run_on_modifications`
381
- # and `run_on_removals` plugin method.
190
+ # Defines a callback to execute arbitrary code before or after any of
191
+ # the `start`, `stop`, `reload`, `run_all`, `run_on_changes`,
192
+ # `run_on_additions`, `run_on_modifications` and `run_on_removals` plugin
193
+ # method.
382
194
  #
383
- # @param [Array] args the callback arguments
384
- # @yield a block with listeners
195
+ # @example Define a callback that'll be called before the `reload` action.
196
+ # callback(:reload_begin) { puts "Let's reload!" }
385
197
  #
386
- # @see Guard::Hook
198
+ # @example Define a callback that'll be called before the `start` and `stop` actions.
199
+ # my_lambda = lambda { |plugin, event, *args| puts "Let's #{event} #{plugin} with #{args}!" }
200
+ # callback(my_lambda, [:start_begin, :start_end])
387
201
  #
388
- def callback(*args, &listener)
389
- listener, events = args.size > 1 ? args : [listener, args[0]]
390
- @callbacks << { :events => events, :listener => listener }
391
- end
392
-
393
- # @deprecated Ignore certain paths globally.
394
- #
395
- # @example Ignore some paths
396
- # ignore_paths ".git", ".svn"
202
+ # @param [Array] args the callback arguments
203
+ # @yield a callback block
397
204
  #
398
- # @param [Array] paths the list of paths to ignore
205
+ # @see Guard::Hooker
399
206
  #
400
- def ignore_paths(*paths)
401
- ::Guard::UI.deprecation(IGNORE_PATHS_DEPRECATION)
207
+ def callback(*args, &block)
208
+ block, events = if args.size > 1
209
+ # block must be the first argument in that case, the yielded block is
210
+ # ignored
211
+ args
212
+ else
213
+ [block, args[0]]
214
+ end
215
+ @callbacks << { events: events, listener: block }
402
216
  end
403
217
 
404
- # Ignore certain paths globally.
218
+ # Ignores certain paths globally.
405
219
  #
406
220
  # @example Ignore some paths
407
221
  # ignore %r{^ignored/path/}, /man/
408
222
  #
409
- # @param [Regexp] regexps a pattern for ignoring paths
223
+ # @param [Regexp] regexps a pattern (or list of patterns) for ignoring paths
410
224
  #
411
225
  def ignore(*regexps)
412
226
  ::Guard.listener = ::Guard.listener.ignore(*regexps) if ::Guard.listener
413
227
  end
414
228
 
415
- # Replace ignored paths globally
229
+ # Replaces ignored paths globally
416
230
  #
417
231
  # @example Ignore only these paths
418
232
  # ignore! %r{^ignored/path/}, /man/
419
233
  #
420
- # @param [Regexp] regexps a pattern for ignoring paths
234
+ # @param [Regexp] regexps a pattern (or list of patterns) for ignoring paths
421
235
  #
422
236
  def ignore!(*regexps)
423
237
  ::Guard.listener = ::Guard.listener.ignore!(*regexps) if ::Guard.listener
424
238
  end
425
239
 
426
- # Filter certain paths globally.
240
+ # Filters certain paths globally.
427
241
  #
428
242
  # @example Filter some files
429
243
  # filter /\.txt$/, /.*\.zip/
430
244
  #
431
- # @param [Regexp] regexps a pattern for filtering paths
245
+ # @param [Regexp] regexps a pattern (or list of patterns) for filtering
246
+ # paths
432
247
  #
433
248
  def filter(*regexps)
434
249
  ::Guard.listener = ::Guard.listener.filter(*regexps) if ::Guard.listener
435
250
  end
436
251
 
437
- # Replace filtered paths globally.
252
+ # Replaces filtered paths globally.
438
253
  #
439
254
  # @example Filter only these files
440
255
  # filter! /\.txt$/, /.*\.zip/
441
256
  #
442
- # @param [Regexp] regexps a pattern for filtering paths
257
+ # @param [Regexp] regexps a pattern (or list of patterns) for filtering
258
+ # paths
443
259
  #
444
260
  def filter!(*regexps)
445
261
  ::Guard.listener = ::Guard.listener.filter!(*regexps) if ::Guard.listener
446
262
  end
447
263
 
448
- # Configure the Guard logger.
264
+ # Configures the Guard logger.
449
265
  #
450
266
  # * Log level must be either `:debug`, `:info`, `:warn` or `:error`.
451
- # * Template supports the following placeholders: `:time`, `:severity`, `:progname`, `:pid`, `:unit_of_work_id` and `:message`
452
- # * Time format directives are the same as Time#strftime or :milliseconds
453
- # * The `:only` and `:except` options must be a RegExp.
267
+ # * Template supports the following placeholders: `:time`, `:severity`,
268
+ # `:progname`, `:pid`, `:unit_of_work_id` and `:message`.
269
+ # * Time format directives are the same as `Time#strftime` or
270
+ # `:milliseconds`.
271
+ # * The `:only` and `:except` options must be a `RegExp`.
454
272
  #
455
273
  # @example Set the log level
456
- # logger :level => :warn
274
+ # logger level: :warn
457
275
  #
458
276
  # @example Set a custom log template
459
- # logger :template => '[Guard - :severity - :progname - :time] :message'
277
+ # logger template: '[Guard - :severity - :progname - :time] :message'
460
278
  #
461
279
  # @example Set a custom time format
462
- # logger :time_format => '%h'
280
+ # logger time_format: '%h'
463
281
  #
464
282
  # @example Limit logging to a Guard plugin
465
- # logger :only => :jasmine
283
+ # logger only: :jasmine
466
284
  #
467
285
  # @example Log all but not the messages from a specific Guard plugin
468
- # logger :except => :jasmine
286
+ # logger except: :jasmine
469
287
  #
470
288
  # @param [Hash] options the log options
471
289
  # @option options [String, Symbol] level the log level
472
290
  # @option options [String] template the logger template
473
291
  # @option options [String, Symbol] time_format the time format
474
- # @option options [RegExp] only show only messages from the matching Guard plugin
475
- # @option options [RegExp] except does not show messages from the matching Guard plugin
292
+ # @option options [Regexp] only show only messages from the matching Guard
293
+ # plugin
294
+ # @option options [Regexp] except does not show messages from the matching
295
+ # Guard plugin
476
296
  #
477
297
  def logger(options)
478
298
  if options[:level]
@@ -499,35 +319,29 @@ module Guard
499
319
  end
500
320
  end
501
321
 
502
- ::Guard::UI.options = ::Guard::UI.options.merge options
322
+ ::Guard::UI.options = ::Guard::UI.options.marshal_dump.merge options
503
323
  end
504
324
 
505
325
  # Sets the default scope on startup
506
326
  #
507
327
  # @example Scope Guard to a single group
508
- # scope :group => :frontend
328
+ # scope group: :frontend
509
329
  #
510
330
  # @example Scope Guard to multiple groups
511
- # scope :groups => [:specs, :docs]
331
+ # scope groups: [:specs, :docs]
512
332
  #
513
333
  # @example Scope Guard to a single plugin
514
- # scope :plugin => :test
334
+ # scope plugin: :test
515
335
  #
516
336
  # @example Scope Guard to multiple plugins
517
- # scope :plugins => [:jasmine, :rspec]
337
+ # scope plugins: [:jasmine, :rspec]
518
338
  #
519
339
  # @param [Hash] scopes the scope for the groups and plugins
520
340
  #
521
- def scope(scopes = {})
522
- if ::Guard.options[:plugin].empty?
523
- ::Guard.options[:plugin] = [scopes[:plugin]] if scopes[:plugin]
524
- ::Guard.options[:plugin] = scopes[:plugins] if scopes[:plugins]
525
- end
526
-
527
- if ::Guard.options[:group].empty?
528
- ::Guard.options[:group] = [scopes[:group]] if scopes[:group]
529
- ::Guard.options[:group] = scopes[:groups] if scopes[:groups]
530
- end
341
+ def scope(scope = {})
342
+ scope[:plugins] = Array(scope[:plugins] || scope[:plugin] || [])
343
+ scope[:groups] = Array(scope[:groups] || scope[:group] || [])
344
+ ::Guard.setup_scope(scope)
531
345
  end
532
346
 
533
347
  end