guard 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/guard/dsl.rb CHANGED
@@ -1,62 +1,160 @@
1
1
  module Guard
2
+
3
+ # The DSL class provides the methods that are used in each `Guardfile` to describe
4
+ # the behaviour of Guard.
5
+ #
6
+ # The main keywords of the DSL are `guard` and `watch`. These are necessary to define
7
+ # the used Guards and the file changes they are watching.
8
+ #
9
+ # You can optionally group the Guards with the `group` keyword and ignore certain paths
10
+ # with the `ignore_paths` keyword.
11
+ #
12
+ # A more advanced DSL use is the `callback` keyword that allows you to execute arbitrary
13
+ # code before or after any of the `start`, `stop`, `reload`, `run_all` and `run_on_change`
14
+ # Guards' method. You can even insert more hooks inside these methods.
15
+ # Please [checkout the Wiki page](https://github.com/guard/guard/wiki/Hooks-and-callbacks) for more details.
16
+ #
17
+ # The DSL will also evaluate normal Ruby code.
18
+ #
19
+ # There are two possible locations for the `Guardfile`:
20
+ # - The `Guardfile` in the current directory where Guard has been started
21
+ # - The `.Guardfile` in your home directory.
22
+ #
23
+ # In addition, if a user configuration `.guard.rb` in your home directory is found, it will
24
+ # be appended to the current project `Guardfile`.
25
+ #
26
+ # @example A sample of a complex Guardfile
27
+ #
28
+ # group 'frontend' do
29
+ # guard 'passenger', :ping => true do
30
+ # watch('config/application.rb')
31
+ # watch('config/environment.rb')
32
+ # watch(%r{^config/environments/.+\.rb})
33
+ # watch(%r{^config/initializers/.+\.rb})
34
+ # end
35
+ #
36
+ # guard 'livereload', :apply_js_live => false do
37
+ # watch(%r{^app/.+\.(erb|haml)})
38
+ # watch(%r{^app/helpers/.+\.rb})
39
+ # watch(%r{^public/javascripts/.+\.js})
40
+ # watch(%r{^public/stylesheets/.+\.css})
41
+ # watch(%r{^public/.+\.html})
42
+ # watch(%r{^config/locales/.+\.yml})
43
+ # end
44
+ # end
45
+ #
46
+ # group 'backend' do
47
+ # # Reload the bundle when the Gemfile is modified
48
+ # guard 'bundler' do
49
+ # watch('Gemfile')
50
+ # end
51
+ #
52
+ # # for big project you can fine tune the "timeout" before Spork's launch is considered failed
53
+ # guard 'spork', :wait => 40 do
54
+ # watch('Gemfile')
55
+ # watch('config/application.rb')
56
+ # watch('config/environment.rb')
57
+ # watch(%r{^config/environments/.+\.rb})
58
+ # watch(%r{^config/initializers/.+\.rb})
59
+ # watch('spec/spec_helper.rb')
60
+ # end
61
+ #
62
+ # # use RSpec 2, from the system's gem and with some direct RSpec CLI options
63
+ # guard 'rspec', :version => 2, :cli => "--color --drb -f doc", :bundler => false do
64
+ # watch('spec/spec_helper.rb') { "spec" }
65
+ # watch('app/controllers/application_controller.rb') { "spec/controllers" }
66
+ # watch('config/routes.rb') { "spec/routing" }
67
+ # watch(%r{^spec/support/(controllers|acceptance)_helpers\.rb}) { |m| "spec/#{m[1]}" }
68
+ # watch(%r{^spec/.+_spec\.rb})
69
+ #
70
+ # watch(%r{^app/controllers/(.+)_(controller)\.rb}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
71
+ #
72
+ # watch(%r{^app/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
73
+ # watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
74
+ # end
75
+ # end
76
+ #
2
77
  class Dsl
3
78
  class << self
79
+
4
80
  @@options = nil
5
81
 
82
+ # Evaluate the DSL methods in the `Guardfile`.
83
+ #
84
+ # @option options [Array<Symbol,String>] groups the groups to evaluate
85
+ # @option options [String] guardfile the path to a valid Guardfile
86
+ # @option options [String] guardfile_contents a string representing the content of a valid Guardfile
87
+ # @raise [ArgumentError] when options are not a Hash
88
+ #
6
89
  def evaluate_guardfile(options = {})
7
- options.is_a?(Hash) or raise ArgumentError.new("evaluate_guardfile not passed a Hash!")
90
+ raise ArgumentError.new('No option hash passed to evaluate_guardfile!') unless options.is_a?(Hash)
8
91
 
9
92
  @@options = options.dup
93
+
10
94
  fetch_guardfile_contents
11
95
  instance_eval_guardfile(guardfile_contents_with_user_config)
