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 Guard plugins and the file changes they are watching.

You can optionally group the Guard plugins with the #group keyword and ignore and filter certain paths with the #ignore and #filter keywords.

You can set your preferred system notification library with #notification and pass some optional configuration options for the library. If you don't configure a library, Guard will automatically pick one with default options (if you don't want notifications, specify :off as library). Please see Notifier for more information about the supported libraries.

A more advanced DSL use is the #callback keyword that allows you to execute arbitrary code before or after any of the Plugin#start, Plugin#stop, Plugin#reload, Plugin#run_all, Plugin#run_on_changes, Plugin#run_on_additions, Plugin#run_on_modifications and Plugin#run_on_removals Guard plugins 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 or guardfile.rb 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.

Direct Known Subclasses

DslReader

Defined Under Namespace

Classes: Error

Constant Summary collapse

WARN_INVALID_LOG_LEVEL =
"Invalid log level `%s` ignored. "\
"Please use either :debug, :info, :warn or :error."
WARN_INVALID_LOG_OPTIONS =
"You cannot specify the logger options"\
" :only and :except at the same time."

Instance Method Summary collapse

Instance Method Details

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

Defines a callback to execute arbitrary code before or after any of the start, stop, reload, run_all, run_on_changes, run_on_additions, run_on_modifications and run_on_removals plugin method.

Examples:

Add callback before the reload action.

callback(:reload_begin) { puts "Let's reload!" }

Add callback before the start and stop actions.


my_lambda = lambda do |plugin, event, *args|
  puts "Let's #{event} #{plugin} with #{args}!"
end

callback(my_lambda, [:start_begin, :start_end])

Parameters:

  • args (Array)

    the callback arguments

Yields:

  • a callback block


249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/guard/dsl.rb', line 249

def callback(*args, &block)
  @plugin_options ||= nil
  fail "callback must be called within a guard block" unless @plugin_options

  block, events = if args.size > 1
                    # block must be the first argument in that case, the
                    # yielded block is ignored
                    args
                  else
                    [block, args[0]]
                  end
  @plugin_options[:callbacks] << { events: events, listener: block }
end

#clearing(flag) ⇒ Object

Sets Guard to clear the screen before every task is run

Examples:

switching clearing the screen on

clearing(:on)

Parameters:

  • on (Symbol)

    ':on' to turn on, ':off' (default) to turn off


411
412
413
# File 'lib/guard/dsl.rb', line 411

def clearing(flag)
  Guard.state.session.clearing(flag == :on)
end

#directories(directories) ⇒ Object

Sets the directories to pass to Listen

Examples:

watch only given directories

directories %w(lib specs)

Parameters:

  • directories (Array)

    directories for Listen to watch


397
398
399
400
401
402
# File 'lib/guard/dsl.rb', line 397

def directories(directories)
  directories.each do |dir|
    fail "Directory #{dir.inspect} does not exist!" unless Dir.exist?(dir)
  end
  Guard.state.session.watchdirs = directories
end

#evaluate(contents, filename, lineno) ⇒ Object


380
381
382
383
384
385
386
387
388
# File 'lib/guard/dsl.rb', line 380

def evaluate(contents, filename, lineno)
  instance_eval(contents, filename.to_s, lineno)
rescue StandardError, ScriptError => e
  prefix = "\n\t(dsl)> "
  cleaned_backtrace = _cleanup_backtrace(e.backtrace)
  backtrace = "#{prefix}#{cleaned_backtrace.join(prefix)}"
  msg = "Invalid Guardfile, original error is: \n\n%s, \nbacktrace: %s"
  raise Error, format(msg, e, backtrace)
end

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

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

Examples:

Declare two groups of Guard plugins

group :backend do
  guard :spork
  guard :rspec
end

group :frontend do
  guard :passenger
  guard :livereload
end

Parameters:

  • name (Symbol, String, Array<Symbol, String>)

    the group name called from the CLI

  • options (Hash)

    the options accepted by the group

Yields:

  • a block where you can declare several Guard plugins

See Also:


126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/guard/dsl.rb', line 126

def group(*args)
  options = args.last.is_a?(Hash) ? args.pop : {}
  groups = args

  groups.each do |group|
    next unless group.to_sym == :all

    fail ArgumentError, "'all' is not an allowed group name!"
  end

  if block_given?
    groups.each do |group|
      # TODO: let groups be added *after* evaluation
      Guard.state.session.groups.add(group, options)
    end

    @current_groups ||= []
    @current_groups.push(groups)

    yield

    @current_groups.pop
  else
    UI.error \
      "No Guard plugins found in the group '#{groups.join(', ')}',"\
      " please add at least one."
  end
end

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

Declares a Guard plugin 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 without watch patterns

guard :rspec

Declare a Guard with a watch pattern

guard :rspec do
  watch %r{.*_spec.rb}
end

Parameters:

  • name (String)

    the Guard plugin name

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

    the options accepted by the Guard plugin

Yields:

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

See Also:


179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/guard/dsl.rb', line 179

def guard(name, options = {})
  @plugin_options = options.merge(watchers: [], callbacks: [])

  yield if block_given?

  @current_groups ||= []
  groups = @current_groups&.last || [:default]
  groups.each do |group|
    opts = @plugin_options.merge(group: group)
    # TODO: let plugins be added *after* evaluation
    Guard.state.session.plugins.add(name, opts)
  end

  @plugin_options = nil
