Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Add a Guard::API module that Guard plugins should include #873

Open
wants to merge 66 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
add7310
Add a Guard::API module that Guard plugins should include
rymai Jun 17, 2017
672ed89
Continue the work on the new Guard::API
rymai Mar 3, 2018
1814234
Continue work on using Guard::API
rymai Oct 9, 2017
cef6aa5
Fix more specs
rymai Mar 4, 2018
52c64a5
Settings: Update rubocop and settings
edthamm Aug 17, 2018
e0eefa7
Auto correct: Style/StringLiterals in spec
edthamm Aug 17, 2018
b680c6c
Auto correct: Style/FrozenStringLiteralComment
edthamm Aug 17, 2018
87a677a
Correct: Violations in gemfile
edthamm Aug 17, 2018
cf64428
Fix: Unfreeze string literal in failing test
edthamm Aug 17, 2018
6f3ef4b
Auto correct: Layout/DotPosition
edthamm Aug 17, 2018
e417c40
Auto correct: Style/PercentLiteralDelimiters in spec
edthamm Aug 17, 2018
fe4e7aa
Auto correct: Layout/EmptyLineAfterMagicComment in spec
edthamm Aug 17, 2018
b80411a
Auto correct: Style/SymbolArray in spec
edthamm Aug 17, 2018
fb32fe9
Auto correct: Layout/MultilineMethodCallIndentation in spec
edthamm Aug 17, 2018
4942fc1
Settings: Set Metrics/LineLength:Max to 125
edthamm Aug 17, 2018
8358c62
Auto correct: Style/TrailingCommaIn.*Literal in spec
edthamm Aug 17, 2018
f33d6c4
Settings: Adapt quote and dot settings
edthamm Aug 17, 2018
98933f8
Auto correct: Style/ExpandPathArguments in spec
edthamm Aug 17, 2018
3d8571a
Auto correct: Layout/AlignArray in spec
edthamm Aug 17, 2018
c7b3fd3
Auto correct: Style/Encoding in spec
edthamm Aug 17, 2018
3a98cc0
Correct: Forgotten double-quotes in Gemfile
edthamm Aug 17, 2018
6b466f6
Auto correct: Lint/UnneededSplatExpansion in spec
edthamm Aug 17, 2018
8c93ed9
Fix: Explicitly set rubocop configuration file
edthamm Aug 17, 2018
5069a11
Auto correct: Style/EmptyMethod in spec
edthamm Aug 17, 2018
b095597
Correct: the remaining 3 violations
edthamm Aug 17, 2018
5230884
Settings: Get rid of warnings.
edthamm Aug 17, 2018
49d6ffa
Fix: Resupport version 2.2.9
edthamm Aug 17, 2018
fed30f1
Fix: Increase aruba timeout for Jruby on CI
edthamm Aug 17, 2018
8c2ab9e
Settings: Enrich Metrics/LineLength config
edthamm Aug 19, 2018
8114666
Fix: Resupport 2.2.9 in rubocop
edthamm Aug 19, 2018
215f891
Settings: Set Style/StringLiterals to double_quotes
edthamm Aug 21, 2018
4a77fde
Auto correct: Style/StringLiterals
edthamm Aug 21, 2018
a804658
Trigger Hound
edthamm Sep 18, 2018
b972242
Auto correct: Style/StringLiterals in top level dir
edthamm Sep 18, 2018
e6aab49
Merge pull request #911 from edthamm/feat/styling-spec
rymai Sep 24, 2018
1e12d8d
add simplecov filter for a spec folder
Mifrill Oct 15, 2018
1baa713
Pry 0.12.0 Deprecation warnings
Nov 8, 2018
0ba79a6
Use Gem Version in comparison
rymai Nov 9, 2018
a47aed1
Merge pull request #916 from chadmetcalf/pry_deprecation
rymai Nov 9, 2018
68dc4bb
Bump to 2.15.0
rymai Nov 14, 2018
8df6a45
Merge pull request #918 from guard/bump-to-2.15.0
rymai Nov 14, 2018
929ffdf
Add a "Reviewed by Hound" badge
salbertson Nov 17, 2018
a3104cb
Merge pull request #919 from salbertson/patch-1
rymai Nov 19, 2018
7ed2884
Update Ruby versions tested in .travis.yml
rymai Feb 6, 2019
568e12a
Fix YARD annotation
olleolleolle Apr 1, 2019
8dc0c4f
Fix YARD annotation
olleolleolle Apr 1, 2019
ebe4b12
Merge pull request #925 from olleolleolle/patch-1
rymai Apr 4, 2019
ca71795
CI: Use 2.4.6, 2.5.5, 2.6.2...
olleolleolle Apr 4, 2019
586224d
Merge pull request #926 from olleolleolle/patch-1
rymai Apr 4, 2019
ba67757
README: Drop outdated badge for Gemnasium
olleolleolle Apr 4, 2019
fbae74a
Merge pull request #927 from olleolleolle/patch-1
rymai Apr 4, 2019
f469f51
Stub File.read instead of IO.read in spec.
jackorp Feb 4, 2019
0363572
Properly stub Pathname and their methods in specs
rymai Apr 4, 2019
435ffc3
Merge pull request #928 from guard/jackorp-fix-spec-helper
rymai Apr 4, 2019
98a4868
Cleanup guard process anytime
pocke Apr 5, 2019
f004880
Add spec for cleanup process
pocke Apr 13, 2019
c9888b4
Merge pull request #930 from pocke/cleanup-process
rymai Apr 17, 2019
ea80783
Update Ruby versions and fix a few small things in the README
rymai Apr 17, 2019
7bc081a
Merge pull request #914 from Mifrill/simplecov
rymai Apr 17, 2019
516b062
Add a Guard::API module that Guard plugins should include
rymai Jun 17, 2017
ec27de8
Continue the work on the new Guard::API
rymai Mar 3, 2018
486ef0d
Continue work on using Guard::API
rymai Oct 9, 2017
d6a4ec6
Fix more specs
rymai Mar 4, 2018
a033cb7
Not sure what I'm doing
rymai Nov 14, 2018
1d993a6
Fix some missed conflicts
rymai Apr 17, 2019
2866275
Merge branch 'guard-api' of github.com:guard/guard into guard-api
rymai Apr 17, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion .rspec
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
--fail-fast
--format documentation
--color
--require spec_helper
48 changes: 24 additions & 24 deletions config/Guardfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ scope(groups: %w(specs))

