guard 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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