Class: Guard::Dsl

Inherits:
Object
  • Object
show all
Defined in:
lib/guard/dsl.rb

Overview

The DSL class provides the methods that are used in each Guardfile to describe the behaviour of Guard.

The main keywords of the DSL are guard and watch. These are necessary to define the used Guards and the file changes they are watching.

You can optionally group the Guards with the group keyword and ignore certain paths with the ignore_paths keyword.

A more advanced DSL use is the callback keyword that allows you to execute arbitrary code before or after any of the start, stop, reload, run_all and run_on_change Guards' method. You can even insert more hooks inside these methods. Please checkout the Wiki page for more details.

The DSL will also evaluate normal Ruby code.

There are two possible locations for the Guardfile:

  • The Guardfile in the current directory where Guard has been started
  • The .Guardfile in your home directory.

In addition, if a user configuration .guard.rb in your home directory is found, it will be appended to the current project Guardfile.

Examples:

A sample of a complex Guardfile


group 'frontend' do
  guard 'passenger', :ping => true do
    watch('config/application.rb')
    watch('config/environment.rb')
    watch(%r{^config/environments/.+\.rb})
    watch(%r{^config/initializers/.+\.rb})
  end

  guard 'livereload', :apply_js_live => false do
    watch(%r{^app/.+\.(erb|haml)})
    watch(%r{^app/helpers/.+\.rb})
    watch(%r{^public/javascripts/.+\.js})
    watch(%r{^public/stylesheets/.+\.css})
    watch(%r{^public/.+\.html})
    watch(%r{^config/locales/.+\.yml})
  end
end