directories %w(spec lib config features man)

watch ("config/Guardfile") { UI.info "Exiting guard because config changed"; exit 0 }
# watch ("config/Guardfile") { UI.info "Exiting guard because config changed"; exit 0 }

group :specs, halt_on_fail: true do
guard :rspec, cmd: "bundle exec rspec", failed_mode: :keep do
Expand All @@ -25,27 +25,27 @@ group :specs, halt_on_fail: true do
# watch("lib/guard/interactor.rb") { "spec/guard/commands" }
# watch(%r{^lib/guard/(guard|plugin).rb$}) { "spec/guard/plugin" }
end

guard :rubocop, all_on_start: false, cli: "--rails" do
watch(%r{.+\.rb$}) { |m| m[0] }
watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
end

guard "cucumber", keep_failed: true, all_on_start: false, cmd_additional_args: '--profile guard' do
watch(%r{^features/.+\.feature$})
watch(%r{^features/support/.+$}) { "features" }
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) do |m|
Dir[File.join("**/#{m[1]}.feature")][0] || "features"
end
end
end

if !defined?(JRUBY_VERSION)
if ENV["CI"] != "true"
group :docs do
guard :ronn do
watch(%r{^man/.+\.ronn?$})
end
end
end
#
# guard :rubocop, all_on_start: false, cli: "--rails" do
# watch(%r{.+\.rb$}) { |m| m[0] }
# watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
# end
#
# guard "cucumber", keep_failed: true, all_on_start: false, cmd_additional_args: '--profile guard' do
# watch(%r{^features/.+\.feature$})
# watch(%r{^features/support/.+$}) { "features" }
# watch(%r{^features/step_definitions/(.+)_steps\.rb$}) do |m|
# Dir[File.join("**/#{m[1]}.feature")][0] || "features"
# end
# end
end
#
# if !defined?(JRUBY_VERSION)
# if ENV["CI"] != "true"
# group :docs do
# guard :ronn do
# watch(%r{^man/.+\.ronn?$})
# end
# end
# end
# end
153 changes: 22 additions & 131 deletions lib/guard.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
require "thread"
require "listen"
require "forwardable"

require "guard/config"
require "guard/engine"
require "guard/api"
require "guard/plugin"
require "guard/deprecated/guard" unless Guard::Config.new.strict?
require "guard/internals/helpers"

require "guard/internals/debugging"
require "guard/internals/traps"
Expand All @@ -18,152 +21,40 @@ module Guard
Deprecated::Guard.add_deprecated(self) unless Config.new.strict?

class << self
attr_reader :state
attr_reader :queue
attr_reader :listener
attr_reader :interactor

# @private api

include Internals::Helpers

# Initializes the Guard singleton:
#
# * Initialize the internal Guard state;
# * Create the interactor
# * Select and initialize the file change listener.
#
# @option options [Boolean] clear if auto clear the UI should be done
# @option options [Boolean] notify if system notifications should be shown
# @option options [Boolean] debug if debug output should be shown
# @option options [Array<String>] group the list of groups to start
# @option options [Array<String>] watchdir the directories to watch
# @option options [String] guardfile the path to the Guardfile
#
# @return [Guard] the Guard singleton
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
# Backward-compatibility with the Guard singleton approach
def state
return unless @engine

def init(cmdline_options)
@state = Internals::State.new(cmdline_options)
@engine.state
end

# Asynchronously trigger changes
#
# Currently supported args:
#
# @example Old style hash:
# async_queue_add(modified: ['foo'], added: ['bar'], removed: [])
#
# @example New style signals with args:
# async_queue_add([:guard_pause, :unpaused ])
#
def async_queue_add(changes)
@queue << changes
def queue
return unless @engine

# Putting interactor in background puts guard into foreground
# so it can handle change notifications
Thread.new { interactor.background }
@engine.queue
end

private
def listener
return unless @engine

# Check if any of the changes are actually watched for
# TODO: why iterate twice? reuse this info when running tasks
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) } }
@engine.listener
end

def _relative_pathnames(paths)
paths.map { |path| _relative_pathname(path) }
end

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])
def interactor
return unless @engine

async_queue_add(relative_paths) if _relevant_changes?(relative_paths)
end
@engine.interactor
end

# TODO: obsoleted? (move to Dsl?)
def _pluginless_guardfile?
state.session.plugins.all.empty?
def start(cmdline_opts = {})
@engine = init(cmdline_opts)
@engine.start
end

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

# TODO: remove at some point
# TODO: not tested because collides with ongoing refactoring
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
def init(cmdline_opts = {})
Engine.new(cmdline_opts: cmdline_opts)
end
end
end