guard 1.8.3 → 2.0.0.pre

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.
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