group 'backend' do
  # Reload the bundle when the Gemfile is modified
  guard 'bundler' do
    watch('Gemfile')
  end

  # for big project you can fine tune the "timeout" before Spork's launch is considered failed
  guard 'spork', :wait => 40 do
    watch('Gemfile')
    watch('config/application.rb')
    watch('config/environment.rb')
    watch(%r{^config/environments/.+\.rb})
    watch(%r{^config/initializers/.+\.rb})
    watch('spec/spec_helper.rb')
  end

  # use RSpec 2, from the system's gem and with some direct RSpec CLI options
  guard 'rspec', :version => 2, :cli => "--color --drb -f doc", :bundler => false do
    watch('spec/spec_helper.rb')                                  { "spec" }
    watch('app/controllers/application_controller.rb')            { "spec/controllers" }
    watch('config/routes.rb')                                     { "spec/routing" }
    watch(%r{^spec/support/(controllers|acceptance)_helpers\.rb}) { |m| "spec/#{m[1]}" }
    watch(%r{^spec/.+_spec\.rb})

    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"] }

    watch(%r{^app/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
    watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
  end
end

Direct Known Subclasses

DslDescriber

Constant Summary collapse

@@options =
nil

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.evaluate_guardfile(options = {}) ⇒ Object

Evaluate the DSL methods in the Guardfile.

Parameters:

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • groups (Array<Symbol,String>)

    the groups to evaluate

  • guardfile (String)

    the path to a valid Guardfile

  • guardfile_contents (String)

    a string representing the content of a valid Guardfile

Raises:

  • (ArgumentError)

    when options are not a Hash



89
90
91
92
93
94
95
96
97
98
# File 'lib/guard/dsl.rb', line 89

def evaluate_guardfile(options = {})
  raise ArgumentError.new('No option hash passed to evaluate_guardfile!') unless options.is_a?(Hash)

  @@options = options.dup

  fetch_guardfile_contents
  instance_eval_guardfile(guardfile_contents_with_user_config)

  UI.error 'No guards found in Guardfile, please add at least one.' if !::Guard.guards.nil? && ::Guard.guards.empty?
end

.fetch_guardfile_contentsObject

Get the content to evaluate and stores it into the options as :guardfile_contents.



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/guard/dsl.rb', line 147

def fetch_guardfile_contents
  if @@options[:guardfile_contents]
    UI.info 'Using inline Guardfile.'
    @@options[:guardfile_path] = 'Inline Guardfile'

  elsif @@options[:guardfile]
    if File.exist?(@@options[:guardfile])
      read_guardfile(@@options[:guardfile])
      UI.info "Using Guardfile at #{ @@options[:guardfile] }."
    else
      UI.error "No Guardfile exists at #{ @@options[:guardfile] }."
      exit 1
    end

  else
    if File.exist?(guardfile_default_path)
      read_guardfile(guardfile_default_path)
    else
      UI.error 'No Guardfile found, please create one with `guard init`.'
      exit 1
    end
  end

  unless guardfile_contents_usable?
    UI.error "The command file(#{ @@options[:guardfile] }) seems to be empty."
    exit 1
  end
end

.guardfile_contentsString

Get the content of the Guardfile.

Returns:

  • (String)

    the Guardfile content



180
181
182
# File 'lib/guard/dsl.rb', line 180

def guardfile_contents
  @@options ? @@options[:guardfile_contents] : ''
end

.guardfile_contents_usable?Boolean

Tests if the current Guardfile content is usable.

Returns:

  • (Boolean)

    if the Guardfile is usable



208
209
210
# File 'lib/guard/dsl.rb', line 208

def guardfile_contents_usable?
  guardfile_contents && guardfile_contents.size >= 'guard :a'.size # Smallest Guard definition
end

.guardfile_contents_with_user_configString

Get the content of the Guardfile and the global user configuration file.

Returns:

  • (String)

    the Guardfile content

See Also:

  • #user_config_path


191
192
193
194
# File 'lib/guard/dsl.rb', line 191

def guardfile_contents_with_user_config
  config = File.read(user_config_path) if File.exist?(user_config_path)
  [guardfile_contents, config].join("\n")
end

.guardfile_default_pathString

Gets the default path of the Guardfile. This returns the Guardfile from the current directory when existing, or the global .Guardfile at the home directory.

Returns:

  • (String)

    the path to the Guardfile



218
219
220
# File 'lib/guard/dsl.rb', line 218

def guardfile_default_path
  File.exist?(local_guardfile_path) ? local_guardfile_path : home_guardfile_path
end

.guardfile_include?(guard_name) ⇒ Boolean

Test if the current Guardfile contains a specific Guard.

Parameters:

  • guard_name (String)

    the name of the Guard

Returns:

  • (Boolean)

    whether the Guard has been declared



128
129
130
# File 'lib/guard/dsl.rb', line 128

def guardfile_include?(guard_name)
  guardfile_contents.match(/^guard\s*\(?\s*['":]#{ guard_name }['"]?/)
end

.guardfile_pathString

Get the file path to the project Guardfile.

Returns:

  • (String)

    the path to the Guardfile



200
201
202
# File 'lib/guard/dsl.rb', line 200

def guardfile_path
  @@options ? @@options[:guardfile_path] : ''
end

.instance_eval_guardfile(contents) ⇒ Object

Evaluate the content of the Guardfile.

Parameters:

  • contents (String)

    the content to evaluate.



116
117
118
119
120
121
# File 'lib/guard/dsl.rb', line 116

def instance_eval_guardfile(contents)
  new.instance_eval(contents, @@options[:guardfile_path], 1)
rescue
  UI.error "Invalid Guardfile, original error is:\n#{ $! }"
  exit 1
end

.read_guardfile(guardfile_path) ⇒ Object

Read the current Guardfile content.

Parameters:

  • the (String)

    path to the Guardfile



136
137
138
139
140
141
142
# File 'lib/guard/dsl.rb', line 136

def read_guardfile(guardfile_path)
  @@options[:guardfile_path]     = guardfile_path
  @@options[:guardfile_contents] = File.read(guardfile_path)
rescue
  UI.error("Error reading file #{ guardfile_path }")
  exit 1
end

.reevaluate_guardfileObject

Re-evaluate the Guardfile to update the current Guard configuration.



102
103
104
105
106
107
108
109
110
# File 'lib/guard/dsl.rb', line 102

def reevaluate_guardfile
  ::Guard.guards.clear
  ::Guard.reset_groups
  @@options.delete(:guardfile_contents)
  Dsl.evaluate_guardfile(@@options)
  msg = 'Guardfile has been re-evaluated.'
  UI.info(msg)
  Notifier.notify(msg)
end

Instance Method Details

#callback(*args) { ... } ⇒ Object

Define a callback to execute arbitrary code before or after any of the start, stop, reload, run_all and run_on_change guards' method.

Parameters:

  • args (Array)

    the callback arguments

Yields:

  • a block with listeners

See Also:



350
351
352
353
# File 'lib/guard/dsl.rb', line 350

def callback(*args, &listener)
  listener, events = args.size > 1 ? args : [listener, args[0]]
  @callbacks << { :events => events, :listener => listener }
end

#group(name, options = {}) { ... } ⇒ Object

Declares a group of guards to be run with guard start --group group_name.

Examples:

Declare two groups of Guards


group 'backend' do
  guard 'spork'
  guard 'rspec'
end

group 'frontend' do
  guard 'passenger'
  guard 'livereload'
end

Parameters:

  • name (Symbol, String)

    the group's name called from the CLI

  • options (Hash) (defaults to: {})

    the options accepted by the group

Yields:

  • a block where you can declare several guards

See Also:



275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/guard/dsl.rb', line 275

def group(name, options = {})
  @groups = @@options[:group] || []
  name    = name.to_sym

  if block_given? && (@groups.empty? || @groups.map(&:to_sym).include?(name))
    ::Guard.add_group(name.to_s.downcase, options)
    @current_group = name

    yield if block_given?

    @current_group = nil
  end
end

#guard(name, options = {}) { ... } ⇒ Object

Declare a guard to be used when running guard start.

The name parameter is usually the name of the gem without the 'guard-' prefix.

The available options are different for each Guard implementation.

Examples:

Declare a Guard


guard 'rspec' do
end

Parameters:

  • name (String)

    the Guard name

  • options (Hash) (defaults to: {})

    the options accepted by the Guard

Yields:

  • a block where you can declare several watch patterns and actions

See Also:



310
311
312
313
314
315
316
317
318
# File 'lib/guard/dsl.rb', line 310

def guard(name, options = {})
  @watchers  = []
  @callbacks = []

  yield if block_given?

  options.update(:group => (@current_group || :default))
  ::Guard.add_guard(name.to_s.downcase, @watchers, @callbacks, options)
end

#ignore_paths(*paths) ⇒ Object

Ignore certain paths globally.

Examples:

Ignore some paths

ignore_paths ".git", ".svn"

Parameters:

  • paths (Array)

    the list of paths to ignore

See Also:



364
365
366
367
# File 'lib/guard/dsl.rb', line 364

def ignore_paths(*paths)
  UI.info "Ignoring paths: #{ paths.join(', ') }"
  ::Guard.listener.ignore_paths.push(*paths)
end

#watch(pattern) {|m| ... } ⇒ Object

Define a pattern to be watched in order to run actions on file modification.

Examples:

Declare watchers for a Guard


guard 'rspec' do
  watch('spec/spec_helper.rb')
  watch(%r{^.+_spec.rb})
  watch(%r{^app/controllers/(.+).rb}) { |m| 'spec/acceptance/#{m[1]}s_spec.rb' }
end

Parameters:

  • pattern (String, Regexp)

    the pattern to be watched by the guard

Yields:

  • a block to be run when the pattern is matched

Yield Parameters:

  • m (MatchData)

    matches of the pattern

Yield Returns:

  • a directory, a filename, an array of directories / filenames, or nothing (can be an arbitrary command)

See Also:



338
339
340
# File 'lib/guard/dsl.rb', line 338

def watch(pattern, &action)
  @watchers << ::Guard::Watcher.new(pattern, action)
end