module Guard
def _evaluate(options)
def _evaluate(options) evaluator = Guardfile::Evaluator.new(options) evaluator.evaluate UI.reset_and_clear msg = "No plugins found in Guardfile, please add at least one." UI.error msg if _pluginless_guardfile? if evaluator.inline? UI.info("Using inline Guardfile.") elsif evaluator.custom? UI.info("Using Guardfile at #{ evaluator.path }.") end rescue Guardfile::Evaluator::NoPluginsError => e UI.error(e.message) end
def _guardfile_deprecated_check(modified)
TODO: remove at some point
def _guardfile_deprecated_check(modified) modified.map!(&:to_s) regexp = %r{^(?:.+/)?Guardfile$} guardfiles = modified.select { |path| regexp.match(path) } return if guardfiles.empty? guardfile = Pathname("Guardfile").realpath real_guardfiles = guardfiles.detect do |path| /^Guardfile$/.match(path) || Pathname(path).expand_path == guardfile end return unless real_guardfiles UI.warning "Guardfile changed -- _guard-core will exit.\n" exit 2 # nonzero to break any while loop end
def _listener_callback
def _listener_callback lambda do |modified, added, removed| relative_paths = { modified: _relative_pathnames(modified), added: _relative_pathnames(added), removed: _relative_pathnames(removed) } _guardfile_deprecated_check(relative_paths[:modified]) async_queue_add(relative_paths) if _relevant_changes?(relative_paths) end end
def _pluginless_guardfile?
def _pluginless_guardfile? state.session.plugins.all.empty? end
def _relative_pathnames(paths)
def _relative_pathnames(paths) paths.map { |path| _relative_pathname(path) } end
def _relevant_changes?(changes)
Check if any of the changes are actually watched for
def _relevant_changes?(changes) # TODO: no coverage! files = changes.values.flatten(1) scope = Guard.state.scope watchers = scope.grouped_plugins.map do |_group, plugins| plugins.map(&:watchers).flatten end.flatten watchers.any? { |watcher| files.any? { |file| watcher.match(file) } } end
def async_queue_add(changes)
- Example: New style signals with args: -
Example: Old style hash: -
def async_queue_add(changes) @queue << changes # Putting interactor in background puts guard into foreground # so it can handle change notifications Thread.new { interactor.background } end
def init(cmdline_options)
def init(cmdline_options) @state = Internals::State.new(cmdline_options) end
def setup(cmdline_options = {})
-
(Guard)
- the Guard singleton
Options Hash:
(**options)
-
guardfile
(String
) -- the path to the Guardfile -
watchdir
(Array
) -- the directories to watch -
group
(Array
) -- the list of groups to start -
debug
(Boolean
) -- if debug output should be shown -
notify
(Boolean
) -- if system notifications should be shown -
clear
(Boolean
) -- if auto clear the UI should be done
def setup(cmdline_options = {}) init(cmdline_options) @queue = Internals::Queue.new(Guard) _evaluate(state.session.evaluator_options) # NOTE: this should be *after* evaluate so :directories can work # TODO: move listener setup to session? @listener = Listen.send(*state.session.listener_args, &_listener_callback) ignores = state.session.guardfile_ignore @listener.ignore(ignores) unless ignores.empty? ignores = state.session.guardfile_ignore_bang @listener.ignore!(ignores) unless ignores.empty? Notifier.connect(state.session.notify_options) traps = Internals::Traps traps.handle("USR1") { async_queue_add([:guard_pause, :paused]) } traps.handle("USR2") { async_queue_add([:guard_pause, :unpaused]) } @interactor = Interactor.new(state.session.interactor_name == :sleep) traps.handle("INT") { @interactor.handle_interrupt } self end