end

#ignore(*regexps) ⇒ Object Also known as: filter

Ignores certain paths globally.

Examples:

Ignore some paths

ignore %r{^ignored/path/}, /man/

Parameters:

  • regexps (Regexp)

    a pattern (or list of patterns) for ignoring paths


270
271
272
273
# File 'lib/guard/dsl.rb', line 270

def ignore(*regexps)
  # TODO: use guardfile results class
  Guard.state.session.guardfile_ignore = regexps
end

#ignore!(*regexps) ⇒ Object Also known as: filter!

Replaces ignored paths globally

Examples:

Ignore only these paths

ignore! %r{^ignored/path/}, /man/

Parameters:

  • regexps (Regexp)

    a pattern (or list of patterns) for ignoring paths


285
286
287
288
289
290
# File 'lib/guard/dsl.rb', line 285

def ignore!(*regexps)
  @ignore_regexps ||= []
  @ignore_regexps << regexps
  # TODO: use guardfile results class
  Guard.state.session.guardfile_ignore_bang = @ignore_regexps
end

#interactor(options) ⇒ Object

Sets the interactor options or disable the interactor.

Examples:

Pass options to the interactor

interactor option1: 'value1', option2: 'value2'

Turn off interactions

interactor :off

Parameters:

  • options (Symbol, Hash)

    either :off or a Hash with interactor options


93
94
95
96
97
98
99
100
101
# File 'lib/guard/dsl.rb', line 93

def interactor(options)
  # TODO: remove dependency on Interactor (let session handle this)
  case options
  when :off
    Interactor.enabled = false
  when Hash
    Interactor.options = options
  end
end

#logger(options) ⇒ Object

Configures the Guard logger.

  • Log level must be either :debug, :info, :warn or :error.
  • Template supports the following placeholders: :time, :severity, :progname, :pid, :unit_of_work_id and :message.
  • Time format directives are the same as Time#strftime or :milliseconds.
  • The :only and :except options must be a RegExp.

Examples:

Set the log level

logger level: :warn

Set a custom log template

logger template: '[Guard - :severity - :progname - :time] :message'

Set a custom time format

logger time_format: '%h'

Limit logging to a Guard plugin

logger only: :jasmine

Log all but not the messages from a specific Guard plugin

logger except: :jasmine

Parameters:

  • options (Hash)

    the log options

Options Hash (options):

  • level (String, Symbol)

    the log level

  • template (String)

    the logger template

  • time_format (String, Symbol)

    the time format

  • only (Regexp)

    show only messages from the matching Guard plugin

  • except (Regexp)

    does not show messages from the matching Guard plugin


328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/guard/dsl.rb', line 328

def logger(options)
  if options[:level]
    options[:level] = options[:level].to_sym

    unless %i(debug info warn error).include? options[:level]
      UI.warning(format(WARN_INVALID_LOG_LEVEL, options[:level]))
      options.delete :level
    end
  end

  if options[:only] && options[:except]
    UI.warning WARN_INVALID_LOG_OPTIONS

    options.delete :only
    options.delete :except
  end

  # Convert the :only and :except options to a regular expression
  %i(only except).each do |name|
    next unless options[name]

    list = [].push(options[name]).flatten.map do |plugin|
      Regexp.escape(plugin.to_s)
    end

    options[name] = Regexp.new(list.join("|"), Regexp::IGNORECASE)
  end

  UI.options = UI.options.merge(options)
end

#notification(notifier, opts = {}) ⇒ Object

Set notification options for the system notifications. You can set multiple notifications, which allows you to show local system notifications and remote notifications with separate libraries. You can also pass :off as library to turn off notifications.

Examples:

Define multiple notifications

notification :ruby_gntp
notification :ruby_gntp, host: '192.168.1.5'

Parameters:

  • notifier (Symbol, String)

    the name of the notifier to use

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

    the notification library options

See Also:


78
79
80
# File 'lib/guard/dsl.rb', line 78

def notification(notifier, opts = {})
  Guard.state.session.guardfile_notification = { notifier.to_sym => opts }
end

#scope(scope = {}) ⇒ Object

Sets the default scope on startup

Examples:

Scope Guard to a single group

scope group: :frontend

Scope Guard to multiple groups

scope groups: [:specs, :docs]

Scope Guard to a single plugin

scope plugin: :test

Scope Guard to multiple plugins

scope plugins: [:jasmine, :rspec]

Parameters:

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

    the scope for the groups and plugins


375
376
377
378
# File 'lib/guard/dsl.rb', line 375

def scope(scope = {})
  # TODO: use a Guardfile::Results class
  Guard.state.session.guardfile_scope(scope)
end

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

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

modification

Examples:

Declare watchers for a Guard

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

Declare global watchers outside of a Guard

watch(%r{^(.+)$}) { |m| puts "#{m[1]} changed." }

Parameters:

  • pattern (String, Regexp)

    the pattern that Guard must watch for

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:


221
222
223
224
225
226
227
228
# File 'lib/guard/dsl.rb', line 221

def watch(pattern, &action)
  # Allow watches in the global scope (to execute arbitrary commands) by
  # building a generic Guard::Plugin.
  @plugin_options ||= nil
  return guard(:plugin) { watch(pattern, &action) } unless @plugin_options

  @plugin_options[:watchers] << Watcher.new(pattern, action)
end