12
96
 
13
- UI.error "No guards found in Guardfile, please add at least one." if !::Guard.guards.nil? && ::Guard.guards.empty?
97
+ UI.error 'No guards found in Guardfile, please add at least one.' if !::Guard.guards.nil? && ::Guard.guards.empty?
14
98
  end
15
99
 
100
+ # Re-evaluate the `Guardfile` to update the current Guard configuration.
101
+ #
16
102
  def reevaluate_guardfile
17
103
  ::Guard.guards.clear
104
+ ::Guard.groups.clear
18
105
  @@options.delete(:guardfile_contents)
19
106
  Dsl.evaluate_guardfile(@@options)
20
- msg = "Guardfile has been re-evaluated."
107
+ msg = 'Guardfile has been re-evaluated.'
21
108
  UI.info(msg)
22
109
  Notifier.notify(msg)
23
110
  end
24
111
 
112
+ # Evaluate the content of the `Guardfile`.
113
+ #
114
+ # @param [String] contents the content to evaluate.
115
+ #
25
116
  def instance_eval_guardfile(contents)
26
- begin
27
- new.instance_eval(contents, @@options[:guardfile_path], 1)
28
- rescue
29
- UI.error "Invalid Guardfile, original error is:\n#{$!}"
30
- exit 1
31
- end
117
+ new.instance_eval(contents, @@options[:guardfile_path], 1)
118
+ rescue
119
+ UI.error "Invalid Guardfile, original error is:\n#{ $! }"
120
+ exit 1
32
121
  end
33
122
 
123
+ # Test if the current `Guardfile` contains a specific Guard.
124
+ #
125
+ # @param [String] guard_name the name of the Guard
126
+ # @return [Boolean] whether the Guard has been declared
127
+ #
34
128
  def guardfile_include?(guard_name)
