guard 1.4.0 → 2.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +1 -677
- data/LICENSE +4 -2
- data/README.md +91 -753
- data/bin/_guard-core +11 -0
- data/bin/guard +108 -3
- data/lib/guard/aruba_adapter.rb +59 -0
- data/lib/guard/cli/environments/bundler.rb +22 -0
- data/lib/guard/cli/environments/evaluate_only.rb +35 -0
- data/lib/guard/cli/environments/valid.rb +69 -0
- data/lib/guard/cli.rb +129 -128
- data/lib/guard/commander.rb +104 -0
- data/lib/guard/commands/all.rb +37 -0
- data/lib/guard/commands/change.rb +31 -0
- data/lib/guard/commands/notification.rb +26 -0
- data/lib/guard/commands/pause.rb +29 -0
- data/lib/guard/commands/reload.rb +36 -0
- data/lib/guard/commands/scope.rb +38 -0
- data/lib/guard/commands/show.rb +24 -0
- data/lib/guard/config.rb +18 -0
- data/lib/guard/deprecated/dsl.rb +45 -0
- data/lib/guard/deprecated/evaluator.rb +39 -0
- data/lib/guard/deprecated/guard.rb +328 -0
- data/lib/guard/deprecated/guardfile.rb +84 -0
- data/lib/guard/deprecated/watcher.rb +27 -0
- data/lib/guard/dsl.rb +332 -363
- data/lib/guard/dsl_describer.rb +132 -122
- data/lib/guard/dsl_reader.rb +51 -0
- data/lib/guard/group.rb +34 -14
- data/lib/guard/guardfile/evaluator.rb +232 -0
- data/lib/guard/guardfile/generator.rb +128 -0
- data/lib/guard/guardfile.rb +24 -60
- data/lib/guard/interactor.rb +31 -255
- data/lib/guard/internals/debugging.rb +68 -0
- data/lib/guard/internals/groups.rb +40 -0
- data/lib/guard/internals/helpers.rb +13 -0
- data/lib/guard/internals/plugins.rb +53 -0
- data/lib/guard/internals/queue.rb +51 -0
- data/lib/guard/internals/scope.rb +121 -0
- data/lib/guard/internals/session.rb +180 -0
- data/lib/guard/internals/state.rb +25 -0
- data/lib/guard/internals/tracing.rb +33 -0
- data/lib/guard/internals/traps.rb +10 -0
- data/lib/guard/jobs/base.rb +21 -0
- data/lib/guard/jobs/pry_wrapper.rb +336 -0
- data/lib/guard/jobs/sleep.rb +26 -0
- data/lib/guard/notifier.rb +46 -212
- data/lib/guard/options.rb +22 -0
- data/lib/guard/plugin.rb +303 -0
- data/lib/guard/plugin_util.rb +191 -0
- data/lib/guard/rake_task.rb +42 -0
- data/lib/guard/runner.rb +80 -140
- data/lib/guard/templates/Guardfile +14 -0
- data/lib/guard/terminal.rb +13 -0
- data/lib/guard/ui/colors.rb +56 -0
- data/lib/guard/ui/config.rb +70 -0
- data/lib/guard/ui/logger.rb +30 -0
- data/lib/guard/ui.rb +163 -128
- data/lib/guard/version.rb +1 -2
- data/lib/guard/watcher/pattern/deprecated_regexp.rb +45 -0
- data/lib/guard/watcher/pattern/match_result.rb +18 -0
- data/lib/guard/watcher/pattern/matcher.rb +33 -0
- data/lib/guard/watcher/pattern/pathname_path.rb +15 -0
- data/lib/guard/watcher/pattern/simple_path.rb +23 -0
- data/lib/guard/watcher/pattern.rb +24 -0
- data/lib/guard/watcher.rb +52 -95
- data/lib/guard.rb +108 -376
- data/lib/tasks/releaser.rb +116 -0
- data/man/guard.1 +12 -9
- data/man/guard.1.html +18 -12
- metadata +148 -77
- data/images/guard.png +0 -0
- data/lib/guard/guard.rb +0 -156
- data/lib/guard/hook.rb +0 -120
- data/lib/guard/interactors/coolline.rb +0 -64
- data/lib/guard/interactors/helpers/completion.rb +0 -32
- data/lib/guard/interactors/helpers/terminal.rb +0 -46
- data/lib/guard/interactors/readline.rb +0 -94
- data/lib/guard/interactors/simple.rb +0 -19
- data/lib/guard/notifiers/emacs.rb +0 -69
- data/lib/guard/notifiers/gntp.rb +0 -118
- data/lib/guard/notifiers/growl.rb +0 -99
- data/lib/guard/notifiers/growl_notify.rb +0 -92
- data/lib/guard/notifiers/libnotify.rb +0 -96
- data/lib/guard/notifiers/notifysend.rb +0 -84
- data/lib/guard/notifiers/rb_notifu.rb +0 -102
- data/lib/guard/notifiers/terminal_notifier.rb +0 -66
- data/lib/guard/notifiers/tmux.rb +0 -69
- data/lib/guard/version.rbc +0 -130
@@ -0,0 +1,128 @@
|
|
1
|
+
require "guard/ui"
|
2
|
+
require "guard/plugin_util"
|
3
|
+
|
4
|
+
# Add Pathname#binwrite to 1.9.3
|
5
|
+
unless Pathname.instance_methods.include?(:binwrite)
|
6
|
+
class Pathname
|
7
|
+
def binwrite(*args)
|
8
|
+
IO.binwrite(to_s, *args)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module Guard
|
14
|
+
module Guardfile
|
15
|
+
# This class is responsible for generating the Guardfile and adding Guard'
|
16
|
+
# plugins' templates into it.
|
17
|
+
#
|
18
|
+
# @see Guard::CLI
|
19
|
+
#
|
20
|
+
class Generator
|
21
|
+
require "guard"
|
22
|
+
require "guard/ui"
|
23
|
+
|
24
|
+
INFO_TEMPLATE_ADDED =
|
25
|
+
"%s template added to Guardfile, feel free to edit it"
|
26
|
+
|
27
|
+
# The Guardfile template for `guard init`
|
28
|
+
GUARDFILE_TEMPLATE = File.expand_path(
|
29
|
+
"../../../guard/templates/Guardfile",
|
30
|
+
__FILE__
|
31
|
+
)
|
32
|
+
|
33
|
+
# The location of user defined templates
|
34
|
+
begin
|
35
|
+
HOME_TEMPLATES = Pathname.new("~/.guard/templates").expand_path
|
36
|
+
rescue ArgumentError
|
37
|
+
# home isn't defined. Set to the root of the drive. Trust that there
|
38
|
+
# won't be user defined templates there
|
39
|
+
HOME_TEMPLATES = Pathname.new("/").expand_path
|
40
|
+
end
|
41
|
+
|
42
|
+
class Error < RuntimeError
|
43
|
+
end
|
44
|
+
|
45
|
+
class NoSuchPlugin < Error
|
46
|
+
attr_reader :plugin_name, :class_name
|
47
|
+
|
48
|
+
def initialize(plugin_name)
|
49
|
+
@plugin_name = plugin_name
|
50
|
+
@class_name = plugin_name.delete("-").capitalize
|
51
|
+
end
|
52
|
+
|
53
|
+
def message
|
54
|
+
"Could not load 'guard/#{plugin_name}'"\
|
55
|
+
" or '~/.guard/templates/#{plugin_name}'"\
|
56
|
+
" or find class Guard::#{class_name}\n"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Creates the initial Guardfile template when it does not
|
61
|
+
# already exist.
|
62
|
+
#
|
63
|
+
# @see Guard::CLI#init
|
64
|
+
#
|
65
|
+
def create_guardfile
|
66
|
+
path = Pathname.new("Guardfile").expand_path
|
67
|
+
if path.exist?
|
68
|
+
_ui(:error, "Guardfile already exists at #{path}")
|
69
|
+
abort
|
70
|
+
end
|
71
|
+
|
72
|
+
_ui(:info, "Writing new Guardfile to #{path}")
|
73
|
+
FileUtils.cp(GUARDFILE_TEMPLATE, path.to_s)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Adds the Guardfile template of a Guard plugin to an existing Guardfile.
|
77
|
+
#
|
78
|
+
# @see Guard::CLI#init
|
79
|
+
#
|
80
|
+
# @param [String] plugin_name the name of the Guard plugin or template to
|
81
|
+
# initialize
|
82
|
+
#
|
83
|
+
def initialize_template(plugin_name)
|
84
|
+
guardfile = Pathname.new("Guardfile")
|
85
|
+
|
86
|
+
plugin_util = PluginUtil.new(plugin_name)
|
87
|
+
# TODO: change to "valid?" method
|
88
|
+
plugin_class = plugin_util.plugin_class(fail_gracefully: true)
|
89
|
+
if plugin_class
|
90
|
+
begin
|
91
|
+
plugin_util.add_to_guardfile
|
92
|
+
rescue Errno::ENOENT => error
|
93
|
+
# TODO: refactor
|
94
|
+
template = plugin_class.template(plugin_util.plugin_location)
|
95
|
+
_ui(:error, "Found class #{plugin_class} but loading it's template"\
|
96
|
+
"failed: '#{template}'")
|
97
|
+
_ui(:error, "Error is: #{error}")
|
98
|
+
return
|
99
|
+
end
|
100
|
+
return
|
101
|
+
end
|
102
|
+
|
103
|
+
template_code = (HOME_TEMPLATES + plugin_name).read
|
104
|
+
guardfile.binwrite(format("\n%s\n", template_code), open_args: ["a"])
|
105
|
+
|
106
|
+
_ui(:info, format(INFO_TEMPLATE_ADDED, plugin_name))
|
107
|
+
|
108
|
+
rescue Errno::ENOENT
|
109
|
+
fail NoSuchPlugin, plugin_name.downcase
|
110
|
+
end
|
111
|
+
|
112
|
+
# Adds the templates of all installed Guard implementations to an
|
113
|
+
# existing Guardfile.
|
114
|
+
#
|
115
|
+
# @see Guard::CLI#init
|
116
|
+
#
|
117
|
+
def initialize_all_templates
|
118
|
+
PluginUtil.plugin_names.each { |g| initialize_template(g) }
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def _ui(*args)
|
124
|
+
UI.send(*args)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/lib/guard/guardfile.rb
CHANGED
@@ -1,73 +1,37 @@
|
|
1
|
-
|
1
|
+
require "guard/config"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
#
|
8
|
-
class Guardfile
|
3
|
+
if Guard::Config.new.strict?
|
4
|
+
abort "Error: Deprecated file #{__FILE__} is being used"
|
5
|
+
else
|
6
|
+
require "guard/deprecated/guardfile"
|
9
7
|
|
10
|
-
|
11
|
-
require 'guard/ui'
|
8
|
+
# TODO: remove this file in next major version
|
12
9
|
|
13
|
-
|
10
|
+
module Guard
|
11
|
+
unless Guard::Config.new.silence_deprecations?
|
12
|
+
UPGRADE_WIKI_URL =
|
13
|
+
"https://github.com/guard/guard/wiki/Upgrading-to-Guard-2.0"
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
#
|
18
|
-
# @see Guard::CLI.init
|
19
|
-
#
|
20
|
-
# @param [Hash] options The options for creating a Guardfile
|
21
|
-
# @option options [Boolean] :abort_on_existence Whether to abort or not when a Guardfile already exists
|
22
|
-
#
|
23
|
-
def create_guardfile(options = {})
|
24
|
-
if !File.exist?('Guardfile')
|
25
|
-
::Guard::UI.info "Writing new Guardfile to #{ Dir.pwd }/Guardfile"
|
26
|
-
FileUtils.cp(GUARDFILE_TEMPLATE, 'Guardfile')
|
27
|
-
elsif options[:abort_on_existence]
|
28
|
-
::Guard::UI.error "Guardfile already exists at #{ Dir.pwd }/Guardfile"
|
29
|
-
abort
|
30
|
-
end
|
31
|
-
end
|
15
|
+
STDERR.puts <<-EOS
|
16
|
+
(guard/guardfile.rb message)
|
32
17
|
|
33
|
-
|
34
|
-
|
35
|
-
#
|
36
|
-
# @see Guard::CLI.init
|
37
|
-
#
|
38
|
-
# @param [String] guard_name the name of the Guard or template to initialize
|
39
|
-
#
|
40
|
-
def initialize_template(guard_name)
|
41
|
-
guard_class = ::Guard.get_guard_class(guard_name, true)
|
18
|
+
You are including "guard/guardfile.rb", which has been deprecated
|
19
|
+
since 2013 ... and will be removed.
|
42
20
|
|
43
|
-
|
44
|
-
guard_class.init(guard_name)
|
45
|
-
elsif File.exist?(File.join(HOME_TEMPLATES, guard_name))
|
46
|
-
content = File.read('Guardfile')
|
47
|
-
template = File.read(File.join(HOME_TEMPLATES, guard_name))
|
21
|
+
Migration is easy, see: #{UPGRADE_WIKI_URL}
|
48
22
|
|
49
|
-
|
50
|
-
|
51
|
-
f.puts('')
|
52
|
-
f.puts(template)
|
53
|
-
end
|
23
|
+
This file was included from:
|
24
|
+
#{caller[0..10] * "\n >"}
|
54
25
|
|
55
|
-
|
56
|
-
else
|
57
|
-
const_name = guard_name.downcase.gsub('-', '')
|
58
|
-
UI.error "Could not load 'guard/#{ guard_name.downcase }' or '~/.guard/templates/#{ guard_name.downcase }' or find class Guard::#{ const_name.capitalize }"
|
59
|
-
end
|
60
|
-
end
|
26
|
+
Sorry for the inconvenience and have a nice day!
|
61
27
|
|
62
|
-
|
63
|
-
# to an existing Guardfile.
|
64
|
-
#
|
65
|
-
# @see Guard::CLI.init
|
66
|
-
#
|
67
|
-
def initialize_all_templates
|
68
|
-
::Guard.guard_gem_names.each { |g| initialize_template(g) }
|
69
|
-
end
|
28
|
+
(end of guard/guardfile.rb message)
|
70
29
|
|
30
|
+
|
31
|
+
EOS
|
32
|
+
end
|
33
|
+
module Guardfile
|
34
|
+
extend Deprecated::Guardfile::ClassMethods
|
71
35
|
end
|
72
36
|
end
|
73
37
|
end
|
data/lib/guard/interactor.rb
CHANGED
@@ -1,277 +1,53 @@
|
|
1
|
-
|
1
|
+
require "forwardable"
|
2
2
|
|
3
|
-
|
4
|
-
# read by a interactor implementation.
|
5
|
-
#
|
6
|
-
# Currently the following actions are implemented:
|
7
|
-
#
|
8
|
-
# - h, help => Show help
|
9
|
-
# - e, exit,
|
10
|
-
# q. quit => Exit Guard
|
11
|
-
# - r, reload => Reload Guard
|
12
|
-
# - p, pause => Toggle file modification listener
|
13
|
-
# - n, notification => Toggle notifications
|
14
|
-
# - s, show => Show Guard plugin configuration
|
15
|
-
# - c, change => Trigger a file change
|
16
|
-
# - <enter> => Run all
|
17
|
-
#
|
18
|
-
# It's also possible to scope `reload` and `run all` actions to only a specified group or a guard.
|
19
|
-
#
|
20
|
-
# @example Reload backend group
|
21
|
-
# backend reload
|
22
|
-
# reload backend
|
23
|
-
#
|
24
|
-
# @example Reload rspec guard
|
25
|
-
# spork reload
|
26
|
-
# reload spork
|
27
|
-
#
|
28
|
-
# @example Run all jasmine specs
|
29
|
-
# jasmine
|
30
|
-
#
|
31
|
-
# @abstract
|
32
|
-
#
|
3
|
+
module Guard
|
33
4
|
class Interactor
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
require 'guard/dsl_describer'
|
38
|
-
require 'guard/notifier'
|
39
|
-
require 'guard/interactors/readline'
|
40
|
-
require 'guard/interactors/coolline'
|
41
|
-
require 'guard/interactors/simple'
|
42
|
-
|
43
|
-
ACTIONS = {
|
44
|
-
:help => %w[help h],
|
45
|
-
:reload => %w[reload r],
|
46
|
-
:stop => %w[exit e quit q],
|
47
|
-
:pause => %w[pause p],
|
48
|
-
:notification => %w[notification n],
|
49
|
-
:show => %w[show s],
|
50
|
-
:change => %w[change c]
|
51
|
-
}
|
52
|
-
|
53
|
-
# Set the interactor implementation
|
54
|
-
#
|
55
|
-
# @param [Symbol] interactor the name of the interactor
|
5
|
+
# Initializes the interactor. This configures
|
6
|
+
# Pry and creates some custom commands and aliases
|
7
|
+
# for Guard.
|
56
8
|
#
|
57
|
-
def
|
58
|
-
@
|
59
|
-
end
|
9
|
+
def initialize(no_interaction = false)
|
10
|
+
@interactive = !no_interaction && self.class.enabled?
|
60
11
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
# @return [Interactor] an interactor implementation
|
65
|
-
#
|
66
|
-
def self.fabricate
|
67
|
-
case @interactor
|
68
|
-
when :coolline
|
69
|
-
::Guard::CoollineInteractor.new if ::Guard::CoollineInteractor.available?
|
70
|
-
when :readline
|
71
|
-
::Guard::ReadlineInteractor.new if ::Guard::ReadlineInteractor.available?
|
72
|
-
when :simple
|
73
|
-
::Guard::SimpleInteractor.new
|
74
|
-
when :off
|
75
|
-
nil
|
76
|
-
else
|
77
|
-
auto_detect
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# Tries to detect an optimal interactor for the
|
82
|
-
# current environment.
|
83
|
-
#
|
84
|
-
# It returns the Readline implementation when:
|
85
|
-
#
|
86
|
-
# * rb-readline is installed
|
87
|
-
# * The Ruby implementation is JRuby
|
88
|
-
# * The current OS is not Mac OS X
|
89
|
-
#
|
90
|
-
# Otherwise the plain gets interactor is returned.
|
91
|
-
#
|
92
|
-
# @return [Interactor] an interactor implementation
|
93
|
-
#
|
94
|
-
def self.auto_detect
|
95
|
-
[::Guard::CoollineInteractor, ::Guard::ReadlineInteractor, ::Guard::SimpleInteractor].detect do |interactor|
|
96
|
-
interactor.available?(true)
|
97
|
-
end.new
|
98
|
-
end
|
12
|
+
# TODO: only require the one used
|
13
|
+
require "guard/jobs/sleep"
|
14
|
+
require "guard/jobs/pry_wrapper"
|
99
15
|
|
100
|
-
|
101
|
-
|
102
|
-
#
|
103
|
-
# @param [Boolean] silent true if no error messages should be shown
|
104
|
-
# @return [Boolean] the availability status
|
105
|
-
#
|
106
|
-
def self.available?(silent = false)
|
107
|
-
true
|
16
|
+
job_klass = interactive? ? Jobs::PryWrapper : Jobs::Sleep
|
17
|
+
@idle_job = job_klass.new(self.class.options)
|
108
18
|
end
|
109
19
|
|
110
|
-
|
111
|
-
|
112
|
-
def start
|
113
|
-
return if ENV['GUARD_ENV'] == 'test'
|
114
|
-
|
115
|
-
::Guard::UI.debug 'Start interactor'
|
116
|
-
@thread = Thread.new { read_line } if !@thread || !@thread.alive?
|
20
|
+
def interactive?
|
21
|
+
@interactive
|
117
22
|
end
|
118
23
|
|
119
|
-
|
120
|
-
|
121
|
-
def stop
|
122
|
-
return if !@thread || ENV['GUARD_ENV'] == 'test'
|
24
|
+
extend Forwardable
|
25
|
+
delegate [:foreground, :background, :handle_interrupt] => :idle_job
|
123
26
|
|
124
|
-
|
125
|
-
|
126
|
-
|
27
|
+
# TODO: everything below is just so the DSL can set options
|
28
|
+
# before setup() is called, which makes it useless for when
|
29
|
+
# Guardfile is reevaluated
|
30
|
+
class << self
|
31
|
+
def options
|
32
|
+
@options ||= {}
|
127
33
|
end
|
128
|
-
end
|
129
34
|
|
130
|
-
|
131
|
-
|
132
|
-
#
|
133
|
-
# @abstract
|
134
|
-
#
|
135
|
-
def read_line
|
136
|
-
raise NotImplementedError
|
137
|
-
end
|
138
|
-
|
139
|
-
# Process the input from readline.
|
140
|
-
#
|
141
|
-
# @param [String] line the input line
|
142
|
-
#
|
143
|
-
def process_input(line)
|
144
|
-
scopes, action, rest = extract_scopes_and_action(line)
|
35
|
+
# Pass options to interactor's job when it's created
|
36
|
+
attr_writer :options
|
145
37
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
when :show
|
150
|
-
::Guard::DslDescriber.show(::Guard.options)
|
151
|
-
when :stop
|
152
|
-
::Guard.stop
|
153
|
-
exit
|
154
|
-
when :pause
|
155
|
-
::Guard.pause
|
156
|
-
when :reload
|
157
|
-
::Guard.reload(scopes)
|
158
|
-
when :change
|
159
|
-
::Guard.within_preserved_state do
|
160
|
-
::Guard.runner.run_on_changes(rest, [], [])
|
161
|
-
end
|
162
|
-
when :run_all
|
163
|
-
::Guard.run_all(scopes)
|
164
|
-
when :notification
|
165
|
-
toggle_notification
|
166
|
-
else
|
167
|
-
::Guard::UI.error "Unknown command #{ line }"
|
38
|
+
# TODO: allow custom user idle jobs, e.g. [:pry, :sleep, :exit, ...]
|
39
|
+
def enabled?
|
40
|
+
@enabled || @enabled.nil?
|
168
41
|
end
|
169
|
-
end
|
170
42
|
|
171
|
-
|
172
|
-
#
|
173
|
-
def toggle_notification
|
174
|
-
if ENV['GUARD_NOTIFY'] == 'true'
|
175
|
-
::Guard::UI.info 'Turn off notifications'
|
176
|
-
::Guard::Notifier.turn_off
|
177
|
-
else
|
178
|
-
::Guard::Notifier.turn_on
|
179
|
-
end
|
180
|
-
end
|
43
|
+
alias_method :enabled, :enabled?
|
181
44
|
|
182
|
-
|
183
|
-
|
184
|
-
def help
|
185
|
-
puts ''
|
186
|
-
puts '[e]xit, [q]uit Exit Guard'
|
187
|
-
puts '[p]ause Toggle file modification listener'
|
188
|
-
puts '[r]eload Reload Guard'
|
189
|
-
puts '[n]otification Toggle notifications'
|
190
|
-
puts '[s]how Show available Guard plugins'
|
191
|
-
puts '[c]hange <file> Trigger a file change'
|
192
|
-
puts '<enter> Run all Guard plugins'
|
193
|
-
puts ''
|
194
|
-
puts 'You can scope the reload action to a specific guard or group:'
|
195
|
-
puts ''
|
196
|
-
puts 'rspec reload Reload the RSpec Guard'
|
197
|
-
puts 'backend reload Reload the backend group'
|
198
|
-
puts ''
|
199
|
-
puts 'You can also run only a specific Guard or all Guard plugins in a specific group:'
|
200
|
-
puts ''
|
201
|
-
puts 'jasmine Run the jasmine Guard'
|
202
|
-
puts 'frontend Run all Guard plugins in the frontend group'
|
203
|
-
puts ''
|
204
|
-
end
|
205
|
-
|
206
|
-
# Extract the Guard or group scope and action from the
|
207
|
-
# input line. There's no strict order for scopes and
|
208
|
-
# actions.
|
209
|
-
#
|
210
|
-
# @example `spork reload` will only reload rspec
|
211
|
-
# @example `jasmine` will only run all jasmine specs
|
212
|
-
#
|
213
|
-
# @param [String] line the readline input
|
214
|
-
# @return [Array] the group or guard scope, the action and the rest
|
215
|
-
#
|
216
|
-
def extract_scopes_and_action(line)
|
217
|
-
entries = line.split(' ')
|
218
|
-
|
219
|
-
scopes = extract_scopes(entries)
|
220
|
-
action = extract_action(entries)
|
221
|
-
|
222
|
-
action = :run_all if !action && (!scopes.empty? || entries.empty?)
|
223
|
-
|
224
|
-
[scopes, action, entries]
|
45
|
+
# TODO: handle switching interactors during runtime?
|
46
|
+
attr_writer :enabled
|
225
47
|
end
|
226
48
|
|
227
49
|
private
|
228
50
|
|
229
|
-
|
230
|
-
# Any entry found will be removed from the entries.
|
231
|
-
#
|
232
|
-
# @param [Array<String>] entries the user entries
|
233
|
-
# @return [Hash] a hash with a Guard or a group scope
|
234
|
-
#
|
235
|
-
def extract_scopes(entries)
|
236
|
-
scopes = { }
|
237
|
-
|
238
|
-
entries.delete_if do |entry|
|
239
|
-
if guard = ::Guard.guards(entry)
|
240
|
-
scopes[:guard] ||= guard
|
241
|
-
true
|
242
|
-
|
243
|
-
elsif group = ::Guard.groups(entry)
|
244
|
-
scopes[:group] ||= group
|
245
|
-
true
|
246
|
-
|
247
|
-
else
|
248
|
-
false
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
scopes
|
253
|
-
end
|
254
|
-
|
255
|
-
# Find the action for the given input entry.
|
256
|
-
# Any action found will be removed from the entries.
|
257
|
-
#
|
258
|
-
# @param [Array<String>] entries the user entries
|
259
|
-
# @return [Symbol] a Guard action
|
260
|
-
#
|
261
|
-
def extract_action(entries)
|
262
|
-
action = nil
|
263
|
-
|
264
|
-
entries.delete_if do |entry|
|
265
|
-
if command = ACTIONS.detect { |k, list| list.include?(entry) }
|
266
|
-
action ||= command.first
|
267
|
-
true
|
268
|
-
else
|
269
|
-
false
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
action
|
274
|
-
end
|
275
|
-
|
51
|
+
attr_reader :idle_job
|
276
52
|
end
|
277
53
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Because it's used by Sheller
|
2
|
+
require "open3"
|
3
|
+
require "logger"
|
4
|
+
|
5
|
+
require "guard/ui"
|
6
|
+
|
7
|
+
require "guard/internals/tracing"
|
8
|
+
|
9
|
+
module Guard
|
10
|
+
# @private api
|
11
|
+
module Internals
|
12
|
+
class Debugging
|
13
|
+
class << self
|
14
|
+
TRACES = [
|
15
|
+
[Kernel, :system],
|
16
|
+
[Kernel, :spawn],
|
17
|
+
[Kernel, :`],
|
18
|
+
[Open3, :popen3]
|
19
|
+
]
|
20
|
+
|
21
|
+
# Sets up debugging:
|
22
|
+
#
|
23
|
+
# * aborts on thread exceptions
|
24
|
+
# * Set the logging level to `:debug`
|
25
|
+
# * traces execution of Kernel.system and backtick calls
|
26
|
+
def start
|
27
|
+
return if @started ||= false
|
28
|
+
@started = true
|
29
|
+
|
30
|
+
Thread.abort_on_exception = true
|
31
|
+
|
32
|
+
UI.level = Logger::DEBUG
|
33
|
+
|
34
|
+
TRACES.each { |mod, meth| _trace(mod, meth, &method(:_notify)) }
|
35
|
+
@traced = true
|
36
|
+
end
|
37
|
+
|
38
|
+
def stop
|
39
|
+
return unless @started ||= false
|
40
|
+
UI.level = Logger::INFO
|
41
|
+
_reset
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def _notify(*args)
|
47
|
+
UI.debug "Command execution: #{args.join(' ')}"
|
48
|
+
end
|
49
|
+
|
50
|
+
# reset singleton - called by tests
|
51
|
+
def _reset
|
52
|
+
@started = false
|
53
|
+
return unless @traced
|
54
|
+
TRACES.each { |mod, meth| _untrace(mod, meth) }
|
55
|
+
@traced = false
|
56
|
+
end
|
57
|
+
|
58
|
+
def _trace(mod, meth, &block)
|
59
|
+
Tracing.trace(mod, meth, &block)
|
60
|
+
end
|
61
|
+
|
62
|
+
def _untrace(mod, meth)
|
63
|
+
Tracing.untrace(mod, meth)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "guard/group"
|
2
|
+
|
3
|
+
module Guard
|
4
|
+
# @private api
|
5
|
+
module Internals
|
6
|
+
class Groups
|
7
|
+
DEFAULT_GROUPS = [:common, :default]
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@groups = DEFAULT_GROUPS.map { |name| Group.new(name) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def all(filter = nil)
|
14
|
+
return @groups if filter.nil?
|
15
|
+
matcher = matcher_for(filter)
|
16
|
+
@groups.select { |group| matcher.call(group) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def add(name, options = {})
|
20
|
+
all(name).first || Group.new(name, options).tap do |group|
|
21
|
+
fail if name == :specs && options.empty?
|
22
|
+
@groups << group
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def matcher_for(filter)
|
29
|
+
case filter
|
30
|
+
when String, Symbol
|
31
|
+
->(group) { group.name == filter.to_sym }
|
32
|
+
when Regexp
|
33
|
+
->(group) { group.name.to_s =~ filter }
|
34
|
+
else
|
35
|
+
fail "Invalid filter: #{filter.inspect}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|