35
- guardfile_contents.match(/^guard\s*\(?\s*['":]#{guard_name}['"]?/)
129
+ guardfile_contents.match(/^guard\s*\(?\s*['":]#{ guard_name }['"]?/)
36
130
  end
37
131
 
132
+ # Read the current `Guardfile` content.
133
+ #
134
+ # @param [String] the path to the Guardfile
135
+ #
38
136
  def read_guardfile(guardfile_path)
39
- begin
40
- @@options[:guardfile_path] = guardfile_path
41
- @@options[:guardfile_contents] = File.read(guardfile_path)
42
- rescue
43
- UI.error("Error reading file #{guardfile_path}")
44
- exit 1
45
- end
137
+ @@options[:guardfile_path] = guardfile_path
138
+ @@options[:guardfile_contents] = File.read(guardfile_path)
139
+ rescue
140
+ UI.error("Error reading file #{ guardfile_path }")
141
+ exit 1
46
142
  end
47
143
 
144
+ # Get the content to evaluate and stores it into
145
+ # the options as `:guardfile_contents`.
146
+ #
48
147
  def fetch_guardfile_contents
49
- # TODO: do we need .rc file interaction?
50
148
  if @@options[:guardfile_contents]
51
- UI.info "Using inline Guardfile."
149
+ UI.info 'Using inline Guardfile.'
52
150
  @@options[:guardfile_path] = 'Inline Guardfile'
53
151
 
54
152
  elsif @@options[:guardfile]
55
153
  if File.exist?(@@options[:guardfile])
56
154
  read_guardfile(@@options[:guardfile])
57
- UI.info "Using Guardfile at #{@@options[:guardfile]}."
155
+ UI.info "Using Guardfile at #{ @@options[:guardfile] }."
58
156
  else
59
- UI.error "No Guardfile exists at #{@@options[:guardfile]}."
157
+ UI.error "No Guardfile exists at #{ @@options[:guardfile] }."
60
158
  exit 1
61
159
  end
62
160
 
@@ -64,85 +162,209 @@ module Guard
64
162
  if File.exist?(guardfile_default_path)
65
163
  read_guardfile(guardfile_default_path)
66
164
  else
67
- UI.error "No Guardfile found, please create one with `guard init`."
165
+ UI.error 'No Guardfile found, please create one with `guard init`.'
68
166
  exit 1
69
167
  end
70
168
  end
71
169
 
72
170
  unless guardfile_contents_usable?
73
- UI.error "The command file(#{@@options[:guardfile]}) seems to be empty."
171
+ UI.error "The command file(#{ @@options[:guardfile] }) seems to be empty."
74
172
  exit 1
75
173
  end
76
174
  end
77
175
 
176
+ # Get the content of the `Guardfile`.
177
+ #
178
+ # @return [String] the Guardfile content
179
+ #
78
180
  def guardfile_contents
79
- @@options ? @@options[:guardfile_contents] : ""
181
+ @@options ? @@options[:guardfile_contents] : ''
80
182
  end
81
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
+ #
82
191
  def guardfile_contents_with_user_config
83
192
  config = File.read(user_config_path) if File.exist?(user_config_path)
84
193
  [guardfile_contents, config].join("\n")
85
194
  end
86
195
 
196
+ # Get the file path to the project `Guardfile`.
197
+ #
198
+ # @return [String] the path to the Guardfile
199
+ #
87
200
  def guardfile_path
88
- @@options ? @@options[:guardfile_path] : ""
201
+ @@options ? @@options[:guardfile_path] : ''
89
202
  end
90
203
 
204
+ # Tests if the current `Guardfile` content is usable.
205
+ #
206
+ # @return [Boolean] if the Guardfile is usable
207
+ #
91
208
  def guardfile_contents_usable?
92
- guardfile_contents && guardfile_contents.size >= 'guard :a'.size # smallest guard-definition
209
+ guardfile_contents && guardfile_contents.size >= 'guard :a'.size # Smallest Guard definition
93
210
  end
94
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
+ #
95
218
  def guardfile_default_path
96
219
  File.exist?(local_guardfile_path) ? local_guardfile_path : home_guardfile_path
97
220
  end
98
221
 
99
- private
222
+ private
100
223
 
224
+ # The path to the `Guardfile` that is located at
225
+ # the directory, where Guard has been started from.
226
+ #
227
+ # @param [String] the path to the local Guardfile
228
+ #
101
229
  def local_guardfile_path
102
- File.join(Dir.pwd, "Guardfile")
230
+ File.join(Dir.pwd, 'Guardfile')
103
231
  end
104
232
 
233
+ # The path to the `.Guardfile` that is located at
234
+ # the users home directory.
235
+ #
236
+ # @param [String] the path to ~/.Guardfile
237
+ #
105
238
  def home_guardfile_path
106
- File.expand_path(File.join("~", ".Guardfile"))
239
+ File.expand_path(File.join('~', '.Guardfile'))
107
240
  end
108
241
 
242
+ # The path to the user configuration `.guard.rb`
243
+ # that is located at the users home directory.
244
+ #
245
+ # @param [String] the path to ~/.guard.rb
246
+ #
109
247
  def user_config_path
110
- File.expand_path(File.join("~", ".guard.rb"))
248
+ File.expand_path(File.join('~', '.guard.rb'))
111
249
  end
112
250
 
113
251
  end
114
252
 
115
- def group(name, &guard_definition)
253
+ # Declares a group of guards to be run with `guard start --group group_name`.
254
+ #
255
+ # @example Declare two groups of Guards
256
+ #
257
+ # group 'backend' do
258
+ # guard 'spork'
259
+ # guard 'rspec'
260
+ # end
261
+ #
262
+ # group 'frontend' do
263
+ # guard 'passenger'
264
+ # guard 'livereload'
265
+ # end
266
+ #
267
+ # @param [Symbol, String] name the group's name called from the CLI
268
+ # @param [Hash] options the options accepted by the group
269
+ # @yield a block where you can declare several guards
270
+ #
271
+ # @see Guard.add_group
272
+ # @see Dsl#guard
273
+ # @see Guard::DslDescriber
274
+ #
275
+ def group(name, options = {})
116
276
  @groups = @@options[:group] || []
117
- name = name.to_sym
277
+ name = name.to_sym
118
278
 
119
- if guard_definition && (@groups.empty? || @groups.map(&:to_sym).include?(name))
279
+ if block_given? && (@groups.empty? || @groups.map(&:to_sym).include?(name))
280
+ ::Guard.add_group(name.to_s.downcase, options)
120
281
  @current_group = name
121
- guard_definition.call
282
+
283
+ yield if block_given?
284
+
122
285
  @current_group = nil
123
286
  end
124
287
  end
125
288
 
126
- def guard(name, options = {}, &watch_and_callback_definition)
289
+ # Declare a guard to be used when running `guard start`.
290
+ #
291
+ # The name parameter is usually the name of the gem without
292
+ # the 'guard-' prefix.
293
+ #
294
+ # The available options are different for each Guard implementation.
295
+ #
296
+ # @example Declare a Guard
297
+ #
298
+ # guard 'rspec' do
299
+ # end
300
+ #
301
+ # @param [String] name the Guard name
302
+ # @param [Hash] options the options accepted by the Guard
303
+ # @yield a block where you can declare several watch patterns and actions
304
+ #
305
+ # @see Guard.add_guard
306
+ # @see Dsl#group
307
+ # @see Dsl#watch
308
+ # @see Guard::DslDescriber
309
+ #
310
+ def guard(name, options = {})
127
311
  @watchers = []
128
312
  @callbacks = []
129
- watch_and_callback_definition.call if watch_and_callback_definition
313
+
314
+ yield if block_given?
315
+
130
316
  options.update(:group => (@current_group || :default))
131
- ::Guard.add_guard(name.to_s.downcase.to_sym, @watchers, @callbacks, options)
317
+ ::Guard.add_guard(name.to_s.downcase, @watchers, @callbacks, options)
132
318
  end
133
319
 
320
+ # Define a pattern to be watched in order to run actions on file modification.
321
+ #
322
+ # @example Declare watchers for a Guard
323
+ #
324
+ # guard 'rspec' do
325
+ # watch('spec/spec_helper.rb')
326
+ # watch(%r{^.+_spec.rb})
327
+ # watch(%r{^app/controllers/(.+).rb}) { |m| 'spec/acceptance/#{m[1]}s_spec.rb' }
328
+ # end
329
+ #
330
+ # @param [String, Regexp] pattern the pattern to be watched by the guard
331
+ # @yield a block to be run when the pattern is matched
332
+ # @yieldparam [MatchData] m matches of the pattern
333
+ # @yieldreturn a directory, a filename, an array of directories / filenames, or nothing (can be an arbitrary command)
334
+ #
335
+ # @see Guard::Watcher
336
+ # @see Dsl#guard
337
+ #
134
338
  def watch(pattern, &action)
135
339
  @watchers << ::Guard::Watcher.new(pattern, action)
136
340
  end
137
341
 
342
+ # Define a callback to execute arbitrary code before or after any of
343
+ # the `start`, `stop`, `reload`, `run_all` and `run_on_change` guards' method.
344
+ #
345
+ # @param [Array] args the callback arguments
346
+ # @yield a block with listeners
347
+ #
348
+ # @see Guard::Hook
349
+ #
138
350
  def callback(*args, &listener)
139
351
  listener, events = args.size > 1 ? args : [listener, args[0]]
140
352
  @callbacks << { :events => events, :listener => listener }
141
353
  end
142
354
 
355
+ # Ignore certain paths globally.
356
+ #
357
+ # @example Ignore some paths
358
+ # ignore_paths ".git", ".svn"
359
+ #
360
+ # @param [Array] paths the list of paths to ignore
361
+ #
362
+ # @see Guard::Listener
363
+ #
143
364
  def ignore_paths(*paths)
144
- UI.info "Ignoring paths: #{paths.join(', ')}"
365
+ UI.info "Ignoring paths: #{ paths.join(', ') }"
145
366
  ::Guard.listener.ignore_paths.push(*paths)
146
367
  end
368
+
147
369
  end
148
370
  end
@@ -1,28 +1,60 @@
1
1
  require 'guard/dsl'
2
2
 
3
3
  module Guard
4
+
5
+ # The DslDescriber overrides methods to create an internal structure
6
+ # of the Guardfile that is used in some inspection utility methods
7
+ # like the CLI commands `show` and `list`.
8
+ #
9
+ # @see Guard::Dsl
10
+ # @see Guard::CLI
11
+ #
4
12
  class DslDescriber < Dsl
13
+
5
14
  @@guardfile_structure = [ { :guards => [] } ]
6
15
 
7
16
  class << self
17
+
18
+ # Get the Guardfile structure.
19
+ #
20
+ # @return [Array<Hash>] the structure
21
+ #
8
22
  def guardfile_structure
9
23
  @@guardfile_structure
10
24
  end
11
25
  end
12
26
 
13
27
  private
14
- def group(name, &guard_definition)
15
- @@guardfile_structure << { :group => name.to_sym, :guards => [] }
16
28
 
29
+ # Declares a group of guards.
30
+ #
31
+ # @param [String] name the group's name called from the CLI
32
+ # @yield a block where you can declare several guards
33
+ #
34
+ # @see Guard::Dsl#group
35
+ #
36
+ def group(name)
37
+ @@guardfile_structure << { :group => name.to_sym, :guards => [] }
17
38
  @group = true
18
- guard_definition.call
39
+
40
+ yield if block_given?
41
+
19
42
  @group = false
20
43
  end
21
44
 
22
- def guard(name, options = {}, &watch_definition)
45
+ # Declares a Guard.
46
+ #
47
+ # @param [String] name the Guard name
48
+ # @param [Hash] options the options accepted by the Guard
49
+ # @yield a block where you can declare several watch patterns and actions
50
+ #
51
+ # @see Guard::Dsl#guard
52
+ #
53
+ def guard(name, options = {})
23
54
  node = (@group ? @@guardfile_structure.last : @@guardfile_structure.first)
24
55
 
25
56
  node[:guards] << { :name => name, :options => options }
26
57
  end
58
+
27
59
  end
28
60
  end